fdf37fb933a43fbbf2ab00800895582f6e4900fd
[mono.git] / mcs / class / corlib / System / DateTime.cs
1 //
2 // System.DateTime.cs
3 //
4 // author:
5 //   Marcel Narings (marcel@narings.nl)
6 //   Martin Baulig (martin@gnome.org)
7 //   Atsushi Enomoto (atsushi@ximian.com)
8 //
9 //   (C) 2001 Marcel Narings
10 // Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Collections;
33 using System.Globalization;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
36 using System.Text;
37
38 namespace System
39 {
40         /// <summary>
41         /// The DateTime structure represents dates and time ranging from
42         /// 1-1-0001 12:00:00 AM to 31-12-9999 23:59:00 Common Era.
43         /// </summary>
44         /// 
45         [Serializable]
46         [StructLayout (LayoutKind.Auto)]
47         public struct DateTime : IFormattable, IConvertible, IComparable, IComparable<DateTime>, IEquatable <DateTime>
48         {
49                 private TimeSpan ticks;
50
51                 DateTimeKind kind;
52
53                 private const int dp400 = 146097;
54                 private const int dp100 = 36524;
55                 private const int dp4 = 1461;
56
57                 // w32 file time starts counting from 1/1/1601 00:00 GMT
58                 // which is the constant ticks from the .NET epoch
59                 private const long w32file_epoch = 504911232000000000L;
60
61                 //private const long MAX_VALUE_TICKS = 3155378975400000000L;
62                 // -- Microsoft .NET has this value.
63                 private const long MAX_VALUE_TICKS = 3155378975999999999L;
64
65                 //
66                 // The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed
67                 // in Ticks
68                 //
69                 internal const long UnixEpoch = 621355968000000000L;
70
71                 // for OLE Automation dates
72                 private const long ticks18991230 = 599264352000000000L;
73                 private const double OAMinValue = -657435.0d;
74                 private const double OAMaxValue = 2958466.0d;
75
76                 public static readonly DateTime MaxValue = new DateTime (false, new TimeSpan (MAX_VALUE_TICKS));
77                 public static readonly DateTime MinValue = new DateTime (false, new TimeSpan (0));
78
79                 // DateTime.Parse patterns
80                 // Patterns are divided to date and time patterns. The algorithm will
81                 // try combinations of these patterns. The algorithm also looks for
82                 // day of the week, AM/PM GMT and Z independently of the patterns.
83                 private static readonly string[] ParseTimeFormats = new string [] {
84                         "H:m:s.fffffffzzz",
85                         "H:m:s.fffffff",
86                         "H:m:s tt zzz",
87                         "H:m:szzz",
88                         "H:m:s",
89                         "H:mzzz",
90                         "H:m",
91                         "H tt", // Specifies AM to disallow '8'.
92                         "H'\u6642'm'\u5206's'\u79D2'",
93                 };
94
95                 // DateTime.Parse date patterns extend ParseExact patterns as follows:
96                 //   MMM - month short name or month full name
97                 //   MMMM - month number or short name or month full name
98
99                 // Parse behaves differently according to the ShorDatePattern of the
100                 // DateTimeFormatInfo. The following define the date patterns for
101                 // different orders of day, month and year in ShorDatePattern.
102                 // Note that the year cannot go between the day and the month.
103                 private static readonly string[] ParseYearDayMonthFormats = new string [] {
104                         "yyyy/M/dT",
105                         "M/yyyy/dT",
106                         "yyyy'\u5E74'M'\u6708'd'\u65E5",
107
108
109                         "yyyy/d/MMMM",
110                         "yyyy/MMM/d",
111                         "d/MMMM/yyyy",
112                         "MMM/d/yyyy",
113                         "d/yyyy/MMMM",
114                         "MMM/yyyy/d",
115
116                         "yy/d/M",
117                 };
118
119                 private static readonly string[] ParseYearMonthDayFormats = new string [] {
120                         "yyyy/M/dT",
121                         "M/yyyy/dT",
122                         "yyyy'\u5E74'M'\u6708'd'\u65E5",
123
124                         "yyyy/MMMM/d",
125                         "yyyy/d/MMM",
126                         "MMMM/d/yyyy",
127                         "d/MMM/yyyy",
128                         "MMMM/yyyy/d",
129                         "d/yyyy/MMM",
130
131                         "yy/MMMM/d",
132                         "yy/d/MMM",
133                         "MMM/yy/d",
134                 };
135
136                 private static readonly string[] ParseDayMonthYearFormats = new string [] {
137                         "yyyy/M/dT",
138                         "M/yyyy/dT",
139                         "yyyy'\u5E74'M'\u6708'd'\u65E5",
140
141                         "yyyy/MMMM/d",
142                         "yyyy/d/MMM",
143                         "d/MMMM/yyyy",
144                         "MMM/d/yyyy",
145                         "MMMM/yyyy/d",
146                         "d/yyyy/MMM",
147
148                         "d/MMMM/yy",
149                         "yy/MMM/d",
150                         "d/yy/MMM",
151                         "yy/d/MMM",
152                         "MMM/d/yy",
153                         "MMM/yy/d",
154                 };
155
156                 private static readonly string[] ParseMonthDayYearFormats = new string [] {
157                         "yyyy/M/dT",
158                         "M/yyyy/dT",
159                         "yyyy'\u5E74'M'\u6708'd'\u65E5",
160
161                         "yyyy/MMMM/d",
162                         "yyyy/d/MMM",
163                         "MMMM/d/yyyy",
164                         "d/MMM/yyyy",
165                         "MMMM/yyyy/d",
166                         "d/yyyy/MMM",
167
168                         "MMMM/d/yy",
169                         "MMM/yy/d",
170                         "d/MMM/yy",
171                         "yy/MMM/d",
172                         "d/yy/MMM",
173                         "yy/d/MMM",
174                 };
175
176                 // Patterns influenced by the MonthDayPattern in DateTimeFormatInfo.
177                 // Note that these patterns cannot be followed by the time.
178                 private static readonly string[] MonthDayShortFormats = new string [] {
179                         "MMMM/d",
180                         "d/MMM",
181                         "yyyy/MMMM",
182                 };
183                 private static readonly string[] DayMonthShortFormats = new string [] {
184                         "d/MMMM",
185                         "MMM/yy",
186                         "yyyy/MMMM",
187                 };
188
189                 private enum Which 
190                 {
191                         Day,
192                         DayYear,
193                         Month,
194                         Year
195                 };
196         
197                 private static readonly int[] daysmonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };        
198                 private static readonly int[] daysmonthleap = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };    
199
200                 private static int AbsoluteDays (int year, int month, int day)
201                 {
202                         int[] days;
203                         int temp = 0, m=1 ;
204                 
205                         days = (IsLeapYear(year) ? daysmonthleap  : daysmonth);
206                         
207                         while (m < month)
208                                 temp += days[m++];
209                         return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));
210                 }
211
212                 private int FromTicks(Which what)
213                 {
214                         int num400, num100, num4, numyears; 
215                         int M =1;
216
217                         int[] days = daysmonth;
218                         int totaldays = this.ticks.Days;
219
220                         num400 = (totaldays / dp400);
221                         totaldays -=  num400 * dp400;
222                 
223                         num100 = (totaldays / dp100);
224                         if (num100 == 4)   // leap
225                                 num100 = 3;
226                         totaldays -= (num100 * dp100);
227
228                         num4 = totaldays / dp4;
229                         totaldays -= (num4 * dp4);
230
231                         numyears = totaldays / 365 ;
232
233                         if (numyears == 4)  //leap
234                                 numyears =3 ;
235                         if (what == Which.Year )
236                                 return num400*400 + num100*100 + num4*4 + numyears + 1;
237
238                         totaldays -= (numyears * 365) ;
239                         if (what == Which.DayYear )
240                                 return totaldays + 1;
241                         
242                         if  ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear
243                                 days = daysmonthleap;
244
245                         while (totaldays >= days[M])
246                                 totaldays -= days[M++];
247
248                         if (what == Which.Month )
249                                 return M;
250
251                         return totaldays +1; 
252                 }
253
254
255                 // Constructors
256                 
257                 /// <summary>
258                 /// Constructs a DateTime for specified ticks
259                 /// </summary>
260                 /// 
261                 public DateTime (long ticks)
262                 {
263                         this.ticks = new TimeSpan (ticks);
264                         if (ticks < MinValue.Ticks || ticks > MaxValue.Ticks) {
265                                 string msg = Locale.GetText ("Value {0} is outside the valid range [{1},{2}].", 
266                                         ticks, MinValue.Ticks, MaxValue.Ticks);
267                                 throw new ArgumentOutOfRangeException ("ticks", msg);
268                         }
269                         kind = DateTimeKind.Unspecified;
270                 }
271
272                 public DateTime (int year, int month, int day)
273                         : this (year, month, day,0,0,0,0) {}
274
275                 public DateTime (int year, int month, int day, int hour, int minute, int second)
276                         : this (year, month, day, hour, minute, second, 0)      {}
277
278                 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
279                         {
280                         if ( year < 1 || year > 9999 || 
281                                 month < 1 || month >12  ||
282                                 day < 1 || day > DaysInMonth(year, month) ||
283                                 hour < 0 || hour > 23 ||
284                                 minute < 0 || minute > 59 ||
285                                 second < 0 || second > 59 ||
286                                 millisecond < 0 || millisecond > 999)
287                                 throw new ArgumentOutOfRangeException ("Parameters describe an " +
288                                                                         "unrepresentable DateTime.");
289
290                         ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
291
292                         kind = DateTimeKind.Unspecified;
293                 }
294
295                 public DateTime (int year, int month, int day, Calendar calendar)
296                         : this (year, month, day, 0, 0, 0, 0, calendar)
297                 {
298                 }
299                 
300                 public DateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)
301                         : this (year, month, day, hour, minute, second, 0, calendar)
302                 {
303                 }
304
305                 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar)
306                 {
307                         if (calendar == null)
308                                 throw new ArgumentNullException ("calendar");
309                         ticks = calendar.ToDateTime (year, month, day, hour, minute, second, millisecond).ticks;
310                         kind = DateTimeKind.Unspecified;
311                 }
312
313                 internal DateTime (bool check, TimeSpan value)
314                 {
315                         if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
316                                 throw new ArgumentOutOfRangeException ();
317
318                         ticks = value;
319
320                         kind = DateTimeKind.Unspecified;
321                 }
322
323                 public DateTime (long ticks, DateTimeKind kind) : this (ticks)
324                 {
325                         CheckDateTimeKind (kind);
326                         this.kind = kind;
327                 }
328
329                 public DateTime (int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
330                         : this (year, month, day, hour, minute, second)
331                 {
332                         CheckDateTimeKind (kind);
333                         this.kind = kind;
334                 }
335
336                 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind)
337                         : this (year, month, day, hour, minute, second, millisecond)
338                 {
339                         CheckDateTimeKind (kind);
340                         this.kind = kind;
341                 }
342
343                 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind)
344                         : this (year, month, day, hour, minute, second, millisecond, calendar)
345                 {
346                         CheckDateTimeKind (kind);
347                         this.kind = kind;
348                 }                       
349
350                 /* Properties  */
351
352                 public DateTime Date 
353                 {
354                         get     
355                         { 
356                                 DateTime ret = new DateTime (Year, Month, Day);
357                                 ret.kind = kind;
358                                 return ret;
359                         }
360                 }
361
362                 public int Month 
363                 {
364                         get     
365                         { 
366                                 return FromTicks(Which.Month); 
367                         }
368                 }
369
370                 public int Day
371                 {
372                         get 
373                         { 
374                                 return FromTicks(Which.Day); 
375                         }
376                 }
377
378                 public DayOfWeek DayOfWeek 
379                 {
380                         get 
381                         { 
382                                 return ( (DayOfWeek) ((ticks.Days+1) % 7) ); 
383                         }
384                 }
385
386                 public int DayOfYear 
387                 {
388                         get 
389                         { 
390                                 return FromTicks(Which.DayYear); 
391                         }
392                 }
393
394                 public TimeSpan TimeOfDay 
395                 {
396                         get     
397                         { 
398                                 return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );
399                         }
400                         
401                 }
402
403                 public int Hour 
404                 {
405                         get 
406                         { 
407                                 return ticks.Hours;
408                         }
409                 }
410
411                 public int Minute 
412                 {
413                         get 
414                         { 
415                                 return ticks.Minutes;
416                         }
417                 }
418
419                 public int Second 
420                 {
421                         get     
422                         { 
423                                 return ticks.Seconds;
424                         }
425                 }
426
427                 public int Millisecond 
428                 {
429                         get 
430                         { 
431                                 return ticks.Milliseconds;
432                         }
433                 }
434                 
435                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
436                 internal static extern long GetTimeMonotonic ();
437
438                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
439                 internal static extern long GetNow ();
440
441                 //
442                 // To reduce the time consumed by DateTime.Now, we keep
443                 // the difference to map the system time into a local
444                 // time into `to_local_time_span', we record the timestamp
445                 // for this in `last_now'
446                 //
447                 static object to_local_time_span_object;
448                 static long last_now;
449                 
450                 public static DateTime Now 
451                 {
452                         get     
453                         {
454                                 long now = GetNow ();
455                                 DateTime dt = new DateTime (now);
456
457                                 if ((now - last_now) > TimeSpan.TicksPerMinute){
458                                         to_local_time_span_object = TimeZone.CurrentTimeZone.GetLocalTimeDiff (dt);
459                                         last_now = now;
460
461                                 }
462
463                                 // This is boxed, so we avoid locking.
464                                 DateTime ret = dt + (TimeSpan) to_local_time_span_object;
465                                 ret.kind = DateTimeKind.Local;
466                                 return ret;
467                         }
468                 }
469
470                 public long Ticks
471                 { 
472                         get     
473                         { 
474                                 return ticks.Ticks;
475                         }
476                 }
477         
478                 public static DateTime Today 
479                 {
480                         get {
481                                 DateTime now = Now;
482                                 DateTime today = new DateTime (now.Year, now.Month, now.Day);
483                                 today.kind = now.kind;
484                                 return today;
485                         }
486                 }
487
488                 public static DateTime UtcNow 
489                 {
490                         get {
491                                 return new DateTime (GetNow (), DateTimeKind.Utc);
492                         }
493                 }
494
495                 public int Year 
496                 {
497                         get 
498                         { 
499                                 return FromTicks(Which.Year); 
500                         }
501                 }
502
503                 public DateTimeKind Kind {
504                         get {
505                                 return kind;
506                         }
507                 }
508
509                 /* methods */
510
511                 public DateTime Add (TimeSpan value)
512                 {
513                         DateTime ret = AddTicks (value.Ticks);
514                         ret.kind = kind;
515                         return ret;
516                 }
517
518                 public DateTime AddDays (double value)
519                 {
520                         return AddMilliseconds (Math.Round (value * 86400000));
521                 }
522                 
523                 public DateTime AddTicks (long value)
524                 {
525                         if ((value + ticks.Ticks) > MAX_VALUE_TICKS || (value + ticks.Ticks) < 0) {
526                                 throw new ArgumentOutOfRangeException();
527                         }
528                         DateTime ret = new DateTime (value + ticks.Ticks);
529                         ret.kind = kind;
530                         return ret;
531                 }
532
533                 public DateTime AddHours (double value)
534                 {
535                         return AddMilliseconds (value * 3600000);
536                 }
537
538                 public DateTime AddMilliseconds (double value)
539                 {
540                         if ((value * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
541                                         (value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
542                                 throw new ArgumentOutOfRangeException();
543                         }
544                         long msticks = (long) (value * TimeSpan.TicksPerMillisecond);
545
546                         return AddTicks (msticks);
547                 }
548
549                 // required to match MS implementation for OADate (OLE Automation)
550                 private DateTime AddRoundedMilliseconds (double ms)
551                 {
552                         if ((ms * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
553                                 (ms * TimeSpan.TicksPerMillisecond) < long.MinValue) {
554                                 throw new ArgumentOutOfRangeException ();
555                         }
556                         long msticks = (long) (ms += ms > 0 ? 0.5 : -0.5) * TimeSpan.TicksPerMillisecond;
557
558                         return AddTicks (msticks);
559                 }
560
561                 public DateTime AddMinutes (double value)
562                 {
563                         return AddMilliseconds (value * 60000);
564                 }
565                 
566                 public DateTime AddMonths (int months)
567                 {
568                         int day, month, year,  maxday ;
569                         DateTime temp ;
570
571                         day = this.Day;
572                         month = this.Month + (months % 12);
573                         year = this.Year + months/12 ;
574                         
575                         if (month < 1)
576                         {
577                                 month = 12 + month ;
578                                 year -- ;
579                         }
580                         else if (month>12) 
581                         {
582                                 month = month -12;
583                                 year ++;
584                         }
585                         maxday = DaysInMonth(year, month);
586                         if (day > maxday)
587                                 day = maxday;
588
589                         temp = new DateTime (year, month, day);
590                         temp.kind = kind;
591                         return  temp.Add (this.TimeOfDay);
592                 }
593
594                 public DateTime AddSeconds (double value)
595                 {
596                         return AddMilliseconds (value * 1000);
597                 }
598
599                 public DateTime AddYears (int value)
600                 {
601                         return AddMonths (value * 12);
602                 }
603
604                 public static int Compare (DateTime t1, DateTime t2)
605                 {
606                         if (t1.ticks < t2.ticks) 
607                                 return -1;
608                         else if (t1.ticks > t2.ticks) 
609                                 return 1;
610                         else
611                                 return 0;
612                 }
613
614                 public int CompareTo (object value)
615                 {
616                         if (value == null)
617                                 return 1;
618
619                         if (!(value is System.DateTime))
620                                 throw new ArgumentException (Locale.GetText (
621                                         "Value is not a System.DateTime"));
622
623                         return Compare (this, (DateTime) value);
624                 }
625
626                 public bool IsDaylightSavingTime ()
627                 {
628                         if (kind == DateTimeKind.Utc)
629                                 return false;
630                         return TimeZone.CurrentTimeZone.IsDaylightSavingTime (this);
631                 }
632
633                 public int CompareTo (DateTime value)
634                 {
635                         return Compare (this, value);
636                 }
637
638                 public bool Equals (DateTime value)
639                 {
640                         return value.ticks == ticks;
641                 }
642
643                 public long ToBinary ()
644                 {
645                         switch (kind) {
646                         case DateTimeKind.Utc:
647                                 return Ticks | 0x4000000000000000;
648                         case DateTimeKind.Local:
649                                 return (long) ((ulong) ToUniversalTime ().Ticks | 0x8000000000000000);
650                         default:
651                                 return Ticks;
652                         }
653                 }
654
655                 public static DateTime FromBinary (long dateData)
656                 {
657                         switch ((ulong)dateData >> 62) {
658                         case 1:
659                                 return new DateTime (dateData ^ 0x4000000000000000, DateTimeKind.Utc);
660                         case 0:
661                                 return new DateTime (dateData, DateTimeKind.Unspecified);
662                         default:
663                                 return new DateTime (dateData & 0x3fffffffffffffff, DateTimeKind.Utc).ToLocalTime ();
664                         }
665                 }
666
667                 public static DateTime SpecifyKind (DateTime value, DateTimeKind kind)
668                 {
669                         return new DateTime (value.Ticks, kind);
670                 }
671
672                 public static int DaysInMonth (int year, int month)
673                 {
674                         int[] days ;
675
676                         if (month < 1 || month >12)
677                                 throw new ArgumentOutOfRangeException ();
678
679                         if (year < 1 || year > 9999)
680                                 throw new ArgumentOutOfRangeException ();
681
682                         days = (IsLeapYear(year) ? daysmonthleap  : daysmonth);
683                         return days[month];                     
684                 }
685                 
686                 public override bool Equals (object value)
687                 {
688                         if (!(value is System.DateTime))
689                                 return false;
690
691                         return ((DateTime) value).ticks == ticks;
692                 }
693
694                 public static bool Equals (DateTime t1, DateTime t2 )
695                 {
696                         return (t1.ticks == t2.ticks );
697                 }
698
699                 public static DateTime FromFileTime (long fileTime) 
700                 {
701                         if (fileTime < 0)
702                                 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
703
704                         return new DateTime (w32file_epoch + fileTime).ToLocalTime ();
705                 }
706
707                 public static DateTime FromFileTimeUtc (long fileTime) 
708                 {
709                         if (fileTime < 0)
710                                 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
711
712                         return new DateTime (w32file_epoch + fileTime);
713                 }
714
715                 public static DateTime FromOADate (double d)
716                 {
717                         // An OLE Automation date is implemented as a floating-point number
718                         // whose value is the number of days from midnight, 30 December 1899.
719
720                         // d must be negative 657435.0 through positive 2958466.0.
721                         if ((d <= OAMinValue) || (d >= OAMaxValue))
722                                 throw new ArgumentException ("d", "[-657435,2958466]");
723
724                         DateTime dt = new DateTime (ticks18991230);
725                         if (d < 0.0d) {
726                                 Double days = Math.Ceiling (d);
727                                 // integer part is the number of days (negative)
728                                 dt = dt.AddRoundedMilliseconds (days * 86400000);
729                                 // but decimals are the number of hours (in days fractions) and positive
730                                 Double hours = (days - d);
731                                 dt = dt.AddRoundedMilliseconds (hours * 86400000);
732                         }
733                         else {
734                                 dt = dt.AddRoundedMilliseconds (d * 86400000);
735                         }
736
737                         return dt;
738                 }
739
740                 public string[] GetDateTimeFormats() 
741                 {
742                         return GetDateTimeFormats (CultureInfo.CurrentCulture);
743                 }
744
745                 public string[] GetDateTimeFormats(char format)
746                 {
747                         if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
748                                 throw new FormatException ("Invalid format character.");
749                         string[] result = new string[1];
750                         result[0] = this.ToString(format.ToString());
751                         return result;
752                 }
753                 
754                 public string[] GetDateTimeFormats(IFormatProvider provider)
755                 {
756                         DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
757 //                      return GetDateTimeFormats (info.GetAllDateTimePatterns ());
758                         ArrayList al = new ArrayList ();
759                         foreach (char c in "dDgGfFmMrRstTuUyY")
760                                 al.AddRange (GetDateTimeFormats (c, info));
761                         return al.ToArray (typeof (string)) as string [];
762                 }
763
764                 public string[] GetDateTimeFormats(char format,IFormatProvider provider )
765                 {
766                         if ("dDgGfFmMrRstTuUyY".IndexOf (format) < 0)
767                                 throw new FormatException ("Invalid format character.");
768
769                         // LAMESPEC: There is NO assurance that 'U' ALWAYS
770                         // euqals to 'F', but since we have to iterate all
771                         // the pattern strings, we cannot just use 
772                         // ToString("U", provider) here. I believe that the 
773                         // method's behavior cannot be formalized.
774                         bool adjustutc = false;
775                         switch (format) {
776                         case 'U':
777 //                      case 'r':
778 //                      case 'R':
779 //                      case 'u':
780                                 adjustutc = true;
781                                 break;
782                         }
783                         DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
784                         return GetDateTimeFormats (adjustutc, info.GetAllRawDateTimePatterns (format), info);
785                 }
786
787                 private string [] GetDateTimeFormats (bool adjustutc, string [] patterns, DateTimeFormatInfo dfi)
788                 {
789                         string [] results = new string [patterns.Length];
790                         DateTime val = adjustutc ? ToUniversalTime () : this;
791                         for (int i = 0; i < results.Length; i++)
792                                 results [i] = DateTimeUtils.ToString (val, patterns [i], dfi);
793                         return results;
794                 }
795
796                 private void CheckDateTimeKind (DateTimeKind kind) {
797                         if ((kind != DateTimeKind.Unspecified) && (kind != DateTimeKind.Utc) && (kind != DateTimeKind.Local))
798                                 throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
799                 }
800
801                 public override int GetHashCode ()
802                 {
803                         return (int) ticks.Ticks;
804                 }
805
806                 public TypeCode GetTypeCode ()
807                 {
808                         return TypeCode.DateTime;
809                 }
810
811                 public static bool IsLeapYear (int year)
812                 {
813                         if (year < 1 || year > 9999)
814                                 throw new ArgumentOutOfRangeException ();
815                         return  ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
816                 }
817
818                 public static DateTime Parse (string s)
819                 {
820                         return Parse (s, null);
821                 }
822
823                 public static DateTime Parse (string s, IFormatProvider provider)
824                 {
825                         return Parse (s, provider, DateTimeStyles.AllowWhiteSpaces);
826                 }
827
828                 public static DateTime Parse (string s, IFormatProvider provider, DateTimeStyles styles)
829                 {
830                         if (s == null)
831                                 throw new ArgumentNullException ("s");
832
833                         DateTime res;
834                         DateTimeOffset dto;
835                         Exception exception = null;
836                         if (!CoreParse (s, provider, styles, out res, out dto, true, ref exception))
837                                 throw exception;
838                         
839                         return res;
840                 }
841
842                 const string formatExceptionMessage = "String was not recognized as a valid DateTime.";
843                 
844                 internal static bool CoreParse (string s, IFormatProvider provider, DateTimeStyles styles,
845                                               out DateTime result, out DateTimeOffset dto, bool setExceptionOnError, ref Exception exception)
846                 {
847                         dto = new DateTimeOffset (0, TimeSpan.Zero);
848                         if (s == null || s.Length == 0) {
849                                 if (setExceptionOnError)
850                                         exception = new FormatException (formatExceptionMessage);
851                                 result = MinValue;
852                                 return false;
853                         }
854
855                         if (provider == null)
856                                 provider = CultureInfo.CurrentCulture;
857                         DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
858
859                         // Try first all the combinations of ParseAllDateFormats & ParseTimeFormats
860                         string[] allDateFormats = YearMonthDayFormats (dfi, setExceptionOnError, ref exception);
861                         if (allDateFormats == null){
862                                 result = MinValue;
863                                 return false;
864                         }
865
866                         bool longYear = false;
867                         for (int i = 0; i < allDateFormats.Length; i++) {
868                                 string firstPart = allDateFormats [i];
869                                 bool incompleteFormat = false;
870                                 if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
871                                         return true;
872
873                                 if (!incompleteFormat)
874                                         continue;
875
876                                 for (int j = 0; j < ParseTimeFormats.Length; j++) {
877                                         if (_DoParse (s, firstPart, ParseTimeFormats [j], false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
878                                                 return true;
879                                 }
880                         }
881
882                         //
883                         // Month day formats
884                         //
885                         int dayIndex = dfi.MonthDayPattern.IndexOf('d');
886                         int monthIndex = dfi.MonthDayPattern.IndexOf('M');
887                         if (dayIndex == -1 || monthIndex == -1){
888                                 result = MinValue;
889                                 if (setExceptionOnError)
890                                         exception = new FormatException (Locale.GetText("Order of month and date is not defined by {0}", dfi.MonthDayPattern));
891                                 return false;
892                         }
893                         bool is_day_before_month = dayIndex < monthIndex;
894                         string[] monthDayFormats = is_day_before_month ? DayMonthShortFormats : MonthDayShortFormats;
895                         for (int i = 0; i < monthDayFormats.Length; i++) {
896                                 bool incompleteFormat = false;
897                                 if (_DoParse (s, monthDayFormats[i], "", false, out result, out dto, dfi, styles, true, ref incompleteFormat, ref longYear))
898                                         return true;
899                         }
900                         
901                         for (int j = 0; j < ParseTimeFormats.Length; j++) {
902                                 string firstPart = ParseTimeFormats [j];
903                                 bool incompleteFormat = false;
904                                 if (_DoParse (s, firstPart, "", false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
905                                         return true;
906                                 if (!incompleteFormat)
907                                         continue;
908
909                                 for (int i = 0; i < monthDayFormats.Length; i++) {
910                                         if (_DoParse (s, firstPart, monthDayFormats [i], false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
911                                                 return true;
912                                 }
913                                 for (int i = 0; i < allDateFormats.Length; i++) {
914                                         string dateFormat = allDateFormats [i];
915                                         if (dateFormat[dateFormat.Length - 1] == 'T')
916                                                 continue; // T formats must be before the time part
917                                         if (_DoParse (s, firstPart, dateFormat, false, out result, out dto, dfi, styles, false, ref incompleteFormat, ref longYear))
918                                                 return true;
919                                 }
920                         }
921
922                         // Try as a last resort all the patterns
923                         if (ParseExact (s, dfi.GetAllDateTimePatternsInternal (), dfi, styles, out result, false, ref longYear, setExceptionOnError, ref exception))
924                                 return true;
925
926                         if (!setExceptionOnError)
927                                 return false;
928                         
929                         // .NET 2.x does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
930                         exception = new FormatException (formatExceptionMessage);
931                         return false;
932                 }
933
934                 public static DateTime ParseExact (string s, string format, IFormatProvider provider)
935                 {
936                         return ParseExact (s, format, provider, DateTimeStyles.None);
937                 }
938
939                 private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi, bool setExceptionOnError, ref Exception exc)
940                 {
941                         int dayIndex = dfi.ShortDatePattern.IndexOf('d');
942                         int monthIndex = dfi.ShortDatePattern.IndexOf('M');
943                         int yearIndex = dfi.ShortDatePattern.IndexOf('y');
944                         if (dayIndex == -1 || monthIndex == -1 || yearIndex == -1){
945                                 if (setExceptionOnError)
946                                         exc = new FormatException (Locale.GetText("Order of year, month and date is not defined by {0}", dfi.ShortDatePattern));
947                                 return null;
948                         }
949
950                         if (yearIndex < monthIndex)
951                                 if (monthIndex < dayIndex)
952                                         return ParseYearMonthDayFormats;
953                                 else if (yearIndex < dayIndex)
954                                         return ParseYearDayMonthFormats;
955                                 else {
956                                         // The year cannot be between the date and the month
957                                         if (setExceptionOnError)
958                                                 exc = new FormatException (Locale.GetText("Order of date, year and month defined by {0} is not supported", dfi.ShortDatePattern));
959                                         return null;
960                                 }
961                         else if (dayIndex < monthIndex)
962                                 return ParseDayMonthYearFormats;
963                         else if (dayIndex < yearIndex)
964                                 return ParseMonthDayYearFormats;
965                         else {
966                                 // The year cannot be between the month and the date
967                                 if (setExceptionOnError)
968                                         exc = new FormatException (Locale.GetText("Order of month, year and date defined by {0} is not supported", dfi.ShortDatePattern));
969                                 return null;
970                         }
971                 }
972
973                 private static int _ParseNumber (string s, int valuePos,
974                                                  int min_digits,
975                                                  int digits,
976                                                  bool leadingzero,
977                                                  bool sloppy_parsing,
978                                                  out int num_parsed)
979                 {
980                         int number = 0, i;
981
982                         if (sloppy_parsing)
983                                 leadingzero = false;
984
985                         if (!leadingzero) {
986                                 int real_digits = 0;
987                                 for (i = valuePos; i < s.Length && i < digits + valuePos; i++) {
988                                         if (!Char.IsDigit (s[i]))
989                                                 break;
990
991                                         real_digits++;
992                                 }
993
994                                 digits = real_digits;
995                         }
996                         if (digits < min_digits) {
997                                 num_parsed = -1;
998                                 return 0;
999                         }
1000
1001                         if (s.Length - valuePos < digits) {
1002                                 num_parsed = -1;
1003                                 return 0;
1004                         }
1005
1006                         for (i = valuePos; i < digits + valuePos; i++) {
1007                                 char c = s[i];
1008                                 if (!Char.IsDigit (c)) {
1009                                         num_parsed = -1;
1010                                         return 0;
1011                                 }
1012
1013                                 number = number * 10 + (byte) (c - '0');
1014                         }
1015
1016                         num_parsed = digits;
1017                         return number;
1018                 }
1019
1020                 private static int _ParseEnum (string s, int sPos, string[] values, string[] invValues, bool exact, out int num_parsed)
1021                 {
1022                         // FIXME: I know this is somehow lame code. Probably
1023                         // it should iterate all the enum value and return
1024                         // the longest match. However right now I don't see
1025                         // anything but "1" and "10" - "12" that might match
1026                         // two or more values. (They are only abbrev month
1027                         // names, so do reverse order search). See bug #80094.
1028                         for (int i = values.Length - 1; i >= 0; i--) {
1029                                 if (!exact && invValues [i].Length > values[i].Length) {
1030                                         if (invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1031                                                 return i;
1032                                         if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1033                                                 return i;
1034                                 }
1035                                 else {
1036                                         if (values [i].Length > 0 && _ParseString (s, sPos, 0, values [i], out num_parsed))
1037                                                 return i;
1038                                         if (!exact && invValues [i].Length > 0 && _ParseString (s, sPos, 0, invValues [i], out num_parsed))
1039                                         return i;
1040                                 }
1041                         }
1042
1043                         num_parsed = -1;
1044                         return -1;
1045                 }
1046
1047                 private static bool _ParseString (string s, int sPos, int maxlength, string value, out int num_parsed)
1048                 {
1049                         if (maxlength <= 0)
1050                                 maxlength = value.Length;
1051
1052                         if (sPos + maxlength <= s.Length && String.Compare (s, sPos, value, 0, maxlength, true, CultureInfo.InvariantCulture) == 0) {
1053                                 num_parsed = maxlength;
1054                                 return true;
1055                         }
1056
1057                         num_parsed = -1;
1058                         return false;
1059                 }
1060
1061                 // Note that in case of Parse (exact == false) we check both for AM/PM
1062                 // and the culture spcific AM/PM strings.
1063                 private static bool _ParseAmPm(string s,
1064                                                int valuePos,
1065                                                int num,
1066                                                DateTimeFormatInfo dfi,
1067                                                bool exact,
1068                                                out int num_parsed,
1069                                                ref int ampm)
1070                 {
1071                         num_parsed = -1;
1072                         if (ampm != -1)
1073                                 return false;
1074
1075                         if (!IsLetter (s, valuePos)) {
1076                                 if (dfi.AMDesignator != "")
1077                                         return false;
1078                                 if (exact)
1079                                         ampm = 0;
1080                                 num_parsed = 0;
1081                                 return true;
1082                         }
1083                         DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1084                         if (!exact && _ParseString (s, valuePos, num, invInfo.PMDesignator, out num_parsed) ||
1085                             dfi.PMDesignator != "" && _ParseString(s, valuePos, num, dfi.PMDesignator, out num_parsed))
1086                                 ampm = 1;
1087                         else if (!exact && _ParseString (s, valuePos, num, invInfo.AMDesignator, out num_parsed) ||
1088                                  _ParseString (s, valuePos, num, dfi.AMDesignator, out num_parsed)) {
1089                                 if (exact || num_parsed != 0)
1090                                         ampm = 0;
1091                         }
1092                         else
1093                                 return false;
1094                         return true;
1095                 }
1096
1097                 // Note that in case of Parse (exact == false) we check both for ':'
1098                 // and the culture spcific TimeSperator
1099                 private static bool _ParseTimeSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1100                 {
1101                         return _ParseString (s, sPos, 0, dfi.TimeSeparator, out num_parsed) ||
1102                                !exact && _ParseString (s, sPos, 0, ":", out num_parsed);
1103                 }
1104
1105                 // Accept any character for DateSeparator, except TimeSeparator,
1106                 // a digit or a letter.
1107                 // Not documented, but seems to be MS behaviour here.  See bug 54047.
1108                 private static bool _ParseDateSeparator (string s, int sPos, DateTimeFormatInfo dfi, bool exact, out int num_parsed)
1109                 {
1110                         num_parsed = -1;
1111                         if (exact && s [sPos] != '/')
1112                                 return false;
1113
1114                         if (_ParseTimeSeparator (s, sPos, dfi, exact, out num_parsed) ||
1115                                 Char.IsDigit (s [sPos]) || Char.IsLetter (s [sPos]))
1116                                 return(false);
1117
1118                         num_parsed = 1;
1119                         return true;
1120                 }
1121
1122                 private static bool IsLetter (string s, int pos)
1123                 {
1124                         return pos < s.Length && Char.IsLetter (s [pos]);
1125                 }
1126
1127                 // To implement better DateTime.Parse we use two format strings one
1128                 // for Date and one for Time. This allows us to define two different
1129                 // arrays of formats for Time and Dates and to combine them more or less
1130                 // efficiently. When this mode is used flexibleTwoPartsParsing is true.
1131                 private static bool _DoParse (string s,
1132                                               string firstPart,
1133                                               string secondPart,
1134                                               bool exact,
1135                                               out DateTime result,
1136                                               out DateTimeOffset dto,
1137                                               DateTimeFormatInfo dfi,
1138                                               DateTimeStyles style,
1139                                               bool firstPartIsDate,
1140                                               ref bool incompleteFormat,
1141                                               ref bool longYear)
1142                 {
1143                         bool useutc = false;
1144                         bool use_invariant = false;
1145                         bool sloppy_parsing = false;
1146                         dto = new DateTimeOffset (0, TimeSpan.Zero);
1147                         bool flexibleTwoPartsParsing = !exact && secondPart != null;
1148                         incompleteFormat = false;
1149                         int valuePos = 0;
1150                         string format = firstPart;
1151                         bool afterTFormat = false;
1152                         DateTimeFormatInfo invInfo = DateTimeFormatInfo.InvariantInfo;
1153                         if (format.Length == 1)
1154                                 format = DateTimeUtils.GetStandardPattern (format [0], dfi, out useutc, out use_invariant);
1155
1156                         result = new DateTime (0);
1157                         if (format == null)
1158                                 return false;
1159
1160                         if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
1161                                 format = format.TrimStart (null);
1162
1163                                 s = s.TrimStart (null); // it could be optimized, but will make little good.
1164                         }
1165
1166                         if ((style & DateTimeStyles.AllowTrailingWhite) != 0) {
1167                                 format = format.TrimEnd (null);
1168                                 s = s.TrimEnd (null); // it could be optimized, but will make little good.
1169                         }
1170
1171                         if (use_invariant)
1172                                 dfi = invInfo;
1173
1174                         if ((style & DateTimeStyles.AllowInnerWhite) != 0)
1175                                 sloppy_parsing = true;
1176
1177                         string chars = format;
1178                         int len = format.Length, pos = 0, num = 0;
1179                         if (len == 0)
1180                                 return false;
1181
1182                         int day = -1, dayofweek = -1, month = -1, year = -1;
1183                         int hour = -1, minute = -1, second = -1;
1184                         double fractionalSeconds = -1;
1185                         int ampm = -1;
1186                         int tzsign = -1, tzoffset = -1, tzoffmin = -1;
1187                         bool isFirstPart = true;
1188
1189                         for (; ; )
1190                         {
1191                                 if (valuePos == s.Length)
1192                                         break;
1193
1194                                 int num_parsed = 0;
1195                                 if (flexibleTwoPartsParsing && pos + num == 0)
1196                                 {
1197                                         bool isLetter = IsLetter(s, valuePos);
1198                                         if (isLetter) {
1199                                                 if (s [valuePos] == 'Z')
1200                                                         num_parsed = 1;
1201                                                 else
1202                                                         _ParseString (s, valuePos, 0, "GMT", out num_parsed);
1203                                                 if (num_parsed > 0 && !IsLetter (s, valuePos + num_parsed)) {
1204                                                         valuePos += num_parsed;
1205                                                         useutc = true;
1206                                                         continue;
1207                                                 }
1208                                         }
1209                                         if (!afterTFormat && _ParseAmPm (s, valuePos, 0, dfi, exact, out num_parsed, ref ampm)) {
1210                                                 if (IsLetter (s, valuePos + num_parsed))
1211                                                         ampm = -1;
1212                                                 else if (num_parsed > 0) {
1213                                                         valuePos += num_parsed;
1214                                                         continue;
1215                                                 }
1216                                         }
1217
1218                                         if (!afterTFormat && dayofweek == -1 && isLetter) {
1219                                                 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1220                                                 if (dayofweek == -1)
1221                                                         dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1222                                                 if (dayofweek != -1 && !IsLetter (s, valuePos + num_parsed)) {
1223                                                         valuePos += num_parsed;
1224                                                         continue;
1225                                                 }
1226                                                 else
1227                                                         dayofweek = -1;
1228                                         }
1229
1230                                         if (char.IsWhiteSpace (s [valuePos]) || s [valuePos] == ',') {
1231                                                 valuePos += 1;
1232                                                 continue;
1233                                         }
1234                                         num_parsed = 0;
1235                                 }
1236
1237                                 if (pos + num >= len)
1238                                 {
1239                                         if (flexibleTwoPartsParsing && num == 0) {
1240                                                 afterTFormat = isFirstPart && firstPart [firstPart.Length - 1] == 'T';
1241                                                 if (!isFirstPart && format == "")
1242                                                         break;
1243
1244                                                 pos = 0;
1245                                                 if (isFirstPart)
1246                                                         format = secondPart;
1247                                                 else
1248                                                         format = "";
1249                                                 chars = format;
1250                                                 len = chars.Length;
1251                                                 isFirstPart = false;
1252                                                 continue;
1253                                         }
1254                                         break;
1255                                 }
1256
1257                                 bool leading_zeros = true;
1258
1259                                 if (chars[pos] == '\'') {
1260                                         num = 1;
1261                                         while (pos+num < len) {
1262                                                 if (chars[pos+num] == '\'')
1263                                                         break;
1264
1265                                                 if (valuePos == s.Length || s [valuePos] != chars [pos + num])
1266                                                         return false;
1267
1268                                                 valuePos++;
1269                                                 num++;
1270                                         }
1271
1272                                         pos += num + 1;
1273                                         num = 0;
1274                                         continue;
1275                                 } else if (chars[pos] == '"') {
1276                                         num = 1;
1277                                         while (pos+num < len) {
1278                                                 if (chars[pos+num] == '"')
1279                                                         break;
1280
1281                                                 if (valuePos == s.Length || s [valuePos] != chars[pos+num])
1282                                                         return false;
1283
1284                                                 valuePos++;
1285                                                 num++;
1286                                         }
1287
1288                                         pos += num + 1;
1289                                         num = 0;
1290                                         continue;
1291                                 } else if (chars[pos] == '\\') {
1292                                         pos += num + 1;
1293                                         num = 0;
1294                                         if (pos >= len)
1295                                                 return false;
1296                                         if (s [valuePos] != chars [pos])
1297                                                 return false;
1298
1299                                         valuePos++;
1300                                         pos++;
1301                                         continue;
1302                                 } else if (chars[pos] == '%') {
1303                                         pos++;
1304                                         continue;
1305                                 } else if (char.IsWhiteSpace (s [valuePos]) ||
1306                                         s [valuePos] == ',' && (!exact && chars [pos] == '/' || Char.IsWhiteSpace (chars [pos]))) {
1307                                         valuePos++;
1308                                         num = 0;
1309                                         if (exact && (style & DateTimeStyles.AllowInnerWhite) == 0) {
1310                                                 if (!Char.IsWhiteSpace (chars[pos]))
1311                                                         return false;
1312                                                 pos++;
1313                                                 continue;
1314                                         }
1315
1316                                         int ws = valuePos;
1317                                         while (ws < s.Length) {
1318                                                 if (Char.IsWhiteSpace (s [ws]) || s [ws] == ',')
1319                                                         ws++;
1320                                                 else
1321                                                         break;
1322                                         }
1323                                         valuePos = ws;
1324                                         ws = pos;
1325                                         while (ws < chars.Length) {
1326                                                 if (Char.IsWhiteSpace (chars [ws]) || chars [ws] == ',')
1327                                                         ws++;
1328                                                 else
1329                                                         break;
1330                                         }
1331                                         pos = ws;
1332                                         // A whitespace may match a '/' in the pattern.
1333                                         if (!exact && pos < chars.Length && chars[pos] == '/')
1334                                                 if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1335                                                         pos++;
1336                                         continue;
1337                                 }
1338
1339                                 if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num])) {
1340                                         num++;
1341                                         continue;
1342                                 }
1343
1344                                 switch (chars[pos])
1345                                 {
1346                                 case 'd':
1347                                         if (num < 2 && day != -1 || num >= 2 && dayofweek != -1)
1348                                                 return false;
1349                                         if (num == 0)
1350                                                 day = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1351                                         else if (num == 1)
1352                                                 day = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1353                                         else if (num == 2)
1354                                                 dayofweek = _ParseEnum (s, valuePos, dfi.RawAbbreviatedDayNames, invInfo.RawAbbreviatedDayNames, exact, out num_parsed);
1355                                         else
1356                                                 dayofweek = _ParseEnum (s, valuePos, dfi.RawDayNames, invInfo.RawDayNames, exact, out num_parsed);
1357                                         break;
1358                                 case 'M':
1359                                         if (month != -1)
1360                                                 return false;
1361
1362                                         if (flexibleTwoPartsParsing) {
1363                                                 num_parsed = -1;
1364                                                 if (num == 0 || num == 3)
1365                                                         month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1366                                                 if (num > 1 && num_parsed == -1)
1367                                                         month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1368                                                 if (num > 1 && num_parsed == -1)
1369                                                         month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1370                                                 break;
1371                                         }
1372
1373                                         if (num == 0)
1374                                                 month = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1375                                         else if (num == 1)
1376                                                 month = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1377                                         else if (num == 2)
1378                                                 month = _ParseEnum (s, valuePos, dfi.RawAbbreviatedMonthNames, invInfo.RawAbbreviatedMonthNames, exact, out num_parsed) + 1;
1379                                         else
1380                                                 month = _ParseEnum (s, valuePos, dfi.RawMonthNames, invInfo.RawMonthNames, exact, out num_parsed) + 1;
1381                                         break;
1382                                 case 'y':
1383                                         if (year != -1)
1384                                                 return false;
1385
1386                                         if (num == 0) {
1387                                                 year = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1388                                         } else if (num < 3) {
1389                                                 year = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1390                                         } else {
1391                                                 year = _ParseNumber (s, valuePos, exact ? 4 : 3, 4, false, sloppy_parsing, out num_parsed);
1392                                                 if ((year >= 1000) && (num_parsed == 4) && (!longYear) && (s.Length > 4 + valuePos)) {
1393                                                         int np = 0;
1394                                                         int ly = _ParseNumber (s, valuePos, 5, 5, false, sloppy_parsing, out np);
1395                                                         longYear = (ly > 9999);
1396                                                 }
1397                                                 num = 3;
1398                                         }
1399
1400                                         //FIXME: We should do use dfi.Calendat.TwoDigitYearMax
1401                                         if (num_parsed <= 2)
1402                                                 year += (year < 30) ? 2000 : 1900;
1403                                         break;
1404                                 case 'h':
1405                                         if (hour != -1)
1406                                                 return false;
1407                                         if (num == 0)
1408                                                 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1409                                         else
1410                                                 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1411
1412                                         if (hour > 12)
1413                                                 return false;
1414                                         if (hour == 12)
1415                                                 hour = 0;
1416
1417                                         break;
1418                                 case 'H':
1419                                         if (hour != -1 || !flexibleTwoPartsParsing && ampm >= 0)
1420                                                 return false;
1421                                         if (num == 0)
1422                                                 hour = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1423                                         else
1424                                                 hour = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1425
1426                                         if (hour >= 24)
1427                                                 return false;
1428
1429 //                                      ampm = -2;
1430                                         break;
1431                                 case 'm':
1432                                         if (minute != -1)
1433                                                 return false;
1434                                         if (num == 0)
1435                                                 minute = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1436                                         else
1437                                                 minute = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1438
1439                                         if (minute >= 60)
1440                                                 return false;
1441
1442                                         break;
1443                                 case 's':
1444                                         if (second != -1)
1445                                                 return false;
1446                                         if (num == 0)
1447                                                 second = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1448                                         else
1449                                                 second = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1450
1451                                         if (second >= 60)
1452                                                 return false;
1453
1454                                         break;
1455                                 case 'F':
1456                                         leading_zeros = false;
1457                                         goto case 'f';
1458                                 case 'f':
1459                                         if (num > 6 || fractionalSeconds != -1)
1460                                                 return false;
1461                                         double decimalNumber = (double) _ParseNumber (s, valuePos, 0, num+1, leading_zeros, sloppy_parsing, out num_parsed);
1462                                         if (num_parsed == -1)
1463                                                 return false;
1464                                         fractionalSeconds = decimalNumber / Math.Pow(10.0, num_parsed);
1465                                         break;
1466                                 case 't':
1467                                         if (!_ParseAmPm (s, valuePos, num > 0 ? 0 : 1, dfi, exact, out num_parsed, ref ampm))
1468                                                         return false;
1469                                         break;
1470                                 case 'z':
1471                                         if (tzsign != -1)
1472                                                 return false;
1473
1474                                         if (s [valuePos] == '+')
1475                                                 tzsign = 0;
1476                                         else if (s [valuePos] == '-')
1477                                                 tzsign = 1;
1478                                         else
1479                                                 return false;
1480                                         valuePos++;
1481
1482                                         if (num == 0)
1483                                                 tzoffset = _ParseNumber (s, valuePos, 1, 2, false, sloppy_parsing, out num_parsed);
1484                                         else if (num == 1)
1485                                                 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1486                                         else {
1487                                                 tzoffset = _ParseNumber (s, valuePos, 1, 2, true, /*sloppy_parsing*/true, out num_parsed);
1488                                                 valuePos += num_parsed;
1489                                                 if (num_parsed < 0)
1490                                                         return false;
1491
1492                                                 num_parsed = 0;
1493                                                 if (valuePos < s.Length && Char.IsDigit (s [valuePos]) ||
1494                                                         _ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed)) {
1495                                                         valuePos += num_parsed;
1496                                                         tzoffmin = _ParseNumber (s, valuePos, 1, 2, true, sloppy_parsing, out num_parsed);
1497                                                         if (num_parsed < 0)
1498                                                                 return false;
1499                                                 }
1500                                                 else if (!flexibleTwoPartsParsing)
1501                                                         return false;
1502                                                 else
1503                                                         num_parsed = 0;
1504                                         }
1505                                         break;
1506                                 case 'K':
1507                                         if (s [valuePos] == 'Z') {
1508                                                 valuePos++;
1509                                                 useutc = true;                                          
1510                                         }
1511                                         else if (s [valuePos] == '+' || s [valuePos] == '-') {
1512                                                 if (tzsign != -1)
1513                                                         return false;
1514                                                 if (s [valuePos] == '+')
1515                                                         tzsign = 0;
1516                                                 else if (s [valuePos] == '-')
1517                                                         tzsign = 1;
1518                                                 valuePos++;
1519
1520                                                 // zzz
1521                                                 tzoffset = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1522                                                 valuePos += num_parsed;
1523                                                 if (num_parsed < 0)
1524                                                         return false;
1525
1526                                                 if (Char.IsDigit (s [valuePos]))
1527                                                         num_parsed = 0;
1528                                                 else if (!_ParseString (s, valuePos, 0, dfi.TimeSeparator, out num_parsed))
1529                                                         return false;
1530                                                 valuePos += num_parsed;
1531
1532                                                 tzoffmin = _ParseNumber (s, valuePos, 0, 2, true, sloppy_parsing, out num_parsed);
1533                                                 num = 2;
1534                                                 if (num_parsed < 0)
1535                                                         return false;
1536                                         }
1537                                         break;
1538
1539                                 // LAMESPEC: This should be part of UTCpattern
1540                                 // string and thus should not be considered here.
1541                                 //
1542                                 // Note that 'Z' is not defined as a pattern
1543                                 // character. Keep it for X509 certificate
1544                                 // verification. Also, "Z" != "'Z'" under MS.NET
1545                                 // ("'Z'" is just literal; handled above)
1546                                 case 'Z':
1547                                         if (s [valuePos] != 'Z')
1548                                                 return false;
1549                                         num = 0;
1550                                         num_parsed = 1;
1551                                         useutc = true;
1552                                         break;
1553                                 case 'G':
1554                                         if (s [valuePos] != 'G')
1555                                                 return false;
1556
1557                                         if ((pos + 2 < len) && (valuePos + 2 < s.Length) &&
1558                                                 (chars [pos + 1] == 'M') && (s[valuePos + 1] == 'M') &&
1559                                                 (chars [pos + 2] == 'T') && (s[valuePos + 2] == 'T'))
1560                                         {
1561                                                 useutc = true;
1562                                                 num = 2;
1563                                                 num_parsed = 3;
1564                                         }
1565                                         else {
1566                                                 num = 0;
1567                                                 num_parsed = 1;
1568                                         }
1569                                         break;
1570                                 case ':':
1571                                         if (!_ParseTimeSeparator (s, valuePos, dfi, exact, out num_parsed))
1572                                                 return false;
1573                                         break;
1574                                 case '/':
1575                                         if (!_ParseDateSeparator (s, valuePos, dfi, exact, out num_parsed))
1576                                                 return false;
1577
1578                                         num = 0;
1579                                         break;
1580                                 default:
1581                                         if (s [valuePos] != chars [pos])
1582                                                         return false;
1583
1584                                         num = 0;
1585                                         num_parsed = 1;
1586                                         break;
1587                                 }
1588
1589                                 if (num_parsed < 0)
1590                                         return false;
1591
1592                                 valuePos += num_parsed;
1593
1594                                 if (!exact && !flexibleTwoPartsParsing) {
1595                                         switch (chars [pos]) {
1596                                         case 'm':
1597                                         case 's':
1598                                         case 'F':
1599                                         case 'f':
1600                                         case 'z':
1601                                                 if (s.Length > valuePos && s [valuePos] == 'Z' &&
1602                                                         (pos + 1 == chars.Length || chars [pos + 1] != 'Z')) {
1603                                                         useutc = true;
1604                                                         valuePos++;
1605                                                 }
1606                                                 break;
1607                                         }
1608                                 }
1609
1610                                 pos = pos + num + 1;
1611                                 num = 0;
1612                         }
1613
1614                         if (pos + 1 < len && chars [pos] == '.' && chars [pos + 1] == 'F') {
1615                                 pos++;
1616                                 while (pos < len && chars [pos] == 'F') // '.FFF....' can be mapped to nothing. See bug #444103
1617                                         pos++;
1618                         }
1619                         while (pos < len && chars [pos] == 'K') // 'K' can be mapped to nothing
1620                                 pos++;
1621
1622                         if (pos < len)
1623                                 return false;
1624
1625                         if (s.Length > valuePos) // extraneous tail.
1626                         {
1627                                 if (valuePos == 0)
1628                                         return false;
1629
1630                                 if (Char.IsDigit (s [valuePos]) && Char.IsDigit (s [valuePos - 1]))
1631                                         return false;
1632                                 if (Char.IsLetter (s [valuePos]) && Char.IsLetter (s [valuePos - 1]))
1633                                         return false;
1634                                 incompleteFormat = true;
1635                                 return false;
1636                         }
1637
1638                         if (hour == -1)
1639                                 hour = 0;
1640                         if (minute == -1)
1641                                 minute = 0;
1642
1643                         if (second == -1)
1644                                 second = 0;
1645                         if (fractionalSeconds == -1)
1646                                 fractionalSeconds = 0;
1647
1648                         // If no date was given
1649                         if ((day == -1) && (month == -1) && (year == -1)) {
1650                                 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0) {
1651                                         day = 1;
1652                                         month = 1;
1653                                         year = 1;
1654                                 } else {
1655                                         day = DateTime.Today.Day;
1656                                         month = DateTime.Today.Month;
1657                                         year = DateTime.Today.Year;
1658                                 }
1659                         }
1660
1661                         if (day == -1)
1662                                 day = 1;
1663                         if (month == -1)
1664                                 month = 1;
1665                         if (year == -1) {
1666                                 if ((style & DateTimeStyles.NoCurrentDateDefault) != 0)
1667                                         year = 1;
1668                                 else
1669                                         year = DateTime.Today.Year;
1670                         }
1671
1672                         if (ampm == 0 && hour == 12)
1673                                 hour = 0;
1674
1675                         if (ampm == 1 && (!flexibleTwoPartsParsing || hour < 12))
1676                                 hour = hour + 12;
1677                         
1678                         // For anything out of range 
1679                         // return false
1680                         if (year < 1 || year > 9999 || 
1681                                 month < 1 || month >12  ||
1682                                 day < 1 || day > DateTime.DaysInMonth(year, month) ||
1683                                 hour < 0 || hour > 23 ||
1684                                 minute < 0 || minute > 59 ||
1685                                 second < 0 || second > 59)
1686                                 return false;
1687
1688                         result = new DateTime (year, month, day, hour, minute, second, 0);
1689                         result = result.AddSeconds(fractionalSeconds);
1690
1691                         if (dayofweek != -1 && dayofweek != (int) result.DayOfWeek)
1692                                 return false;
1693
1694                         if (tzsign == -1) {
1695                                 if (result != DateTime.MinValue) {
1696                                         try {
1697                                                 dto = new DateTimeOffset (result);
1698                                         } catch { } // We handle this error in DateTimeOffset.Parse
1699                                 }
1700                         } else {
1701                                 if (tzoffmin == -1)
1702                                         tzoffmin = 0;
1703                                 if (tzoffset == -1)
1704                                         tzoffset = 0;
1705                                 if (tzsign == 1) {
1706                                         tzoffset = -tzoffset;
1707                                         tzoffmin = -tzoffmin;
1708                                 }
1709                                 try {
1710                                         dto = new DateTimeOffset (result, new TimeSpan (tzoffset, tzoffmin, 0));
1711                                 } catch {} // We handle this error in DateTimeOffset.Parse
1712                         }
1713                         bool adjustToUniversal = (style & DateTimeStyles.AdjustToUniversal) != 0;
1714                         
1715                         if (tzsign != -1) {
1716                                 long newticks = (result.ticks - dto.Offset).Ticks;
1717                                 if (newticks < 0)
1718                                         newticks += TimeSpan.TicksPerDay;
1719                                 result = new DateTime (false, new TimeSpan (newticks));
1720                                 result.kind = DateTimeKind.Utc;
1721                                 if ((style & DateTimeStyles.RoundtripKind) != 0)
1722                                         result = result.ToLocalTime ();
1723                         }
1724                         else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
1725                                 result.kind = DateTimeKind.Utc;
1726                         else if ((style & DateTimeStyles.AssumeLocal) != 0)
1727                                 result.kind = DateTimeKind.Local;                                               
1728
1729                         bool adjustToLocal = !adjustToUniversal && (style & DateTimeStyles.RoundtripKind) == 0;
1730                         if (result.kind != DateTimeKind.Unspecified)
1731                         {                               
1732                                 if (adjustToUniversal)
1733                                         result = result.ToUniversalTime ();
1734                                 else if (adjustToLocal)
1735                                         result = result.ToLocalTime ();
1736                         }
1737                         return true;
1738                 }
1739
1740                 public static DateTime ParseExact (string s, string format,
1741                                                    IFormatProvider provider, DateTimeStyles style)
1742                 {
1743                         if (format == null)
1744                                 throw new ArgumentNullException ("format");
1745
1746                         string [] formats = new string [1];
1747                         formats[0] = format;
1748
1749                         return ParseExact (s, formats, provider, style);
1750                 }
1751
1752                 public static DateTime ParseExact (string s, string[] formats,
1753                                                    IFormatProvider provider,
1754                                                    DateTimeStyles style)
1755                 {
1756                         DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1757                         CheckStyle (style);
1758                         if (s == null)
1759                                 throw new ArgumentNullException ("s");
1760                         if (formats == null)
1761                                 throw new ArgumentNullException ("formats");
1762                         if (formats.Length == 0)
1763                                 throw new FormatException ("Format specifier was invalid.");
1764
1765                         DateTime result;
1766                         bool longYear = false;
1767                         Exception e = null;
1768                         if (!ParseExact (s, formats, dfi, style, out result, true, ref longYear, true, ref e))
1769                                 throw e;
1770                         return result;
1771                 }               
1772
1773                 private static void CheckStyle (DateTimeStyles style)
1774                 {
1775                         if ( (style & DateTimeStyles.RoundtripKind) != 0)
1776                         {
1777                                 if ((style & DateTimeStyles.AdjustToUniversal) != 0 || (style & DateTimeStyles.AssumeLocal) != 0 ||
1778                                          (style & DateTimeStyles.AssumeUniversal) != 0)
1779                                         throw new ArgumentException ("The DateTimeStyles value RoundtripKind cannot be used with the values AssumeLocal, Asersal or AdjustToUniversal.", "style");
1780                         }
1781                         if ((style & DateTimeStyles.AssumeUniversal) != 0 && (style & DateTimeStyles.AssumeLocal) != 0)                 
1782                                 throw new ArgumentException ("The DateTimeStyles values AssumeLocal and AssumeUniversal cannot be used together.", "style");
1783                 }
1784
1785                 public static bool TryParse (string s, out DateTime result)
1786                 {
1787                         if (s != null){
1788                                 try {
1789                                         Exception exception = null;
1790                                         DateTimeOffset dto;
1791
1792                                         return CoreParse (s, null, DateTimeStyles.AllowWhiteSpaces, out result, out dto, false, ref exception);
1793                                 } catch { }
1794                         }
1795                         result = MinValue;
1796                         return false;
1797                 }
1798                 
1799                 public static bool TryParse (string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
1800                 {
1801                         if (s != null){
1802                                 try {
1803                                         Exception exception = null;
1804                                         DateTimeOffset dto;
1805                                         
1806                                         return CoreParse (s, provider, styles, out result, out dto, false, ref exception);
1807                                 } catch {}
1808                         } 
1809                         result = MinValue;
1810                         return false;
1811                 }
1812                 
1813                 public static bool TryParseExact (string s, string format,
1814                                                   IFormatProvider provider,
1815                                                   DateTimeStyles style,
1816                                                   out DateTime result)
1817                 {
1818                         string[] formats;
1819                         formats = new string [1];
1820                         formats[0] = format;
1821
1822                         return TryParseExact (s, formats, provider, style, out result);
1823                 }
1824
1825                 public static bool TryParseExact (string s, string[] formats,
1826                                                   IFormatProvider provider,
1827                                                   DateTimeStyles style,
1828                                                   out DateTime result)
1829                 {
1830                         DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1831
1832                         bool longYear = false;
1833                         Exception e = null;
1834                         return ParseExact (s, formats, dfi, style, out result, true, ref longYear, false, ref e);
1835                 }
1836
1837                 private static bool ParseExact (string s, string [] formats,
1838                                                 DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
1839                                                 bool exact, ref bool longYear,
1840                                                 bool setExceptionOnError, ref Exception exception)
1841                 {
1842                         int i;
1843                         bool incompleteFormat = false;
1844                         for (i = 0; i < formats.Length; i++)
1845                         {
1846                                 DateTime result;
1847                                 string format = formats[i];
1848                                 if (format == null || format == String.Empty)
1849                                         break;
1850
1851                                 DateTimeOffset dto;
1852                                 if (_DoParse (s, formats[i], null, exact, out result, out dto, dfi, style, false, ref incompleteFormat, ref longYear)) {
1853                                         ret = result;
1854                                         return true;
1855                                 }
1856                         }
1857
1858                         if (setExceptionOnError)
1859                                 exception = new FormatException ("Invalid format string");
1860                         ret = DateTime.MinValue;
1861                         return false;
1862                 }
1863                 
1864                 public TimeSpan Subtract (DateTime value)
1865                 {
1866                         return new TimeSpan (ticks.Ticks) - value.ticks;
1867                 }
1868
1869                 public DateTime Subtract(TimeSpan value)
1870                 {
1871                         TimeSpan newticks;
1872
1873                         newticks = (new TimeSpan (ticks.Ticks)) - value;
1874                         DateTime ret = new DateTime (true,newticks);
1875                         ret.kind = kind;
1876                         return ret;
1877                 }
1878
1879                 public long ToFileTime()
1880                 {
1881                         DateTime universalTime = ToUniversalTime();
1882                         
1883                         if (universalTime.Ticks < w32file_epoch) {
1884                                 throw new ArgumentOutOfRangeException("file time is not valid");
1885                         }
1886                         
1887                         return(universalTime.Ticks - w32file_epoch);
1888                 }
1889
1890                 public long ToFileTimeUtc()
1891                 {
1892                         if (Ticks < w32file_epoch) {
1893                                 throw new ArgumentOutOfRangeException("file time is not valid");
1894                         }
1895                         
1896                         return (Ticks - w32file_epoch);
1897                 }
1898
1899                 public string ToLongDateString()
1900                 {
1901                         return ToString ("D");
1902                 }
1903
1904                 public string ToLongTimeString()
1905                 {
1906                         return ToString ("T");
1907                 }
1908
1909                 public double ToOADate ()
1910                 {
1911                         long t = this.Ticks;
1912                         // uninitialized DateTime case
1913                         if (t == 0)
1914                                 return 0;
1915                         // we can't reach minimum value
1916                         if (t < 31242239136000000)
1917                                 return OAMinValue + 0.001;
1918
1919                         TimeSpan ts = new TimeSpan (this.Ticks - ticks18991230);
1920                         double result = ts.TotalDays;
1921                         // t < 0 (where 599264352000000000 == 0.0d for OA)
1922                         if (t < 599264352000000000) {
1923                                 // negative days (int) but decimals are positive
1924                                 double d = Math.Ceiling (result);
1925                                 result = d - 2 - (result - d);
1926                         }
1927                         else {
1928                                 // we can't reach maximum value
1929                                 if (result >= OAMaxValue)
1930                                         result = OAMaxValue - 0.00000001d;
1931                         }
1932                         return result;
1933                 }
1934
1935                 public string ToShortDateString()
1936                 {
1937                         return ToString ("d");
1938                 }
1939
1940                 public string ToShortTimeString()
1941                 {
1942                         return ToString ("t");
1943                 }
1944                 
1945                 public override string ToString ()
1946                 {
1947                         return ToString ("G", null);
1948                 }
1949
1950                 public string ToString (IFormatProvider provider)
1951                 {
1952                         return ToString (null, provider);
1953                 }
1954
1955                 public string ToString (string format)
1956                 {
1957                         return ToString (format, null);
1958                 }
1959         
1960                 public string ToString (string format, IFormatProvider provider)
1961                 {
1962                         DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
1963
1964                         if (format == null || format == String.Empty)
1965                                 format = "G";
1966
1967                         bool useutc = false, use_invariant = false;
1968
1969                         if (format.Length == 1) {
1970                                 char fchar = format [0];
1971                                 format = DateTimeUtils.GetStandardPattern (fchar, dfi, out useutc, out use_invariant);
1972                                 if (fchar == 'U')
1973                                         return DateTimeUtils.ToString (ToUniversalTime (), format, dfi);
1974 //                                      return ToUniversalTime()._ToString (format, dfi);
1975
1976                                 if (format == null)
1977                                         throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
1978                         }
1979
1980                         // Don't convert UTC value. It just adds 'Z' for 
1981                         // 'u' format, for the same ticks.
1982                         return DateTimeUtils.ToString (this, format, dfi);
1983                 }
1984
1985                 public DateTime ToLocalTime ()
1986                 {
1987                         return TimeZone.CurrentTimeZone.ToLocalTime (this);
1988                 }
1989
1990                 public DateTime ToUniversalTime()
1991                 {
1992                         return TimeZone.CurrentTimeZone.ToUniversalTime (this);
1993                 }
1994
1995                 /*  OPERATORS */
1996
1997                 public static DateTime operator +(DateTime d, TimeSpan t)
1998                 {
1999                         DateTime ret = new DateTime (true, d.ticks + t);
2000                         ret.kind = d.kind;
2001                         return ret;
2002                 }
2003
2004                 public static bool operator ==(DateTime d1, DateTime d2)
2005                 {
2006                         return (d1.ticks == d2.ticks);
2007                 }
2008
2009                 public static bool operator >(DateTime t1,DateTime t2)
2010                 {
2011                         return (t1.ticks > t2.ticks);
2012                 }
2013
2014                 public static bool operator >=(DateTime t1,DateTime t2)
2015                 {
2016                         return (t1.ticks >= t2.ticks);
2017                 }
2018
2019                 public static bool operator !=(DateTime d1, DateTime d2)
2020                 {
2021                         return (d1.ticks != d2.ticks);
2022                 }
2023
2024                 public static bool operator <(DateTime t1,      DateTime t2)
2025                 {
2026                         return (t1.ticks < t2.ticks );
2027                 }
2028
2029                 public static bool operator <=(DateTime t1,DateTime t2)
2030                 {
2031                         return (t1.ticks <= t2.ticks);
2032                 }
2033
2034                 public static TimeSpan operator -(DateTime d1,DateTime d2)
2035                 {
2036                         return new TimeSpan((d1.ticks - d2.ticks).Ticks);
2037                 }
2038
2039                 public static DateTime operator -(DateTime d,TimeSpan t)
2040                 {
2041                         DateTime ret = new DateTime (true, d.ticks - t);
2042                         ret.kind = d.kind;
2043                         return ret;
2044                 }
2045
2046                 bool IConvertible.ToBoolean(IFormatProvider provider)
2047                 {
2048                         throw new InvalidCastException();
2049                 }
2050                 
2051                 byte IConvertible.ToByte(IFormatProvider provider)
2052                 {
2053                         throw new InvalidCastException();
2054
2055                 }
2056
2057                 char IConvertible.ToChar(IFormatProvider provider)
2058                 {
2059                         throw new InvalidCastException();
2060                 }
2061
2062                 System.DateTime IConvertible.ToDateTime(IFormatProvider provider)
2063                 {
2064                         return this;
2065                 } 
2066                 
2067                 decimal IConvertible.ToDecimal(IFormatProvider provider)
2068                 {
2069                          throw new InvalidCastException();
2070                 }
2071
2072                 double IConvertible.ToDouble(IFormatProvider provider)
2073                 {
2074                         throw new InvalidCastException();
2075                 }
2076
2077                 Int16 IConvertible.ToInt16(IFormatProvider provider)
2078                 {
2079                         throw new InvalidCastException();
2080                 }
2081
2082                 Int32 IConvertible.ToInt32(IFormatProvider provider)
2083                 {
2084                         throw new InvalidCastException();
2085                 }
2086
2087                 Int64 IConvertible.ToInt64(IFormatProvider provider)
2088                 {
2089                         throw new InvalidCastException();
2090                 }
2091
2092                 SByte IConvertible.ToSByte(IFormatProvider provider)
2093                 {
2094                         throw new InvalidCastException();
2095                 }
2096
2097                 Single IConvertible.ToSingle(IFormatProvider provider)
2098                 {
2099                         throw new InvalidCastException();
2100                 }
2101
2102                 object IConvertible.ToType (Type targetType, IFormatProvider provider)
2103                 {
2104                         if (targetType == null)
2105                                 throw new ArgumentNullException ("targetType");
2106
2107                         if (targetType == typeof (DateTime))
2108                                 return this;
2109                         else if (targetType == typeof (String))
2110                                 return this.ToString (provider);
2111                         else if (targetType == typeof (Object))
2112                                 return this;
2113                         else
2114                                 throw new InvalidCastException();
2115                 }
2116
2117                 UInt16 IConvertible.ToUInt16(IFormatProvider provider)
2118                 {
2119                         throw new InvalidCastException();
2120                 }
2121
2122                 UInt32 IConvertible.ToUInt32(IFormatProvider provider)
2123                 {
2124                         throw new InvalidCastException();
2125                 }
2126
2127                 UInt64 IConvertible.ToUInt64(IFormatProvider provider)
2128                 {
2129                         throw new InvalidCastException();
2130                 }
2131         }
2132 }