2008-01-14 Sephane Delcroix <sdelcroix@novell.com>
[mono.git] / mcs / class / corlib / System / DateTimeOffset.cs
1 /*
2  * System.DateTimeOffset
3  *
4  * Author(s)
5  *      Stephane Delcroix <stephane@delcroix.org>
6  *      Marek Safar (marek.safar@gmail.com)
7  *
8  *  Copyright (C) 2007 Novell, Inc (http://www.novell.com) 
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining
11  * a copy of this software and associated documentation files (the
12  * "Software"), to deal in the Software without restriction, including
13  * without limitation the rights to use, copy, modify, merge, publish,
14  * distribute, sublicense, and/or sell copies of the Software, and to
15  * permit persons to whom the Software is furnished to do so, subject to
16  * the following conditions:
17  * 
18  * The above copyright notice and this permission notice shall be
19  * included in all copies or substantial portions of the Software.
20  * 
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28  */
29
30
31 #if NET_2_0 // Introduced by .NET 3.5 for 2.0 mscorlib
32
33 using System.Globalization;
34 using System.Runtime.InteropServices;
35 using System.Runtime.Serialization;
36 using System.Text;
37
38 namespace System
39 {
40         [Serializable]
41         [StructLayout (LayoutKind.Auto)]
42         public struct DateTimeOffset : IComparable, IFormattable, ISerializable, IDeserializationCallback, IComparable<DateTimeOffset>, IEquatable<DateTimeOffset>
43         {
44                 public static readonly DateTimeOffset MaxValue = new DateTimeOffset (DateTime.MaxValue, TimeSpan.Zero);
45                 public static readonly DateTimeOffset MinValue = new DateTimeOffset (DateTime.MinValue, TimeSpan.Zero);
46                 
47                 DateTime dt;
48                 TimeSpan utc_offset;
49         
50                 public DateTimeOffset (DateTime dateTime)
51                 {
52                         dt = dateTime;
53
54                         if (dateTime.Kind == DateTimeKind.Utc)
55                                 utc_offset = TimeSpan.Zero;
56                         else 
57                                 utc_offset = TimeZone.CurrentTimeZone.GetUtcOffset (dateTime);
58                                 
59                         if (UtcDateTime < DateTime.MinValue || UtcDateTime > DateTime.MaxValue)
60                                 throw new ArgumentOutOfRangeException ("The UTC date and time that results from applying the offset is earlier than MinValue or later than MaxValue.");
61
62                 }
63                 
64                 public DateTimeOffset (DateTime dateTime, TimeSpan offset)
65                 {
66                         if (dateTime.Kind == DateTimeKind.Utc && offset != TimeSpan.Zero)
67                                 throw new ArgumentException ("dateTime.Kind equals Utc and offset does not equal zero.");
68
69                         if (dateTime.Kind == DateTimeKind.Local && offset != TimeZone.CurrentTimeZone.GetUtcOffset (dateTime))
70                                 throw new ArgumentException ("dateTime.Kind equals Local and offset does not equal the offset of the system's local time zone.");
71
72                         if (offset.Ticks % TimeSpan.TicksPerMinute != 0)
73                                 throw new ArgumentException ("offset is not specified in whole minutes.");
74
75                         if (offset < new TimeSpan (-14, 0 ,0) || offset > new TimeSpan (14, 0, 0))
76                                 throw new ArgumentOutOfRangeException ("offset is less than -14 hours or greater than 14 hours.");
77
78                         dt = dateTime;
79                         utc_offset = offset;
80
81                         if (UtcDateTime < DateTime.MinValue || UtcDateTime > DateTime.MaxValue)
82                                 throw new ArgumentOutOfRangeException ("The UtcDateTime property is earlier than MinValue or later than MaxValue.");
83                 }
84
85                 public DateTimeOffset (long ticks, TimeSpan offset) : this (new DateTime (ticks), offset)
86                 {
87                 }
88
89                 public DateTimeOffset (int year, int month, int day, int hour, int minute, int second, TimeSpan offset) : 
90                         this (new DateTime (year, month, day, hour, minute, second), offset)
91                 {
92                 }
93
94                 public DateTimeOffset (int year, int month, int day, int hour, int minute, int second, int millisecond, TimeSpan offset) :
95                         this (new DateTime (year, month, day, hour, minute, second, millisecond), offset)
96                 {
97                 }
98
99                 public DateTimeOffset (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, TimeSpan offset) :
100                         this (new DateTime (year, month, day, hour, minute, second, millisecond, calendar), offset)
101                 {
102                 }
103
104                 public DateTimeOffset Add (TimeSpan timeSpan)
105                 {
106                         return new DateTimeOffset (dt.Add (timeSpan), utc_offset);
107                 }
108         
109                 public DateTimeOffset AddDays (double days)
110                 {
111                         return new DateTimeOffset (dt.AddDays (days), utc_offset);      
112                 }
113                 
114                 public DateTimeOffset AddHours (double hours)
115                 {
116                         return new DateTimeOffset (dt.AddHours (hours), utc_offset);
117                 }
118
119                 public static DateTimeOffset operator + (DateTimeOffset dateTimeTz, TimeSpan timeSpan)
120                 {
121                         return dateTimeTz.Add (timeSpan);
122                 }
123
124                 public DateTimeOffset AddMilliseconds (double milliseconds)
125                 {
126                         return new DateTimeOffset (dt.AddMilliseconds (milliseconds), utc_offset);
127                 }
128
129                 public DateTimeOffset AddMinutes (double minutes)
130                 {
131                         return new DateTimeOffset (dt.AddMinutes (minutes), utc_offset);        
132                 }
133
134                 public DateTimeOffset AddMonths (int months)
135                 {
136                         return new DateTimeOffset (dt.AddMonths (months), utc_offset);
137                 }
138
139                 public DateTimeOffset AddSeconds (double seconds)
140                 {
141                         return new DateTimeOffset (dt.AddSeconds (seconds), utc_offset);
142                 }
143
144                 public DateTimeOffset AddTicks (long ticks)
145                 {
146                         return new DateTimeOffset (dt.AddTicks (ticks), utc_offset);    
147                 }
148
149                 public DateTimeOffset AddYears (int years)
150                 {
151                         return new DateTimeOffset (dt.AddYears (years), utc_offset);
152                 }
153
154                 public static int Compare (DateTimeOffset first, DateTimeOffset second)
155                 {
156                         return first.CompareTo (second);        
157                 }
158
159                 public int CompareTo (DateTimeOffset other)
160                 {
161                         return UtcDateTime.CompareTo (other.UtcDateTime);
162                 }
163
164                 public int CompareTo (object other)
165                 {
166                         return CompareTo ((DateTimeOffset) other);
167                 }
168
169                 public static bool operator == (DateTimeOffset left, DateTimeOffset right)
170                 {
171                         return left.Equals (right);     
172                 }
173
174                 public bool Equals (DateTimeOffset other)
175                 {
176                         return UtcDateTime == other.UtcDateTime;
177                 }
178
179                 public override bool Equals (object other)
180                 {
181                         return UtcDateTime == ((DateTimeOffset) other).UtcDateTime;
182                 }
183
184                 public static bool Equals (DateTimeOffset first, DateTimeOffset second)
185                 {
186                         return first.Equals (second);   
187                 }
188
189                 public bool EqualsExact (DateTimeOffset other)
190                 {
191                         return dt == other.dt && utc_offset == other.utc_offset;        
192                 }
193
194                 public static DateTimeOffset FromFileTime (long fileTime)
195                 {
196                         if (fileTime < 0 || fileTime > MaxValue.Ticks)
197                                 throw new ArgumentOutOfRangeException ("fileTime is less than zero or greater than DateTimeOffset.MaxValue.Ticks.");
198                         
199                         return new DateTimeOffset (DateTime.FromFileTime (fileTime), TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.FromFileTime (fileTime)));
200
201                 }
202
203                 public override int GetHashCode ()
204                 {
205                         return dt.GetHashCode () ^ utc_offset.GetHashCode ();
206                 }
207
208                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
209                 {
210                         if (info == null)
211                                 throw new ArgumentNullException ("info");
212
213                         info.AddValue ("datetime", dt);
214                         info.AddValue ("offset", utc_offset);
215                 }
216
217                 public static bool operator > (DateTimeOffset left, DateTimeOffset right)
218                 {
219                         return left.UtcDateTime > right.UtcDateTime;
220                 }                       
221
222                 public static bool operator >= (DateTimeOffset left, DateTimeOffset right)
223                 {
224                         return left.UtcDateTime >= right.UtcDateTime;
225                 }                       
226
227                 public static implicit operator DateTimeOffset (DateTime dateTime)
228                 {
229                         return new DateTimeOffset (dateTime);
230                 }
231
232                 public static bool operator != (DateTimeOffset left, DateTimeOffset right)
233                 {
234                         return left.UtcDateTime != right.UtcDateTime;
235                 }
236
237                 public static bool operator < (DateTimeOffset left, DateTimeOffset right)
238                 {
239                         return left.UtcDateTime < right.UtcDateTime;
240                 }
241                 
242                 public static bool operator <= (DateTimeOffset left, DateTimeOffset right)
243                 {
244                         return left.UtcDateTime <= right.UtcDateTime;
245                 }
246         
247                 [MonoTODO]
248                 void IDeserializationCallback.OnDeserialization (object sender)
249                 {
250                 }
251
252                 public static DateTimeOffset Parse (string input)
253                 {
254                         return Parse (input, null);
255                 }
256
257                 public static DateTimeOffset Parse (string input, IFormatProvider formatProvider)
258                 {
259                         return Parse (input, formatProvider, DateTimeStyles.AllowWhiteSpaces);
260                 }
261
262                 [MonoTODO]
263                 public static DateTimeOffset Parse (string input, IFormatProvider formatProvider, DateTimeStyles styles)
264                 {
265                         if (input == null)
266                                 throw new ArgumentNullException ("input");
267
268                         throw new NotImplementedException ();
269                 }
270
271                 public static DateTimeOffset ParseExact (string input, string format, IFormatProvider formatProvider)
272                 {
273                         return ParseExact (input, format, formatProvider, DateTimeStyles.AssumeLocal);
274                 }
275
276                 public static DateTimeOffset ParseExact (string input, string format, IFormatProvider formatProvider, DateTimeStyles styles)
277                 {
278                         if (format == null)
279                                 throw new ArgumentNullException ("format");
280
281                         if (format == String.Empty)
282                                 throw new FormatException ("format is an empty string");
283
284                         return ParseExact (input, new string [] {format}, formatProvider, styles);
285                 }
286
287                 public static DateTimeOffset ParseExact (string input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles)
288                 {
289                         if (input == null)
290                                 throw new ArgumentNullException ("input");
291
292                         if (input == String.Empty)
293                                 throw new FormatException ("input is an empty string");
294
295                         if (formats == null)
296                                 throw new ArgumentNullException ("formats");
297
298                         if (formats.Length == 0)
299                                 throw new FormatException ("Invalid format specifier");
300
301                         DateTimeOffset result;
302                         if (!ParseExact (input, formats, DateTimeFormatInfo.GetInstance (formatProvider), styles, out result))
303                                 throw new FormatException ();
304
305                         return result;
306                 }
307
308                 private static bool ParseExact (string input, string [] formats,
309                                 DateTimeFormatInfo dfi, DateTimeStyles styles, out DateTimeOffset ret)
310                 {
311                         foreach (string format in formats)
312                         {
313                                 if (format == null || format == String.Empty)
314                                         throw new FormatException ("Invlid Format Sting");
315
316                                 DateTimeOffset result;
317                                 if (DoParse (input, format, false, out result, dfi, styles)) {
318                                         ret = result;
319                                         return true;
320                                 }
321                         }
322                         ret = DateTimeOffset.MinValue;
323                         return false;
324                 }
325
326                 private static bool DoParse (string input, 
327                                 string format,
328                                 bool exact,
329                                 out DateTimeOffset result,
330                                 DateTimeFormatInfo dfi,
331                                 DateTimeStyles styles)
332                 {
333                         bool useutc=false, use_invariants = false;
334                         if (format.Length == 1)
335                                 format = DateTimeUtils.GetStandardPattern (format[0], dfi, out useutc, out use_invariants, true);
336
337                         int year = -1;
338                         int month = -1;
339                         int day = -1;
340                         int hour = -1;
341                         int minute = -1;
342                         TimeSpan offset = TimeSpan.Zero;
343
344                         int fi = 0; //format iterator
345                         int ii = 0; //input iterator
346                         while (fi < format.Length) {
347                                 int tokLen;
348                                 char ch = format [fi];
349
350                                 switch (ch) {
351                                 case 'd':
352                                         tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
353                                         switch (tokLen) {
354                                                 case 1:
355                                                         int l = 1;
356                                                         if (input.Length != ii + 1 && System.Char.IsDigit (input[ii + 1]))
357                                                                 l = 2;
358                                                         day = Int32.Parse (input.Substring (ii, l));
359                                                         ii += l;
360                                                         break;
361                                                 case 2:
362                                                         day = Int32.Parse (input.Substring (ii, 2));
363                                                         ii += 2;
364                                                         break;
365                                                 case 3:
366                                                 case 4:
367                                                         ii = input.IndexOf (format [fi + tokLen]);
368                                                         break;
369                                                 default:
370                                                         throw new FormatException ();
371                                                         break;
372                                         }
373                                         
374                                         break;
375                                 case 'h':
376                                         tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
377                                         switch(tokLen) {
378                                                 case 1:
379                                                         int l = 1;
380                                                         if (input.Length != ii + 1 && System.Char.IsDigit (input[ii + 1]))
381                                                                 l = 2;
382                                                         if (hour == -1)
383                                                                 hour = 0;
384                                                         hour += Int32.Parse (input.Substring (ii, l));
385                                                         ii += l;
386                                                         break;
387                                                 case 2:
388                                                         if (hour == -1)
389                                                                 hour = 0;
390                                                         hour += Int32.Parse (input.Substring (ii, 2));
391                                                         ii += 2;
392                                                         break;
393                                                 default:
394                                                         throw new FormatException ();
395                                                         break;
396                                         }
397                                         break;
398                                 case 'H':
399                                         tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
400                                         switch (tokLen) {
401                                                 case 1:
402                                                         int l = 1;
403                                                         if (input.Length != ii + 1 && System.Char.IsDigit (input[ii + 1]))
404                                                                 l = 2;
405                                                         hour = Int32.Parse (input.Substring (ii, l));
406                                                         ii += l;
407                                                         break;
408                                                 case 2:
409                                                         hour = Int32.Parse (input.Substring (ii, 2));
410                                                         ii += 2;
411                                                         break;
412                                                 default:
413                                                         throw new FormatException ();
414                                                         break;
415                                         }
416                                         break;
417                                 case 'm':
418                                         tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
419                                         switch (tokLen) {
420                                                 case 1:
421                                                         int l = 1;
422                                                         if (input.Length != ii + 1 && System.Char.IsDigit (input[ii + 1]))
423                                                                 l = 2;
424                                                         minute = Int32.Parse (input.Substring (ii, l));
425                                                         ii += l;
426                                                         break;
427                                                 case 2:
428                                                         minute = Int32.Parse (input.Substring (ii, 2));
429                                                         ii += 2;
430                                                         break;
431                                                 default:
432                                                         throw new FormatException ();
433                                                         break;
434                                         }
435                                         break;
436                                 case 'M':
437                                         tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
438                                         switch (tokLen) {
439                                                 case 1:
440                                                         int l = 1;
441                                                         if (input.Length != ii + 1 && System.Char.IsDigit (input[ii + 1]))
442                                                                 l = 2;
443                                                         month = Int32.Parse (input.Substring (ii, l));
444                                                         ii += l;
445                                                         break;
446                                                 case 2:
447                                                         month = Int32.Parse (input.Substring (ii, 2));
448                                                         ii += 2;
449                                                         break;
450                                                 case 3:
451                                                         for (int i = 0; i < 13; i++)
452                                                                 if (input.Substring (ii).StartsWith (dfi.AbbreviatedMonthNames [i])) {
453                                                                         month = i + 1;
454                                                                         ii += dfi.AbbreviatedMonthNames [i].Length;
455                                                                         break;
456                                                                 }
457                                                         break;
458                                                 case 4:
459                                                         for (int i = 0; i < 13; i++)
460                                                                 if (input.Substring (ii).StartsWith (dfi.MonthNames [i])) {
461                                                                         month = i + 1;
462                                                                         ii += dfi.MonthNames [i].Length;
463                                                                         break;
464                                                                 }
465                                                         break;
466                                                 default:
467                                                         throw new FormatException ();
468                                         }
469                                         break;
470                                 case 't':
471                                         tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
472                                         switch (tokLen) {
473                                                 case 1:
474                                                         if (input [ii] == dfi.PMDesignator [0]) {
475                                                                 if (hour == -1)
476                                                                         hour = 0;
477                                                                 hour += 12;
478                                                         } else if (input [ii] != dfi.AMDesignator [0])
479                                                                 throw new FormatException ();
480                                                         ii ++;
481                                                         break;
482                                                 case 2:
483                                                         if (input.Substring (ii).StartsWith (dfi.PMDesignator)) {
484                                                                 if (hour == -1)
485                                                                         hour = 0;
486                                                                 hour += 12;
487                                                                 ii += dfi.PMDesignator.Length;
488                                                         } else if (input.Substring (ii).StartsWith (dfi.AMDesignator))
489                                                                 ii += dfi.AMDesignator.Length;
490                                                         else
491                                                                 throw new FormatException ();
492                                                         break;
493
494                                                 default:
495                                                         throw new FormatException ();
496                                                         break;
497                                         }
498                                         break;
499                                 case 'y':
500                                         tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
501                                         switch (tokLen) {
502                                                 case 1:
503                                                         int l = 1;
504                                                         if (input.Length != ii + 1 && System.Char.IsDigit (input[ii + 1]))
505                                                                 l = 2;
506                                                         year = Int32.Parse (input.Substring (ii, l));
507                                                         year += DateTime.Now.Year - DateTime.Now.Year % 100;
508                                                         ii += l;
509                                                         break;
510                                                 case 2:
511                                                         year = Int32.Parse (input.Substring (ii, 2));
512                                                         year += DateTime.Now.Year - DateTime.Now.Year % 100;
513                                                         ii += 2;
514                                                         break;
515                                                 case 3:
516                                                         throw new NotImplementedException ();
517                                                         //ToString ("yyy") seems to print 4-digits year...
518                                                         year = Int32.Parse (input.Substring (ii, 3));
519                                                         year += DateTime.Now.Year - DateTime.Now.Year % 1000;
520                                                         ii += 3;
521                                                         break;
522                                                 default:
523                                                         year = Int32.Parse (input.Substring (ii, tokLen));
524                                                         ii += tokLen;
525                                                         break;
526                                         }
527                                         break;
528                                 case 'z':
529                                         tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
530                                         int off_h, off_m = 0, sign;
531                                         switch (input[ii]) {
532                                                 case '+': sign = 1; break;
533                                                 case '-': sign = -1; break;
534                                                 default:
535                                                         throw new FormatException ();
536                                                         break;
537                                         }
538                                         ii ++;
539                                         switch (tokLen) {
540                                                 case 1:
541                                                         int l = 1;
542                                                         if (input.Length != ii + 1 && System.Char.IsDigit (input[ii + 1]))
543                                                                 l = 2;
544                                                         off_h = Int32.Parse (input.Substring (ii, l));
545                                                         break;
546                                                 case 2:
547                                                         off_h = Int32.Parse (input.Substring (ii, 2));
548                                                         ii += 2;
549                                                         break;
550                                                 case 3:
551                                                         off_h = Int32.Parse (input.Substring (ii, 2));
552                                                         ii += 2;
553                                                         if (input [ii++] != ':')
554                                                                 throw new FormatException ();
555                                                         off_m = Int32.Parse (input.Substring (ii, 2));
556                                                         ii += 2;
557                                                         break;
558                                                 default:
559                                                         throw new FormatException ();
560                                                         break;
561                                         }
562                                         offset = new TimeSpan (sign * off_h, sign * off_m, 0);
563                                         break;
564                                 case ':':
565                                         tokLen = 1;
566                                         if (!input.Substring (ii).StartsWith (dfi.TimeSeparator))
567                                                 throw new FormatException ();
568                                         ii += dfi.TimeSeparator.Length;
569                                         break;
570                                 case '/':
571                                         tokLen = 1;
572                                         if (!input.Substring (ii).StartsWith (dfi.DateSeparator))
573                                                 throw new FormatException ();
574                                         ii += dfi.DateSeparator.Length;
575                                         break;
576                                 case ' ':
577                                         tokLen = 1;
578                                         ii++;
579                                         break;
580                                 default:
581                                         tokLen = 1;
582                                         ii++;
583                                         Console.WriteLine ("un-parsed character: {0}", ch);
584                                         break;
585                                 }
586                                 fi += tokLen;
587                         }
588
589                         if (day > 0 && month > 0 && year > 0 && hour > 0 && minute > 0) {
590                                 result = new DateTimeOffset (year, month, day, hour, minute, 0, offset);
591                                 return true;
592                         }
593                         if (day > 0 && month > 0 && year > 0) {
594                                 result = new DateTimeOffset (year, month, day, 0, 0, 0, offset);
595                                 return true;
596                         }
597
598                         result = DateTimeOffset.MinValue;
599                         return false;
600                 }
601
602                 public TimeSpan Subtract (DateTimeOffset other)
603                 {
604                         return UtcDateTime - other.UtcDateTime;
605                 }
606
607                 public DateTimeOffset Subtract (TimeSpan timeSpan)
608                 {
609                         return Add (-timeSpan);
610                 }
611
612                 public static TimeSpan operator - (DateTimeOffset left, DateTimeOffset right)
613                 {
614                         return left.Subtract (right);
615                 }
616
617                 public static DateTimeOffset operator - (DateTimeOffset dateTimeTz, TimeSpan timeSpan)
618                 {
619                         return dateTimeTz.Subtract (timeSpan);  
620                 }
621
622                 public long ToFileTime ()
623                 {
624                         return UtcDateTime.ToFileTime ();
625                 }
626
627                 public DateTimeOffset ToLocalTime ()
628                 {
629                         return new DateTimeOffset (UtcDateTime.ToLocalTime (), TimeZone.CurrentTimeZone.GetUtcOffset (UtcDateTime.ToLocalTime ()));
630                 }
631
632                 public DateTimeOffset ToOffset (TimeSpan offset)
633                 {
634                         return new DateTimeOffset (dt - utc_offset + offset, offset);
635                 }
636
637                 public override string ToString ()
638                 {
639                         return ToString (null, null);
640                 }
641
642                 public string ToString (IFormatProvider formatProvider)
643                 {
644                         return ToString (null, formatProvider);
645                 }
646
647                 public string ToString (string format)
648                 {
649                         return ToString (format, null);
650                 }
651
652                 public string ToString (string format, IFormatProvider formatProvider)
653                 {
654                         DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance(formatProvider);
655
656                         if (format == null || format == String.Empty)
657                                 format = dfi.ShortDatePattern + " " + dfi.LongTimePattern + " zzz";
658
659                         bool to_utc = false, use_invariant = false;
660                         if (format.Length == 1) {
661                                 char fchar = format [0];
662                                 try {
663                                         format = DateTimeUtils.GetStandardPattern (fchar, dfi, out to_utc, out use_invariant, true);
664                                 } catch {
665                                         format = null;
666                                 }
667                 
668                                 if (format == null)
669                                         throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
670                         }
671                         return to_utc ? DateTimeUtils.ToString (UtcDateTime, TimeSpan.Zero, format, dfi) : DateTimeUtils.ToString (DateTime, Offset, format, dfi);
672                 }
673
674                 public DateTimeOffset ToUniversalTime ()
675                 {
676                         return new DateTimeOffset (UtcDateTime, TimeSpan.Zero); 
677                 }
678
679                 public static bool TryParse (string input, out DateTimeOffset result)
680                 {
681                         try {
682                                 result = Parse (input);
683                                 return true;
684                         } catch {
685                                 result = MinValue;
686                                 return false;
687                         }
688                 }
689
690                 public static bool TryParse (string input, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
691                 {
692                         try {
693                                 result = Parse (input, formatProvider, styles);
694                                 return true;
695                         } catch {
696                                 result = MinValue;
697                                 return false;
698                         }       
699                 }
700
701                 public static bool TryParseExact (string input, string format, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
702                 {
703                         try {
704                                 result = ParseExact (input, format, formatProvider, styles);
705                                 return true;
706                         } catch {
707                                 result = MinValue;
708                                 return false;
709                         }
710                 }
711
712                 public static bool TryParseExact (string input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
713                 {
714                         try {
715                                 result = ParseExact (input, formats, formatProvider, styles);
716                                 return true;
717                         } catch {
718                                 result = MinValue;
719                                 return false;
720                         }
721                 }
722
723                 public DateTime Date {
724                         get { return DateTime.SpecifyKind (dt.Date, DateTimeKind.Unspecified); }
725                 }
726
727                 public DateTime DateTime {
728                         get { return DateTime.SpecifyKind (dt, DateTimeKind.Unspecified); }
729                 }
730
731                 public int Day {
732                         get { return dt.Day; }
733                 }
734
735                 public DayOfWeek DayOfWeek {
736                         get { return dt.DayOfWeek; }
737                 }
738
739                 public int DayOfYear {
740                         get { return dt.DayOfYear; }
741                 }
742
743                 public int Hour {
744                         get { return dt.Hour; }
745                 }
746
747                 public DateTime LocalDateTime {
748                         get { return UtcDateTime.ToLocalTime (); }
749                 }
750
751                 public int Millisecond {
752                         get { return dt.Millisecond; }
753                 }
754
755                 public int Minute {
756                         get { return dt.Minute; }
757                 }
758
759                 public int Month {
760                         get { return dt.Month; }
761                 }
762
763                 public static DateTimeOffset Now {
764                         get { return new DateTimeOffset (DateTime.Now);}
765                 }
766
767                 public TimeSpan Offset {
768                         get { return utc_offset; }      
769                 }
770
771                 public int Second {
772                         get { return dt.Second; }
773                 }
774
775                 public long Ticks {
776                         get { return dt.Ticks; }        
777                 }
778
779                 public TimeSpan TimeOfDay {
780                         get { return dt.TimeOfDay; }
781                 }
782
783                 public DateTime UtcDateTime {
784                         get { return DateTime.SpecifyKind (dt - utc_offset, DateTimeKind.Utc); }        
785                 }
786                 
787                 public static DateTimeOffset UtcNow {
788                         get { return new DateTimeOffset (DateTime.UtcNow); }
789                 }
790
791                 public long UtcTicks {
792                         get { return UtcDateTime.Ticks; }
793                 }
794
795                 public int Year {
796                         get { return dt.Year; }
797                 }
798         }
799 }
800 #endif