5 // Marcel Narings (marcel@narings.nl)
7 // (C) 2001 Marcel Narings
10 using System.Globalization;
11 using System.Runtime.CompilerServices;
17 /// The DateTime structure represents dates and time ranging from
18 /// 1-1-0001 12:00:00 AM to 31-12-9999 23:59:00 Common Era.
21 public struct DateTime : IComparable , IFormattable , IConvertible
23 private TimeSpan ticks;
24 private TimeSpan utcoffset;
26 private const int dp400 = 146097;
27 private const int dp100 = 36524;
28 private const int dp4 = 1461;
30 // w32 file time starts counting from 1/1/1601 00:00 GMT
31 // which is the constant ticks from the .NET epoch
32 private const long w32file_epoch = 504911232000000000L;
35 // The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed
38 internal const long UnixEpoch = 621355968000000000L;
40 public static readonly DateTime MaxValue = new DateTime (false,TimeSpan.MaxValue);
41 public static readonly DateTime MinValue = new DateTime (false,TimeSpan.MinValue);
51 private static int[] daysmonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
52 private static int[] daysmonthleap = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
54 private static int AbsoluteDays (int year, int month, int day)
59 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
63 return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));
66 private int FromTicks(Which what)
68 int num400, num100, num4, numyears;
71 int[] days = daysmonth;
72 int totaldays = this.ticks.Days;
74 num400 = (totaldays / dp400);
75 totaldays -= num400 * dp400;
77 num100 = (totaldays / dp100);
78 if (num100 == 4) // leap
80 totaldays -= (num100 * dp100);
82 num4 = totaldays / dp4;
83 totaldays -= (num4 * dp4);
85 numyears = totaldays / 365 ;
87 if (numyears == 4) //leap
89 if (what == Which.Year )
90 return num400*400 + num100*100 + num4*4 + numyears + 1;
92 totaldays -= (numyears * 365) ;
93 if (what == Which.DayYear )
96 if ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear
99 while (totaldays >= days[M])
100 totaldays -= days[M++];
102 if (what == Which.Month )
112 /// Constructs a DateTime for specified ticks
115 public DateTime (long newticks)
116 // `local' must default to false here to avoid
118 : this (false, newticks) {}
120 internal DateTime (bool local, long newticks)
121 : this (true, new TimeSpan (newticks))
124 TimeZone tz = TimeZone.CurrentTimeZone;
126 utcoffset = tz.GetUtcOffset (this);
128 ticks = ticks + utcoffset;
132 public DateTime (int year, int month, int day)
133 : this (year, month, day,0,0,0,0) {}
135 public DateTime (int year, int month, int day, int hour, int minute, int second)
136 : this (year, month, day, hour, minute, second, 0) {}
138 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
140 if ( year < 1 || year > 9999 ||
141 month < 1 || month >12 ||
142 day < 1 || day > DaysInMonth(year, month) ||
143 hour < 0 || hour > 23 ||
144 minute < 0 || minute > 59 ||
145 second < 0 || second > 59 )
146 throw new ArgumentOutOfRangeException() ;
148 ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
149 utcoffset = new TimeSpan (0);
152 public DateTime (int year, int month, int day, Calendar calendar)
153 : this (year, month, day, 0, 0, 0, 0, calendar) {}
156 public DateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)
157 : this (year, month, day, hour, minute, second, 0, calendar) {}
160 public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar)
161 : this(year, month, day, hour, minute, second, millisecond)
163 if ( calendar == null)
164 throw new ArgumentNullException();
167 internal DateTime (bool check, TimeSpan value)
169 if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
170 throw new ArgumentOutOfRangeException ();
174 utcoffset = new TimeSpan (0);
183 return new DateTime (Year, Month, Day);
191 return FromTicks(Which.Month);
200 return FromTicks(Which.Day);
204 public DayOfWeek DayOfWeek
208 return ( (DayOfWeek) ((ticks.Days+1) % 7) );
216 return FromTicks(Which.DayYear);
220 public TimeSpan TimeOfDay
224 return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );
241 return ticks.Minutes;
249 return ticks.Seconds;
253 public int Millisecond
257 return ticks.Milliseconds;
261 [MethodImplAttribute(MethodImplOptions.InternalCall)]
262 private static extern long GetNow ();
264 public static DateTime Now
268 return new DateTime (true, GetNow ());
280 public static DateTime Today
284 return new DateTime (true, (GetNow () / TimeSpan.TicksPerDay) * TimeSpan.TicksPerDay);
288 public static DateTime UtcNow
291 return new DateTime (GetNow ());
299 return FromTicks(Which.Year);
305 public DateTime Add (TimeSpan ts)
307 return new DateTime (true, ticks) + ts;
310 public DateTime AddDays (double days)
312 return AddMilliseconds (days * 86400000);
315 public DateTime AddTicks (long t)
317 return Add (new TimeSpan (t));
320 public DateTime AddHours (double hours)
322 return AddMilliseconds (hours * 3600000);
325 public DateTime AddMilliseconds (double ms)
329 msticks = (long) (ms += ms > 0 ? 0.5 : -0.5) * TimeSpan.TicksPerMillisecond ;
331 return AddTicks (msticks);
334 public DateTime AddMinutes (double minutes)
336 return AddMilliseconds (minutes * 60000);
339 public DateTime AddMonths (int months)
341 int day, month, year, maxday ;
345 month = this.Month + (months % 12);
346 year = this.Year + months/12 ;
358 maxday = DaysInMonth(year, month);
362 temp = new DateTime (year, month, day);
363 return temp.Add (this.TimeOfDay);
366 public DateTime AddSeconds (double seconds)
368 return AddMilliseconds (seconds*1000);
371 public DateTime AddYears (int years )
373 return AddMonths(years * 12);
376 public static int Compare (DateTime t1, DateTime t2)
378 if (t1.ticks < t2.ticks)
380 else if (t1.ticks > t2.ticks)
386 public int CompareTo (object v)
391 if (!(v is System.DateTime))
392 throw new ArgumentException (Locale.GetText (
393 "Value is not a System.DateTime"));
395 return Compare (this, (DateTime) v);
398 public static int DaysInMonth (int year, int month)
402 if (month < 1 || month >12)
403 throw new ArgumentOutOfRangeException ();
405 days = (IsLeapYear(year) ? daysmonthleap : daysmonth);
409 public override bool Equals (object o)
411 if (!(o is System.DateTime))
414 return ((DateTime) o).ticks == ticks;
417 public static bool Equals (DateTime t1, DateTime t2 )
419 return (t1.ticks == t2.ticks );
422 public static DateTime FromFileTime (long fileTime)
424 return new DateTime (w32file_epoch + fileTime);
427 // TODO: Implement me.
429 public static DateTime FromOADate (double d)
431 return new DateTime(0);
434 // TODO: Implement me.
436 public string[] GetDateTimeFormats()
443 public string[] GetDateTimeFormats(char format)
448 // TODO: implement me
450 public string[] GetDateTimeFormats(IFormatProvider provider)
457 public string[] GetDateTimeFormats(char format,IFormatProvider provider )
462 public override int GetHashCode ()
464 return (int) ticks.Ticks;
467 public TypeCode GetTypeCode ()
469 return TypeCode.DateTime;
472 public static bool IsLeapYear (int year)
474 return ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
478 public static DateTime Parse (string s)
480 // TODO: Implement me
481 return new DateTime (0);
485 public static DateTime Parse (string s, IFormatProvider fp)
487 // TODO: Implement me
488 return new DateTime (0);
492 public static DateTime Parse (string s, NumberStyles style, IFormatProvider fp)
494 // TODO: Implement me
495 return new DateTime (0);
499 public static DateTime ParseExact(string s, string format, IFormatProvider provider )
501 // TODO: Implement me
502 return new DateTime (0);
506 public static DateTime ParseExact(string s, string format, IFormatProvider provider, DateTimeStyles style )
508 // TODO: Implement me
509 return new DateTime (0);
514 public static DateTime ParseExact( string s, string[] formats, IFormatProvider provider,
515 DateTimeStyles style )
517 // TODO: Implement me
518 return new DateTime (0);
522 public TimeSpan Subtract(DateTime dt)
524 return new TimeSpan(ticks.Ticks) - dt.ticks;
527 public DateTime Subtract(TimeSpan ts)
531 newticks = (new TimeSpan (ticks.Ticks)) - ts;
532 return new DateTime(true,newticks);
535 public long ToFileTime()
537 if(ticks.Ticks < w32file_epoch) {
538 throw new ArgumentOutOfRangeException("file time is not valid");
541 return(ticks.Ticks - w32file_epoch);
544 public string ToLongDateString()
546 return ToString ("D");
549 public string ToLongTimeString()
551 return ToString ("T");
555 public double ToOADate()
561 public string ToShortDateString()
563 return ToString ("d");
566 public string ToShortTimeString()
568 return ToString ("t");
571 public override string ToString ()
573 return ToString (null, null);
576 public string ToString (IFormatProvider fp)
578 return ToString (null, fp);
581 public string ToString (string format)
583 return ToString (format, null);
586 internal string _GetStandardPattern (char format, DateTimeFormatInfo dfi, out bool useutc)
588 String pattern, f1, f2;
595 pattern = dfi.ShortDatePattern;
598 pattern = dfi.LongDatePattern;
601 f1 = dfi.LongDatePattern;
602 f2 = dfi.ShortTimePattern;
603 pattern = String.Concat (f1, " ");
604 pattern = String.Concat (pattern, f2);
607 pattern = dfi.FullDateTimePattern;
610 f1 = dfi.ShortDatePattern;
611 f2 = dfi.ShortTimePattern;
612 pattern = String.Concat (f1, " ");
613 pattern = String.Concat (pattern, f2);
616 f1 = dfi.ShortDatePattern;
617 f2 = dfi.LongTimePattern;
618 pattern = String.Concat (f1, " ");
619 pattern = String.Concat (pattern, f2);
623 pattern = dfi.MonthDayPattern;
627 pattern = dfi.RFC1123Pattern;
630 pattern = dfi.SortableDateTimePattern;
633 pattern = dfi.ShortTimePattern;
636 pattern = dfi.LongTimePattern;
639 pattern = dfi.UniversalSortableDateTimePattern;
643 f1 = dfi.LongDatePattern;
644 f2 = dfi.LongTimePattern;
645 pattern = String.Concat (f1, " ");
646 pattern = String.Concat (pattern, f2);
651 pattern = dfi.YearMonthPattern;
658 Console.Write ("Pattern: ");
659 Console.WriteLine (pattern);
664 internal string _ToString (string format, DateTimeFormatInfo dfi)
666 String str = null, result = null;
667 char[] chars = format.ToCharArray ();
668 int len = format.Length, pos = 0, num = 0;
670 while (pos+num < len)
672 if (chars[pos] == '\'')
675 while (pos+num < len)
677 if (chars[pos+num] == '\'')
680 result = String.Concat (result, chars[pos+num]);
685 throw new FormatException (Locale.GetText ("The specified format is invalid"));
691 else if (chars[pos] == '\\')
694 throw new FormatException (Locale.GetText ("The specified format is invalid"));
696 result = String.Concat (result, chars[pos]);
700 else if (chars[pos] == '%')
707 if ((pos+num+1 < len) && (chars[pos+num+1] == chars[pos+num]))
717 str = Day.ToString ("d");
719 str = Day.ToString ("d02");
721 str = dfi.GetAbbreviatedDayName (DayOfWeek);
724 str = dfi.GetDayName (DayOfWeek);
730 str = Month.ToString ("d");
732 str = Month.ToString ("d02");
734 str = dfi.GetAbbreviatedMonthName (Month);
737 str = dfi.GetMonthName (Month);
744 int shortyear = Year % 100;
745 str = shortyear.ToString ("d");
749 int shortyear = Year % 100;
750 str = shortyear.ToString ("d02");
755 str = Year.ToString ("d");
763 num = Math.Min (num, 6);
765 long ms = (long) Millisecond;
767 for (int i = 0; i < num; i++)
769 long maxexp = TimeSpan.TicksPerMillisecond;
771 exp = Math.Min (exp, maxexp);
772 ms = ms * exp / maxexp;
774 String prec = (num+1).ToString ("d02");
775 str = ms.ToString (String.Concat ("d", prec));
781 int shorthour = Hour % 12;
782 str = shorthour.ToString ("d");
786 int shorthour = Hour % 12;
787 str = shorthour.ToString ("d02");
793 str = Hour.ToString ("d");
796 str = Hour.ToString ("d02");
802 str = Minute.ToString ("d");
805 str = Minute.ToString ("d02");
811 str = Second.ToString ("d");
814 str = Second.ToString ("d02");
820 str = dfi.AMDesignator;
822 str = dfi.PMDesignator;
825 str = str.Substring (0,1);
832 int offset = utcoffset.Hours;
833 str = offset.ToString ("d");
835 str = String.Concat ("+", str);
839 int offset = utcoffset.Hours;
840 str = offset.ToString ("d02");
842 str = String.Concat ("+", str);
846 int offhour = utcoffset.Hours;
847 int offminute = utcoffset.Minutes;
848 str = offhour.ToString ("d02");
849 str = String.Concat (str, dfi.TimeSeparator);
850 str = String.Concat (str, offminute.ToString ("d02"));
852 str = String.Concat ("+", str);
857 str = dfi.TimeSeparator;
861 str = dfi.DateSeparator;
865 str = String.Concat (chars [pos]);
870 result = String.Concat (result, str);
880 public string ToString (string format, IFormatProvider fp)
882 DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance(fp);
885 format = dfi.FullDateTimePattern;
889 if (format.Length == 1) {
890 char fchar = (format.ToCharArray ())[0];
891 format = this._GetStandardPattern (fchar, dfi, out useutc);
895 return this.ToUniversalTime ()._ToString (format, dfi);
897 return this._ToString (format, dfi);
900 public DateTime ToLocalTime()
902 TimeZone tz = TimeZone.CurrentTimeZone;
904 TimeSpan offset = tz.GetUtcOffset (this);
906 return new DateTime (true, ticks + offset);
909 public DateTime ToUniversalTime()
911 TimeZone tz = TimeZone.CurrentTimeZone;
913 TimeSpan offset = tz.GetUtcOffset (this);
915 return new DateTime (true, ticks - offset);
920 public static DateTime operator +(DateTime d, TimeSpan t)
922 return new DateTime (true, d.ticks + t);
925 public static bool operator ==(DateTime d1, DateTime d2)
927 return (d1.ticks == d2.ticks);
930 public static bool operator >(DateTime t1,DateTime t2)
932 return (t1.ticks > t2.ticks);
935 public static bool operator >=(DateTime t1,DateTime t2)
937 return (t1.ticks >= t2.ticks);
940 public static bool operator !=(DateTime d1, DateTime d2)
942 return (d1.ticks != d2.ticks);
945 public static bool operator <(DateTime t1, DateTime t2)
947 return (t1.ticks < t2.ticks );
950 public static bool operator <=(DateTime t1,DateTime t2)
952 return (t1.ticks <= t2.ticks);
955 public static TimeSpan operator -(DateTime d1,DateTime d2)
957 return new TimeSpan((d1.ticks - d2.ticks).Ticks);
960 public static DateTime operator -(DateTime d,TimeSpan t)
962 return new DateTime (true, d.ticks - t);
965 public bool ToBoolean(IFormatProvider provider)
967 throw new InvalidCastException();
970 public byte ToByte(IFormatProvider provider)
972 throw new InvalidCastException();
975 public char ToChar(IFormatProvider provider)
977 throw new InvalidCastException();
982 public System.DateTime ToDateTime(IFormatProvider provider)
984 return new System.DateTime(true,this.ticks);
987 public decimal ToDecimal(IFormatProvider provider)
989 throw new InvalidCastException();
992 public double ToDouble(IFormatProvider provider)
994 throw new InvalidCastException();
997 public Int16 ToInt16(IFormatProvider provider)
999 throw new InvalidCastException();
1002 public Int32 ToInt32(IFormatProvider provider)
1004 throw new InvalidCastException();
1007 public Int64 ToInt64(IFormatProvider provider)
1009 throw new InvalidCastException();
1012 [CLSCompliant(false)]
1013 public SByte ToSByte(IFormatProvider provider)
1015 throw new InvalidCastException();
1018 public Single ToSingle(IFormatProvider provider)
1020 throw new InvalidCastException();
1023 public object ToType(Type conversionType,IFormatProvider provider)
1025 throw new InvalidCastException();
1028 UInt16 System.IConvertible.ToUInt16(IFormatProvider provider)
1030 throw new InvalidCastException();
1033 [CLSCompliant(false)]
1034 public UInt32 ToUInt32(IFormatProvider provider)
1036 throw new InvalidCastException();
1039 [CLSCompliant(false)]
1040 public UInt64 ToUInt64(IFormatProvider provider)
1042 throw new InvalidCastException();
1049 public enum DayOfWeek