5 // Marcel Narings (marcel@narings.nl)
6 // Martin Baulig (martin@gnome.org)
7 // Atsushi Enomoto (atsushi@ximian.com)
9 // (C) 2001 Marcel Narings
10 // Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
32 using System
.Collections
;
33 using System
.Globalization
;
34 using System
.Runtime
.CompilerServices
;
35 using System
.Runtime
.InteropServices
;
37 using System
.Runtime
.Serialization
;
42 /// The DateTime structure represents dates and time ranging from
43 /// 1-1-0001 12:00:00 AM to 31-12-9999 23:59:00 Common Era.
47 [StructLayout (LayoutKind
.Auto
)]
48 public struct DateTime
: IFormattable
, IConvertible
, IComparable
, ISerializable
, IComparable
<DateTime
>, IEquatable
<DateTime
>
52 if (MonoTouchAOTHelper
.FalseFlag
) {
53 var comparer
= new System
.Collections
.Generic
.GenericComparer
<DateTime
> ();
54 var eqcomparer
= new System
.Collections
.Generic
.GenericEqualityComparer
<DateTime
> ();
58 private TimeSpan ticks
;
62 private const int dp400
= 146097;
63 private const int dp100
= 36524;
64 private const int dp4
= 1461;
66 // w32 file time starts counting from 1/1/1601 00:00 GMT
67 // which is the constant ticks from the .NET epoch
68 private const long w32file_epoch
= 504911232000000000L;
70 //private const long MAX_VALUE_TICKS = 3155378975400000000L;
71 // -- Microsoft .NET has this value.
72 private const long MAX_VALUE_TICKS
= 3155378975999999999L;
75 // The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed
78 internal const long UnixEpoch
= 621355968000000000L;
80 // for OLE Automation dates
81 private const long ticks18991230
= 599264352000000000L;
82 private const double OAMinValue
= -657435.0d
;
83 private const double OAMaxValue
= 2958466.0d
;
85 public static readonly DateTime MaxValue
= new DateTime (false, new TimeSpan (MAX_VALUE_TICKS
));
86 public static readonly DateTime MinValue
= new DateTime (false, new TimeSpan (0));
88 // DateTime.Parse patterns
89 // Patterns are divided to date and time patterns. The algorithm will
90 // try combinations of these patterns. The algorithm also looks for
91 // day of the week, AM/PM GMT and Z independently of the patterns.
92 private static readonly string[] ParseTimeFormats
= new string [] {
100 "H tt", // Specifies AM to disallow '8'.
101 "H'\u6642'm'\u5206's'\u79D2'",
104 // DateTime.Parse date patterns extend ParseExact patterns as follows:
105 // MMM - month short name or month full name
106 // MMMM - month number or short name or month full name
108 // Parse behaves differently according to the ShorDatePattern of the
109 // DateTimeFormatInfo. The following define the date patterns for
110 // different orders of day, month and year in ShorDatePattern.
111 // Note that the year cannot go between the day and the month.
112 private static readonly string[] ParseYearDayMonthFormats
= new string [] {
115 "yyyy'\u5E74'M'\u6708'd'\u65E5",
128 private static readonly string[] ParseYearMonthDayFormats
= new string [] {
131 "yyyy'\u5E74'M'\u6708'd'\u65E5",
145 private static readonly string[] ParseDayMonthYearFormats
= new string [] {
148 "yyyy'\u5E74'M'\u6708'd'\u65E5",
165 private static readonly string[] ParseMonthDayYearFormats
= new string [] {
168 "yyyy'\u5E74'M'\u6708'd'\u65E5",
185 // Patterns influenced by the MonthDayPattern in DateTimeFormatInfo.
186 // Note that these patterns cannot be followed by the time.
187 private static readonly string[] MonthDayShortFormats
= new string [] {
192 private static readonly string[] DayMonthShortFormats
= new string [] {
206 private static readonly int[] daysmonth
= { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
;
207 private static readonly int[] daysmonthleap
= { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
;
209 private static int AbsoluteDays (int year
, int month
, int day
)
214 days
= (IsLeapYear(year
) ? daysmonthleap
: daysmonth
);
218 return ((day
-1) + temp
+ (365* (year
-1)) + ((year
-1)/4) - ((year
-1)/100) + ((year
-1)/400));
221 private int FromTicks(Which what
)
223 int num400
, num100
, num4
, numyears
;
226 int[] days
= daysmonth
;
227 int totaldays
= this.ticks
.Days
;
229 num400
= (totaldays
/ dp400
);
230 totaldays
-= num400
* dp400
;
232 num100
= (totaldays
/ dp100
);
233 if (num100
== 4) // leap
235 totaldays
-= (num100
* dp100
);
237 num4
= totaldays
/ dp4
;
238 totaldays
-= (num4
* dp4
);
240 numyears
= totaldays
/ 365 ;
242 if (numyears
== 4) //leap
244 if (what
== Which
.Year
)
245 return num400
*400 + num100
*100 + num4
*4 + numyears
+ 1;
247 totaldays
-= (numyears
* 365) ;
248 if (what
== Which
.DayYear
)
249 return totaldays
+ 1;
251 if ((numyears
==3) && ((num100
== 3) || !(num4
== 24)) ) //31 dec leapyear
252 days
= daysmonthleap
;
254 while (totaldays
>= days
[M
])
255 totaldays
-= days
[M
++];
257 if (what
== Which
.Month
)
267 /// Constructs a DateTime for specified ticks
270 public DateTime (long ticks
)
272 this.ticks
= new TimeSpan (ticks
);
273 if (ticks
< MinValue
.Ticks
|| ticks
> MaxValue
.Ticks
) {
274 string msg
= Locale
.GetText ("Value {0} is outside the valid range [{1},{2}].",
275 ticks
, MinValue
.Ticks
, MaxValue
.Ticks
);
276 throw new ArgumentOutOfRangeException ("ticks", msg
);
278 kind
= DateTimeKind
.Unspecified
;
281 public DateTime (int year
, int month
, int day
)
282 : this (year
, month
, day
,0,0,0,0) {}
284 public DateTime (int year
, int month
, int day
, int hour
, int minute
, int second
)
285 : this (year
, month
, day
, hour
, minute
, second
, 0) {}
287 public DateTime (int year
, int month
, int day
, int hour
, int minute
, int second
, int millisecond
)
289 if ( year
< 1 || year
> 9999 ||
290 month
< 1 || month
>12 ||
291 day
< 1 || day
> DaysInMonth(year
, month
) ||
292 hour
< 0 || hour
> 23 ||
293 minute
< 0 || minute
> 59 ||
294 second
< 0 || second
> 59 ||
295 millisecond
< 0 || millisecond
> 999)
296 throw new ArgumentOutOfRangeException ("Parameters describe an " +
297 "unrepresentable DateTime.");
299 ticks
= new TimeSpan (AbsoluteDays(year
,month
,day
), hour
, minute
, second
, millisecond
);
301 kind
= DateTimeKind
.Unspecified
;
304 public DateTime (int year
, int month
, int day
, Calendar calendar
)
305 : this (year
, month
, day
, 0, 0, 0, 0, calendar
)
309 public DateTime (int year
, int month
, int day
, int hour
, int minute
, int second
, Calendar calendar
)
310 : this (year
, month
, day
, hour
, minute
, second
, 0, calendar
)
314 public DateTime (int year
, int month
, int day
, int hour
, int minute
, int second
, int millisecond
, Calendar calendar
)
316 if (calendar
== null)
317 throw new ArgumentNullException ("calendar");
318 ticks
= calendar
.ToDateTime (year
, month
, day
, hour
, minute
, second
, millisecond
).ticks
;
319 kind
= DateTimeKind
.Unspecified
;
322 internal DateTime (bool check
, TimeSpan
value)
324 if (check
&& (value.Ticks
< MinValue
.Ticks
|| value.Ticks
> MaxValue
.Ticks
))
325 throw new ArgumentOutOfRangeException ();
329 kind
= DateTimeKind
.Unspecified
;
332 public DateTime (long ticks
, DateTimeKind kind
) : this (ticks
)
334 CheckDateTimeKind (kind
);
338 public DateTime (int year
, int month
, int day
, int hour
, int minute
, int second
, DateTimeKind kind
)
339 : this (year
, month
, day
, hour
, minute
, second
)
341 CheckDateTimeKind (kind
);
345 public DateTime (int year
, int month
, int day
, int hour
, int minute
, int second
, int millisecond
, DateTimeKind kind
)
346 : this (year
, month
, day
, hour
, minute
, second
, millisecond
)
348 CheckDateTimeKind (kind
);
352 public DateTime (int year
, int month
, int day
, int hour
, int minute
, int second
, int millisecond
, Calendar calendar
, DateTimeKind kind
)
353 : this (year
, month
, day
, hour
, minute
, second
, millisecond
, calendar
)
355 CheckDateTimeKind (kind
);
360 // Not visible, but can be invoked during deserialization
362 DateTime (SerializationInfo info
, StreamingContext context
)
364 if (info
.HasKey ("dateData")){
365 long dateData
= info
.GetInt64 ("dateData");
366 kind
= (DateTimeKind
) (dateData
>> 62);
367 ticks
= new TimeSpan (dateData
& 0x3fffffffffffffff);
368 } else if (info
.HasKey ("ticks")){
369 ticks
= new TimeSpan (info
.GetInt64 ("ticks"));
370 kind
= DateTimeKind
.Unspecified
;
372 kind
= DateTimeKind
.Unspecified
;
373 ticks
= new TimeSpan (0);
384 DateTime ret
= new DateTime (Year
, Month
, Day
);
394 return FromTicks(Which
.Month
);
402 return FromTicks(Which
.Day
);
406 public DayOfWeek DayOfWeek
410 return ( (DayOfWeek
) ((ticks
.Days
+1) % 7) );
418 return FromTicks(Which
.DayYear
);
422 public TimeSpan TimeOfDay
426 return new TimeSpan(ticks
.Ticks
% TimeSpan
.TicksPerDay
);
443 return ticks
.Minutes
;
451 return ticks
.Seconds
;
455 public int Millisecond
459 return ticks
.Milliseconds
;
463 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
464 internal static extern long GetTimeMonotonic ();
466 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
467 internal static extern long GetNow ();
470 // To reduce the time consumed by DateTime.Now, we keep
471 // the difference to map the system time into a local
472 // time into `to_local_time_span', we record the timestamp
473 // for this in `last_now'
475 static object to_local_time_span_object
;
476 static long last_now
;
478 public static DateTime Now
482 long now
= GetNow ();
483 DateTime dt
= new DateTime (now
);
485 if ((now
- last_now
) > TimeSpan
.TicksPerMinute
){
486 to_local_time_span_object
= TimeZone
.CurrentTimeZone
.GetLocalTimeDiff (dt
);
491 // This is boxed, so we avoid locking.
492 DateTime ret
= dt
+ (TimeSpan
) to_local_time_span_object
;
493 ret
.kind
= DateTimeKind
.Local
;
506 public static DateTime Today
510 DateTime today
= new DateTime (now
.Year
, now
.Month
, now
.Day
);
511 today
.kind
= now
.kind
;
516 public static DateTime UtcNow
519 return new DateTime (GetNow (), DateTimeKind
.Utc
);
527 return FromTicks(Which
.Year
);
531 public DateTimeKind Kind
{
539 public DateTime
Add (TimeSpan
value)
541 DateTime ret
= AddTicks (value.Ticks
);
546 public DateTime
AddDays (double value)
548 return AddMilliseconds (Math
.Round (value * 86400000));
551 public DateTime
AddTicks (long value)
553 if ((value + ticks
.Ticks
) > MAX_VALUE_TICKS
|| (value + ticks
.Ticks
) < 0) {
554 throw new ArgumentOutOfRangeException();
556 DateTime ret
= new DateTime (value + ticks
.Ticks
);
561 public DateTime
AddHours (double value)
563 return AddMilliseconds (value * 3600000);
566 public DateTime
AddMilliseconds (double value)
568 if ((value * TimeSpan
.TicksPerMillisecond
) > long.MaxValue
||
569 (value * TimeSpan
.TicksPerMillisecond
) < long.MinValue
) {
570 throw new ArgumentOutOfRangeException();
572 long msticks
= (long) Math
.Round (value * TimeSpan
.TicksPerMillisecond
);
574 return AddTicks (msticks
);
577 // required to match MS implementation for OADate (OLE Automation)
578 private DateTime
AddRoundedMilliseconds (double ms
)
580 if ((ms
* TimeSpan
.TicksPerMillisecond
) > long.MaxValue
||
581 (ms
* TimeSpan
.TicksPerMillisecond
) < long.MinValue
) {
582 throw new ArgumentOutOfRangeException ();
584 long msticks
= (long) (ms
+= ms
> 0 ? 0.5 : -0.5) * TimeSpan
.TicksPerMillisecond
;
586 return AddTicks (msticks
);
589 public DateTime
AddMinutes (double value)
591 return AddMilliseconds (value * 60000);
594 public DateTime
AddMonths (int months
)
596 int day
, month
, year
, maxday
;
600 month
= this.Month
+ (months
% 12);
601 year
= this.Year
+ months
/12 ;
613 maxday
= DaysInMonth(year
, month
);
617 temp
= new DateTime (year
, month
, day
);
619 return temp
.Add (this.TimeOfDay
);
622 public DateTime
AddSeconds (double value)
624 return AddMilliseconds (value * 1000);
627 public DateTime
AddYears (int value)
629 return AddMonths (value * 12);
632 public static int Compare (DateTime t1
, DateTime t2
)
634 if (t1
.ticks
< t2
.ticks
)
636 else if (t1
.ticks
> t2
.ticks
)
642 public int CompareTo (object value)
647 if (!(value is System
.DateTime
))
648 throw new ArgumentException (Locale
.GetText (
649 "Value is not a System.DateTime"));
651 return Compare (this, (DateTime
) value);
654 public bool IsDaylightSavingTime ()
656 if (kind
== DateTimeKind
.Utc
)
658 return TimeZone
.CurrentTimeZone
.IsDaylightSavingTime (this);
661 public int CompareTo (DateTime
value)
663 return Compare (this, value);
666 public bool Equals (DateTime
value)
668 return value.ticks
== ticks
;
671 public long ToBinary ()
674 case DateTimeKind
.Utc
:
675 return Ticks
| 0x4000000000000000;
676 case DateTimeKind
.Local
:
677 return (long) ((ulong) ToUniversalTime ().Ticks
| 0x8000000000000000);
683 public static DateTime
FromBinary (long dateData
)
685 switch ((ulong)dateData
>> 62) {
687 return new DateTime (dateData ^
0x4000000000000000, DateTimeKind
.Utc
);
689 return new DateTime (dateData
, DateTimeKind
.Unspecified
);
691 return new DateTime (dateData
& 0x3fffffffffffffff, DateTimeKind
.Utc
).ToLocalTime ();
695 public static DateTime
SpecifyKind (DateTime
value, DateTimeKind kind
)
697 return new DateTime (value.Ticks
, kind
);
700 public static int DaysInMonth (int year
, int month
)
704 if (month
< 1 || month
>12)
705 throw new ArgumentOutOfRangeException ();
707 if (year
< 1 || year
> 9999)
708 throw new ArgumentOutOfRangeException ();
710 days
= (IsLeapYear(year
) ? daysmonthleap
: daysmonth
);
714 public override bool Equals (object value)
716 if (!(value is System
.DateTime
))
719 return ((DateTime
) value).ticks
== ticks
;
722 public static bool Equals (DateTime t1
, DateTime t2
)
724 return (t1
.ticks
== t2
.ticks
);
727 public static DateTime
FromFileTime (long fileTime
)
730 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
732 return new DateTime (w32file_epoch
+ fileTime
).ToLocalTime ();
735 public static DateTime
FromFileTimeUtc (long fileTime
)
738 throw new ArgumentOutOfRangeException ("fileTime", "< 0");
740 return new DateTime (w32file_epoch
+ fileTime
);
743 public static DateTime
FromOADate (double d
)
745 // An OLE Automation date is implemented as a floating-point number
746 // whose value is the number of days from midnight, 30 December 1899.
748 // d must be negative 657435.0 through positive 2958466.0.
749 if ((d
<= OAMinValue
) || (d
>= OAMaxValue
))
750 throw new ArgumentException ("d", "[-657435,2958466]");
752 DateTime dt
= new DateTime (ticks18991230
);
754 Double days
= Math
.Ceiling (d
);
755 // integer part is the number of days (negative)
756 dt
= dt
.AddRoundedMilliseconds (days
* 86400000);
757 // but decimals are the number of hours (in days fractions) and positive
758 Double hours
= (days
- d
);
759 dt
= dt
.AddRoundedMilliseconds (hours
* 86400000);
762 dt
= dt
.AddRoundedMilliseconds (d
* 86400000);
768 public string[] GetDateTimeFormats()
770 return GetDateTimeFormats (CultureInfo
.CurrentCulture
);
773 public string[] GetDateTimeFormats(char format
)
775 if ("dDgGfFmMrRstTuUyY".IndexOf (format
) < 0)
776 throw new FormatException ("Invalid format character.");
777 string[] result
= new string[1];
778 result
[0] = this.ToString(format
.ToString());
782 public string[] GetDateTimeFormats(IFormatProvider provider
)
784 DateTimeFormatInfo info
= (DateTimeFormatInfo
) provider
.GetFormat (typeof(DateTimeFormatInfo
));
785 // return GetDateTimeFormats (info.GetAllDateTimePatterns ());
786 ArrayList al
= new ArrayList ();
787 foreach (char c
in "dDgGfFmMrRstTuUyY")
788 al
.AddRange (GetDateTimeFormats (c
, info
));
789 return al
.ToArray (typeof (string)) as string [];
792 public string[] GetDateTimeFormats(char format
,IFormatProvider provider
)
794 if ("dDgGfFmMrRstTuUyY".IndexOf (format
) < 0)
795 throw new FormatException ("Invalid format character.");
797 // LAMESPEC: There is NO assurance that 'U' ALWAYS
798 // euqals to 'F', but since we have to iterate all
799 // the pattern strings, we cannot just use
800 // ToString("U", provider) here. I believe that the
801 // method's behavior cannot be formalized.
802 bool adjustutc
= false;
811 DateTimeFormatInfo info
= (DateTimeFormatInfo
) provider
.GetFormat (typeof(DateTimeFormatInfo
));
812 return GetDateTimeFormats (adjustutc
, info
.GetAllRawDateTimePatterns (format
), info
);
815 private string [] GetDateTimeFormats (bool adjustutc
, string [] patterns
, DateTimeFormatInfo dfi
)
817 string [] results
= new string [patterns
.Length
];
818 DateTime val
= adjustutc
? ToUniversalTime () : this;
819 for (int i
= 0; i
< results
.Length
; i
++)
820 results
[i
] = DateTimeUtils
.ToString (val
, patterns
[i
], dfi
);
824 private void CheckDateTimeKind (DateTimeKind kind
) {
825 if ((kind
!= DateTimeKind
.Unspecified
) && (kind
!= DateTimeKind
.Utc
) && (kind
!= DateTimeKind
.Local
))
826 throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
829 public override int GetHashCode ()
831 return (int) ticks
.Ticks
;
834 public TypeCode
GetTypeCode ()
836 return TypeCode
.DateTime
;
839 public static bool IsLeapYear (int year
)
841 if (year
< 1 || year
> 9999)
842 throw new ArgumentOutOfRangeException ();
843 return ( (year
% 4 == 0 && year
% 100 != 0) || year
% 400 == 0) ;
846 public static DateTime
Parse (string s
)
848 return Parse (s
, null);
851 public static DateTime
Parse (string s
, IFormatProvider provider
)
853 return Parse (s
, provider
, DateTimeStyles
.AllowWhiteSpaces
);
856 public static DateTime
Parse (string s
, IFormatProvider provider
, DateTimeStyles styles
)
859 throw new ArgumentNullException ("s");
863 Exception exception
= null;
864 if (!CoreParse (s
, provider
, styles
, out res
, out dto
, true, ref exception
))
870 const string formatExceptionMessage
= "String was not recognized as a valid DateTime.";
872 internal static bool CoreParse (string s
, IFormatProvider provider
, DateTimeStyles styles
,
873 out DateTime result
, out DateTimeOffset dto
, bool setExceptionOnError
, ref Exception exception
)
875 dto
= new DateTimeOffset (0, TimeSpan
.Zero
);
876 if (s
== null || s
.Length
== 0) {
877 if (setExceptionOnError
)
878 exception
= new FormatException (formatExceptionMessage
);
883 if (provider
== null)
884 provider
= CultureInfo
.CurrentCulture
;
885 DateTimeFormatInfo dfi
= DateTimeFormatInfo
.GetInstance (provider
);
887 // Try first all the combinations of ParseAllDateFormats & ParseTimeFormats
888 string[] allDateFormats
= YearMonthDayFormats (dfi
, setExceptionOnError
, ref exception
);
889 if (allDateFormats
== null){
894 bool longYear
= false;
895 for (int i
= 0; i
< allDateFormats
.Length
; i
++) {
896 string firstPart
= allDateFormats
[i
];
897 bool incompleteFormat
= false;
898 if (_DoParse (s
, firstPart
, "", false, out result
, out dto
, dfi
, styles
, true, ref incompleteFormat
, ref longYear
))
901 if (!incompleteFormat
)
904 for (int j
= 0; j
< ParseTimeFormats
.Length
; j
++) {
905 if (_DoParse (s
, firstPart
, ParseTimeFormats
[j
], false, out result
, out dto
, dfi
, styles
, true, ref incompleteFormat
, ref longYear
))
913 int dayIndex
= dfi
.MonthDayPattern
.IndexOf('d');
914 int monthIndex
= dfi
.MonthDayPattern
.IndexOf('M');
915 if (dayIndex
== -1 || monthIndex
== -1){
917 if (setExceptionOnError
)
918 exception
= new FormatException (Locale
.GetText("Order of month and date is not defined by {0}", dfi
.MonthDayPattern
));
921 bool is_day_before_month
= dayIndex
< monthIndex
;
922 string[] monthDayFormats
= is_day_before_month
? DayMonthShortFormats
: MonthDayShortFormats
;
923 for (int i
= 0; i
< monthDayFormats
.Length
; i
++) {
924 bool incompleteFormat
= false;
925 if (_DoParse (s
, monthDayFormats
[i
], "", false, out result
, out dto
, dfi
, styles
, true, ref incompleteFormat
, ref longYear
))
929 for (int j
= 0; j
< ParseTimeFormats
.Length
; j
++) {
930 string firstPart
= ParseTimeFormats
[j
];
931 bool incompleteFormat
= false;
932 if (_DoParse (s
, firstPart
, "", false, out result
, out dto
, dfi
, styles
, false, ref incompleteFormat
, ref longYear
))
934 if (!incompleteFormat
)
937 for (int i
= 0; i
< monthDayFormats
.Length
; i
++) {
938 if (_DoParse (s
, firstPart
, monthDayFormats
[i
], false, out result
, out dto
, dfi
, styles
, false, ref incompleteFormat
, ref longYear
))
941 for (int i
= 0; i
< allDateFormats
.Length
; i
++) {
942 string dateFormat
= allDateFormats
[i
];
943 if (dateFormat
[dateFormat
.Length
- 1] == 'T')
944 continue; // T formats must be before the time part
945 if (_DoParse (s
, firstPart
, dateFormat
, false, out result
, out dto
, dfi
, styles
, false, ref incompleteFormat
, ref longYear
))
950 // Try as a last resort all the patterns
951 if (ParseExact (s
, dfi
.GetAllDateTimePatternsInternal (), dfi
, styles
, out result
, false, ref longYear
, setExceptionOnError
, ref exception
))
954 if (!setExceptionOnError
)
957 // .NET 2.x does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
958 exception
= new FormatException (formatExceptionMessage
);
962 public static DateTime
ParseExact (string s
, string format
, IFormatProvider provider
)
964 return ParseExact (s
, format
, provider
, DateTimeStyles
.None
);
967 private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi
, bool setExceptionOnError
, ref Exception exc
)
969 int dayIndex
= dfi
.ShortDatePattern
.IndexOf('d');
970 int monthIndex
= dfi
.ShortDatePattern
.IndexOf('M');
971 int yearIndex
= dfi
.ShortDatePattern
.IndexOf('y');
972 if (dayIndex
== -1 || monthIndex
== -1 || yearIndex
== -1){
973 if (setExceptionOnError
)
974 exc
= new FormatException (Locale
.GetText("Order of year, month and date is not defined by {0}", dfi
.ShortDatePattern
));
978 if (yearIndex
< monthIndex
)
979 if (monthIndex
< dayIndex
)
980 return ParseYearMonthDayFormats
;
981 else if (yearIndex
< dayIndex
)
982 return ParseYearDayMonthFormats
;
984 // The year cannot be between the date and the month
985 if (setExceptionOnError
)
986 exc
= new FormatException (Locale
.GetText("Order of date, year and month defined by {0} is not supported", dfi
.ShortDatePattern
));
989 else if (dayIndex
< monthIndex
)
990 return ParseDayMonthYearFormats
;
991 else if (dayIndex
< yearIndex
)
992 return ParseMonthDayYearFormats
;
994 // The year cannot be between the month and the date
995 if (setExceptionOnError
)
996 exc
= new FormatException (Locale
.GetText("Order of month, year and date defined by {0} is not supported", dfi
.ShortDatePattern
));
1001 private static int _ParseNumber (string s
, int valuePos
,
1005 bool sloppy_parsing
,
1011 leadingzero
= false;
1014 int real_digits
= 0;
1015 for (i
= valuePos
; i
< s
.Length
&& i
< digits
+ valuePos
; i
++) {
1016 if (!Char
.IsDigit (s
[i
]))
1022 digits
= real_digits
;
1024 if (digits
< min_digits
) {
1029 if (s
.Length
- valuePos
< digits
) {
1034 for (i
= valuePos
; i
< digits
+ valuePos
; i
++) {
1036 if (!Char
.IsDigit (c
)) {
1041 number
= number
* 10 + (byte) (c
- '0');
1044 num_parsed
= digits
;
1048 private static int _ParseEnum (string s
, int sPos
, string[] values
, string[] invValues
, bool exact
, out int num_parsed
)
1050 // FIXME: I know this is somehow lame code. Probably
1051 // it should iterate all the enum value and return
1052 // the longest match. However right now I don't see
1053 // anything but "1" and "10" - "12" that might match
1054 // two or more values. (They are only abbrev month
1055 // names, so do reverse order search). See bug #80094.
1056 for (int i
= values
.Length
- 1; i
>= 0; i
--) {
1057 if (!exact
&& invValues
[i
].Length
> values
[i
].Length
) {
1058 if (invValues
[i
].Length
> 0 && _ParseString (s
, sPos
, 0, invValues
[i
], out num_parsed
))
1060 if (values
[i
].Length
> 0 && _ParseString (s
, sPos
, 0, values
[i
], out num_parsed
))
1064 if (values
[i
].Length
> 0 && _ParseString (s
, sPos
, 0, values
[i
], out num_parsed
))
1066 if (!exact
&& invValues
[i
].Length
> 0 && _ParseString (s
, sPos
, 0, invValues
[i
], out num_parsed
))
1075 private static bool _ParseString (string s
, int sPos
, int maxlength
, string value, out int num_parsed
)
1078 maxlength
= value.Length
;
1080 if (sPos
+ maxlength
<= s
.Length
&& String
.Compare (s
, sPos
, value, 0, maxlength
, true, CultureInfo
.InvariantCulture
) == 0) {
1081 num_parsed
= maxlength
;
1089 // Note that in case of Parse (exact == false) we check both for AM/PM
1090 // and the culture spcific AM/PM strings.
1091 private static bool _ParseAmPm(string s
,
1094 DateTimeFormatInfo dfi
,
1103 if (!IsLetter (s
, valuePos
)) {
1104 if (dfi
.AMDesignator
!= "")
1111 DateTimeFormatInfo invInfo
= DateTimeFormatInfo
.InvariantInfo
;
1112 if (!exact
&& _ParseString (s
, valuePos
, num
, invInfo
.PMDesignator
, out num_parsed
) ||
1113 dfi
.PMDesignator
!= "" && _ParseString(s
, valuePos
, num
, dfi
.PMDesignator
, out num_parsed
))
1115 else if (!exact
&& _ParseString (s
, valuePos
, num
, invInfo
.AMDesignator
, out num_parsed
) ||
1116 _ParseString (s
, valuePos
, num
, dfi
.AMDesignator
, out num_parsed
)) {
1117 if (exact
|| num_parsed
!= 0)
1125 // Note that in case of Parse (exact == false) we check both for ':'
1126 // and the culture spcific TimeSperator
1127 private static bool _ParseTimeSeparator (string s
, int sPos
, DateTimeFormatInfo dfi
, bool exact
, out int num_parsed
)
1129 return _ParseString (s
, sPos
, 0, dfi
.TimeSeparator
, out num_parsed
) ||
1130 !exact
&& _ParseString (s
, sPos
, 0, ":", out num_parsed
);
1133 // Accept any character for DateSeparator, except TimeSeparator,
1134 // a digit or a letter.
1135 // Not documented, but seems to be MS behaviour here. See bug 54047.
1136 private static bool _ParseDateSeparator (string s
, int sPos
, DateTimeFormatInfo dfi
, bool exact
, out int num_parsed
)
1139 if (exact
&& s
[sPos
] != '/')
1142 if (_ParseTimeSeparator (s
, sPos
, dfi
, exact
, out num_parsed
) ||
1143 Char
.IsDigit (s
[sPos
]) || Char
.IsLetter (s
[sPos
]))
1150 private static bool IsLetter (string s
, int pos
)
1152 return pos
< s
.Length
&& Char
.IsLetter (s
[pos
]);
1155 // To implement better DateTime.Parse we use two format strings one
1156 // for Date and one for Time. This allows us to define two different
1157 // arrays of formats for Time and Dates and to combine them more or less
1158 // efficiently. When this mode is used flexibleTwoPartsParsing is true.
1159 private static bool _DoParse (string s
,
1163 out DateTime result
,
1164 out DateTimeOffset dto
,
1165 DateTimeFormatInfo dfi
,
1166 DateTimeStyles style
,
1167 bool firstPartIsDate
,
1168 ref bool incompleteFormat
,
1171 bool useutc
= false;
1172 bool use_invariant
= false;
1173 bool sloppy_parsing
= false;
1174 dto
= new DateTimeOffset (0, TimeSpan
.Zero
);
1175 bool flexibleTwoPartsParsing
= !exact
&& secondPart
!= null;
1176 incompleteFormat
= false;
1178 string format
= firstPart
;
1179 bool afterTFormat
= false;
1180 DateTimeFormatInfo invInfo
= DateTimeFormatInfo
.InvariantInfo
;
1181 if (format
.Length
== 1)
1182 format
= DateTimeUtils
.GetStandardPattern (format
[0], dfi
, out useutc
, out use_invariant
);
1184 result
= new DateTime (0);
1191 if ((style
& DateTimeStyles
.AllowLeadingWhite
) != 0) {
1192 format
= format
.TrimStart (null);
1194 s
= s
.TrimStart (null); // it could be optimized, but will make little good.
1197 if ((style
& DateTimeStyles
.AllowTrailingWhite
) != 0) {
1198 format
= format
.TrimEnd (null);
1199 s
= s
.TrimEnd (null); // it could be optimized, but will make little good.
1205 if ((style
& DateTimeStyles
.AllowInnerWhite
) != 0)
1206 sloppy_parsing
= true;
1208 string chars
= format
;
1209 int len
= format
.Length
, pos
= 0, num
= 0;
1213 int day
= -1, dayofweek
= -1, month
= -1, year
= -1;
1214 int hour
= -1, minute
= -1, second
= -1;
1215 double fractionalSeconds
= -1;
1217 int tzsign
= -1, tzoffset
= -1, tzoffmin
= -1;
1218 bool isFirstPart
= true;
1222 if (valuePos
== s
.Length
)
1226 if (flexibleTwoPartsParsing
&& pos
+ num
== 0)
1228 bool isLetter
= IsLetter(s
, valuePos
);
1230 if (s
[valuePos
] == 'Z')
1233 _ParseString (s
, valuePos
, 0, "GMT", out num_parsed
);
1234 if (num_parsed
> 0 && !IsLetter (s
, valuePos
+ num_parsed
)) {
1235 valuePos
+= num_parsed
;
1240 if (!afterTFormat
&& _ParseAmPm (s
, valuePos
, 0, dfi
, exact
, out num_parsed
, ref ampm
)) {
1241 if (IsLetter (s
, valuePos
+ num_parsed
))
1243 else if (num_parsed
> 0) {
1244 valuePos
+= num_parsed
;
1249 if (!afterTFormat
&& dayofweek
== -1 && isLetter
) {
1250 dayofweek
= _ParseEnum (s
, valuePos
, dfi
.RawDayNames
, invInfo
.RawDayNames
, exact
, out num_parsed
);
1251 if (dayofweek
== -1)
1252 dayofweek
= _ParseEnum (s
, valuePos
, dfi
.RawAbbreviatedDayNames
, invInfo
.RawAbbreviatedDayNames
, exact
, out num_parsed
);
1253 if (dayofweek
!= -1 && !IsLetter (s
, valuePos
+ num_parsed
)) {
1254 valuePos
+= num_parsed
;
1261 if (char.IsWhiteSpace (s
[valuePos
]) || s
[valuePos
] == ',') {
1268 if (pos
+ num
>= len
)
1270 if (flexibleTwoPartsParsing
&& num
== 0) {
1271 afterTFormat
= isFirstPart
&& firstPart
[firstPart
.Length
- 1] == 'T';
1272 if (!isFirstPart
&& format
== "")
1277 format
= secondPart
;
1282 isFirstPart
= false;
1288 bool leading_zeros
= true;
1290 if (chars
[pos
] == '\'') {
1292 while (pos
+num
< len
) {
1293 if (chars
[pos
+num
] == '\'')
1296 if (valuePos
== s
.Length
|| s
[valuePos
] != chars
[pos
+ num
])
1306 } else if (chars
[pos
] == '"') {
1308 while (pos
+num
< len
) {
1309 if (chars
[pos
+num
] == '"')
1312 if (valuePos
== s
.Length
|| s
[valuePos
] != chars
[pos
+num
])
1322 } else if (chars
[pos
] == '\\') {
1327 if (s
[valuePos
] != chars
[pos
])
1333 } else if (chars
[pos
] == '%') {
1336 } else if (char.IsWhiteSpace (s
[valuePos
]) ||
1337 s
[valuePos
] == ',' && (!exact
&& chars
[pos
] == '/' || Char
.IsWhiteSpace (chars
[pos
]))) {
1340 if (exact
&& (style
& DateTimeStyles
.AllowInnerWhite
) == 0) {
1341 if (!Char
.IsWhiteSpace (chars
[pos
]))
1348 while (ws
< s
.Length
) {
1349 if (Char
.IsWhiteSpace (s
[ws
]) || s
[ws
] == ',')
1356 while (ws
< chars
.Length
) {
1357 if (Char
.IsWhiteSpace (chars
[ws
]) || chars
[ws
] == ',')
1363 // A whitespace may match a '/' in the pattern.
1364 if (!exact
&& pos
< chars
.Length
&& chars
[pos
] == '/')
1365 if (!_ParseDateSeparator (s
, valuePos
, dfi
, exact
, out num_parsed
))
1370 if ((pos
+num
+1 < len
) && (chars
[pos
+num
+1] == chars
[pos
+num
])) {
1378 if (num
< 2 && day
!= -1 || num
>= 2 && dayofweek
!= -1)
1381 day
= _ParseNumber (s
, valuePos
, 1, 2, false, sloppy_parsing
, out num_parsed
);
1383 day
= _ParseNumber (s
, valuePos
, 1, 2, true, sloppy_parsing
, out num_parsed
);
1385 dayofweek
= _ParseEnum (s
, valuePos
, dfi
.RawAbbreviatedDayNames
, invInfo
.RawAbbreviatedDayNames
, exact
, out num_parsed
);
1387 dayofweek
= _ParseEnum (s
, valuePos
, dfi
.RawDayNames
, invInfo
.RawDayNames
, exact
, out num_parsed
);
1393 if (flexibleTwoPartsParsing
) {
1395 if (num
== 0 || num
== 3)
1396 month
= _ParseNumber (s
, valuePos
, 1, 2, false, sloppy_parsing
, out num_parsed
);
1397 if (num
> 1 && num_parsed
== -1)
1398 month
= _ParseEnum (s
, valuePos
, dfi
.RawMonthNames
, invInfo
.RawMonthNames
, exact
, out num_parsed
) + 1;
1399 if (num
> 1 && num_parsed
== -1)
1400 month
= _ParseEnum (s
, valuePos
, dfi
.RawAbbreviatedMonthNames
, invInfo
.RawAbbreviatedMonthNames
, exact
, out num_parsed
) + 1;
1405 month
= _ParseNumber (s
, valuePos
, 1, 2, false, sloppy_parsing
, out num_parsed
);
1407 month
= _ParseNumber (s
, valuePos
, 1, 2, true, sloppy_parsing
, out num_parsed
);
1409 month
= _ParseEnum (s
, valuePos
, dfi
.RawAbbreviatedMonthNames
, invInfo
.RawAbbreviatedMonthNames
, exact
, out num_parsed
) + 1;
1411 month
= _ParseEnum (s
, valuePos
, dfi
.RawMonthNames
, invInfo
.RawMonthNames
, exact
, out num_parsed
) + 1;
1418 year
= _ParseNumber (s
, valuePos
, 1, 2, false, sloppy_parsing
, out num_parsed
);
1419 } else if (num
< 3) {
1420 year
= _ParseNumber (s
, valuePos
, 1, 2, true, sloppy_parsing
, out num_parsed
);
1422 year
= _ParseNumber (s
, valuePos
, exact
? 4 : 3, 4, false, sloppy_parsing
, out num_parsed
);
1423 if ((year
>= 1000) && (num_parsed
== 4) && (!longYear
) && (s
.Length
> 4 + valuePos
)) {
1425 int ly
= _ParseNumber (s
, valuePos
, 5, 5, false, sloppy_parsing
, out np
);
1426 longYear
= (ly
> 9999);
1431 //FIXME: We should do use dfi.Calendat.TwoDigitYearMax
1432 if (num_parsed
<= 2)
1433 year
+= (year
< 30) ? 2000 : 1900;
1439 hour
= _ParseNumber (s
, valuePos
, 1, 2, false, sloppy_parsing
, out num_parsed
);
1441 hour
= _ParseNumber (s
, valuePos
, 1, 2, true, sloppy_parsing
, out num_parsed
);
1450 if (hour
!= -1 || !flexibleTwoPartsParsing
&& ampm
>= 0)
1453 hour
= _ParseNumber (s
, valuePos
, 1, 2, false, sloppy_parsing
, out num_parsed
);
1455 hour
= _ParseNumber (s
, valuePos
, 1, 2, true, sloppy_parsing
, out num_parsed
);
1466 minute
= _ParseNumber (s
, valuePos
, 1, 2, false, sloppy_parsing
, out num_parsed
);
1468 minute
= _ParseNumber (s
, valuePos
, 1, 2, true, sloppy_parsing
, out num_parsed
);
1478 second
= _ParseNumber (s
, valuePos
, 1, 2, false, sloppy_parsing
, out num_parsed
);
1480 second
= _ParseNumber (s
, valuePos
, 1, 2, true, sloppy_parsing
, out num_parsed
);
1487 leading_zeros
= false;
1490 if (num
> 6 || fractionalSeconds
!= -1)
1492 double decimalNumber
= (double) _ParseNumber (s
, valuePos
, 0, num
+1, leading_zeros
, sloppy_parsing
, out num_parsed
);
1493 if (num_parsed
== -1)
1495 fractionalSeconds
= decimalNumber
/ Math
.Pow(10.0, num_parsed
);
1498 if (!_ParseAmPm (s
, valuePos
, num
> 0 ? 0 : 1, dfi
, exact
, out num_parsed
, ref ampm
))
1505 if (s
[valuePos
] == '+')
1507 else if (s
[valuePos
] == '-')
1514 tzoffset
= _ParseNumber (s
, valuePos
, 1, 2, false, sloppy_parsing
, out num_parsed
);
1516 tzoffset
= _ParseNumber (s
, valuePos
, 1, 2, true, sloppy_parsing
, out num_parsed
);
1518 tzoffset
= _ParseNumber (s
, valuePos
, 1, 2, true, /*sloppy_parsing*/true, out num_parsed
);
1519 valuePos
+= num_parsed
;
1524 if (valuePos
< s
.Length
&& Char
.IsDigit (s
[valuePos
]) ||
1525 _ParseTimeSeparator (s
, valuePos
, dfi
, exact
, out num_parsed
)) {
1526 valuePos
+= num_parsed
;
1527 tzoffmin
= _ParseNumber (s
, valuePos
, 1, 2, true, sloppy_parsing
, out num_parsed
);
1531 else if (!flexibleTwoPartsParsing
)
1538 if (s
[valuePos
] == 'Z') {
1542 else if (s
[valuePos
] == '+' || s
[valuePos
] == '-') {
1545 if (s
[valuePos
] == '+')
1547 else if (s
[valuePos
] == '-')
1552 tzoffset
= _ParseNumber (s
, valuePos
, 0, 2, true, sloppy_parsing
, out num_parsed
);
1553 valuePos
+= num_parsed
;
1557 if (Char
.IsDigit (s
[valuePos
]))
1559 else if (!_ParseString (s
, valuePos
, 0, dfi
.TimeSeparator
, out num_parsed
))
1561 valuePos
+= num_parsed
;
1563 tzoffmin
= _ParseNumber (s
, valuePos
, 0, 2, true, sloppy_parsing
, out num_parsed
);
1570 // LAMESPEC: This should be part of UTCpattern
1571 // string and thus should not be considered here.
1573 // Note that 'Z' is not defined as a pattern
1574 // character. Keep it for X509 certificate
1575 // verification. Also, "Z" != "'Z'" under MS.NET
1576 // ("'Z'" is just literal; handled above)
1578 if (s
[valuePos
] != 'Z')
1585 if (s
[valuePos
] != 'G')
1588 if ((pos
+ 2 < len
) && (valuePos
+ 2 < s
.Length
) &&
1589 (chars
[pos
+ 1] == 'M') && (s
[valuePos
+ 1] == 'M') &&
1590 (chars
[pos
+ 2] == 'T') && (s
[valuePos
+ 2] == 'T'))
1602 if (!_ParseTimeSeparator (s
, valuePos
, dfi
, exact
, out num_parsed
))
1606 if (!_ParseDateSeparator (s
, valuePos
, dfi
, exact
, out num_parsed
))
1612 if (s
[valuePos
] != chars
[pos
])
1623 valuePos
+= num_parsed
;
1625 if (!exact
&& !flexibleTwoPartsParsing
) {
1626 switch (chars
[pos
]) {
1632 if (s
.Length
> valuePos
&& s
[valuePos
] == 'Z' &&
1633 (pos
+ 1 == chars
.Length
|| chars
[pos
+ 1] != 'Z')) {
1641 pos
= pos
+ num
+ 1;
1645 if (pos
+ 1 < len
&& chars
[pos
] == '.' && chars
[pos
+ 1] == 'F') {
1647 while (pos
< len
&& chars
[pos
] == 'F') // '.FFF....' can be mapped to nothing. See bug #444103
1650 while (pos
< len
&& chars
[pos
] == 'K') // 'K' can be mapped to nothing
1656 if (s
.Length
> valuePos
) // extraneous tail.
1661 if (Char
.IsDigit (s
[valuePos
]) && Char
.IsDigit (s
[valuePos
- 1]))
1663 if (Char
.IsLetter (s
[valuePos
]) && Char
.IsLetter (s
[valuePos
- 1]))
1665 incompleteFormat
= true;
1676 if (fractionalSeconds
== -1)
1677 fractionalSeconds
= 0;
1679 // If no date was given
1680 if ((day
== -1) && (month
== -1) && (year
== -1)) {
1681 if ((style
& DateTimeStyles
.NoCurrentDateDefault
) != 0) {
1686 day
= DateTime
.Today
.Day
;
1687 month
= DateTime
.Today
.Month
;
1688 year
= DateTime
.Today
.Year
;
1697 if ((style
& DateTimeStyles
.NoCurrentDateDefault
) != 0)
1700 year
= DateTime
.Today
.Year
;
1703 if (ampm
== 0 && hour
== 12)
1706 if (ampm
== 1 && (!flexibleTwoPartsParsing
|| hour
< 12))
1709 // For anything out of range
1711 if (year
< 1 || year
> 9999 ||
1712 month
< 1 || month
>12 ||
1713 day
< 1 || day
> DateTime
.DaysInMonth(year
, month
) ||
1714 hour
< 0 || hour
> 23 ||
1715 minute
< 0 || minute
> 59 ||
1716 second
< 0 || second
> 59)
1719 result
= new DateTime (year
, month
, day
, hour
, minute
, second
, 0);
1720 result
= result
.AddSeconds(fractionalSeconds
);
1722 if (dayofweek
!= -1 && dayofweek
!= (int) result
.DayOfWeek
)
1726 if (result
!= DateTime
.MinValue
) {
1728 dto
= new DateTimeOffset (result
);
1729 } catch { }
// We handle this error in DateTimeOffset.Parse
1737 tzoffset
= -tzoffset
;
1738 tzoffmin
= -tzoffmin
;
1741 dto
= new DateTimeOffset (result
, new TimeSpan (tzoffset
, tzoffmin
, 0));
1742 } catch {} // We handle this error in DateTimeOffset.Parse
1744 bool adjustToUniversal
= (style
& DateTimeStyles
.AdjustToUniversal
) != 0;
1747 long newticks
= (result
.ticks
- dto
.Offset
).Ticks
;
1749 newticks
+= TimeSpan
.TicksPerDay
;
1750 result
= new DateTime (false, new TimeSpan (newticks
));
1751 result
.kind
= DateTimeKind
.Utc
;
1752 if ((style
& DateTimeStyles
.RoundtripKind
) != 0)
1753 result
= result
.ToLocalTime ();
1755 else if (useutc
|| ((style
& DateTimeStyles
.AssumeUniversal
) != 0))
1756 result
.kind
= DateTimeKind
.Utc
;
1757 else if ((style
& DateTimeStyles
.AssumeLocal
) != 0)
1758 result
.kind
= DateTimeKind
.Local
;
1760 bool adjustToLocal
= !adjustToUniversal
&& (style
& DateTimeStyles
.RoundtripKind
) == 0;
1761 if (result
.kind
!= DateTimeKind
.Unspecified
)
1763 if (adjustToUniversal
)
1764 result
= result
.ToUniversalTime ();
1765 else if (adjustToLocal
)
1766 result
= result
.ToLocalTime ();
1771 public static DateTime
ParseExact (string s
, string format
,
1772 IFormatProvider provider
, DateTimeStyles style
)
1775 throw new ArgumentNullException ("format");
1777 string [] formats
= new string [1];
1778 formats
[0] = format
;
1780 return ParseExact (s
, formats
, provider
, style
);
1783 public static DateTime
ParseExact (string s
, string[] formats
,
1784 IFormatProvider provider
,
1785 DateTimeStyles style
)
1787 DateTimeFormatInfo dfi
= DateTimeFormatInfo
.GetInstance (provider
);
1790 throw new ArgumentNullException ("s");
1791 if (formats
== null)
1792 throw new ArgumentNullException ("formats");
1793 if (formats
.Length
== 0)
1794 throw new FormatException ("Format specifier was invalid.");
1797 bool longYear
= false;
1799 if (!ParseExact (s
, formats
, dfi
, style
, out result
, true, ref longYear
, true, ref e
))
1804 private static void CheckStyle (DateTimeStyles style
)
1806 if ( (style
& DateTimeStyles
.RoundtripKind
) != 0)
1808 if ((style
& DateTimeStyles
.AdjustToUniversal
) != 0 || (style
& DateTimeStyles
.AssumeLocal
) != 0 ||
1809 (style
& DateTimeStyles
.AssumeUniversal
) != 0)
1810 throw new ArgumentException ("The DateTimeStyles value RoundtripKind cannot be used with the values AssumeLocal, Asersal or AdjustToUniversal.", "style");
1812 if ((style
& DateTimeStyles
.AssumeUniversal
) != 0 && (style
& DateTimeStyles
.AssumeLocal
) != 0)
1813 throw new ArgumentException ("The DateTimeStyles values AssumeLocal and AssumeUniversal cannot be used together.", "style");
1816 public static bool TryParse (string s
, out DateTime result
)
1820 Exception exception
= null;
1823 return CoreParse (s
, null, DateTimeStyles
.AllowWhiteSpaces
, out result
, out dto
, false, ref exception
);
1830 public static bool TryParse (string s
, IFormatProvider provider
, DateTimeStyles styles
, out DateTime result
)
1834 Exception exception
= null;
1837 return CoreParse (s
, provider
, styles
, out result
, out dto
, false, ref exception
);
1844 public static bool TryParseExact (string s
, string format
,
1845 IFormatProvider provider
,
1846 DateTimeStyles style
,
1847 out DateTime result
)
1850 formats
= new string [1];
1851 formats
[0] = format
;
1853 return TryParseExact (s
, formats
, provider
, style
, out result
);
1856 public static bool TryParseExact (string s
, string[] formats
,
1857 IFormatProvider provider
,
1858 DateTimeStyles style
,
1859 out DateTime result
)
1862 DateTimeFormatInfo dfi
= DateTimeFormatInfo
.GetInstance (provider
);
1864 bool longYear
= false;
1866 return ParseExact (s
, formats
, dfi
, style
, out result
, true, ref longYear
, false, ref e
);
1873 private static bool ParseExact (string s
, string [] formats
,
1874 DateTimeFormatInfo dfi
, DateTimeStyles style
, out DateTime ret
,
1875 bool exact
, ref bool longYear
,
1876 bool setExceptionOnError
, ref Exception exception
)
1879 bool incompleteFormat
= false;
1880 for (i
= 0; i
< formats
.Length
; i
++)
1883 string format
= formats
[i
];
1884 if (format
== null || format
== String
.Empty
)
1888 if (_DoParse (s
, formats
[i
], null, exact
, out result
, out dto
, dfi
, style
, false, ref incompleteFormat
, ref longYear
)) {
1894 if (setExceptionOnError
)
1895 exception
= new FormatException ("Invalid format string");
1896 ret
= DateTime
.MinValue
;
1900 public TimeSpan
Subtract (DateTime
value)
1902 return new TimeSpan (ticks
.Ticks
) - value.ticks
;
1905 public DateTime
Subtract(TimeSpan
value)
1909 newticks
= (new TimeSpan (ticks
.Ticks
)) - value;
1910 DateTime ret
= new DateTime (true,newticks
);
1915 public long ToFileTime()
1917 DateTime universalTime
= ToUniversalTime();
1919 if (universalTime
.Ticks
< w32file_epoch
) {
1920 throw new ArgumentOutOfRangeException("file time is not valid");
1923 return(universalTime
.Ticks
- w32file_epoch
);
1926 public long ToFileTimeUtc()
1928 if (Ticks
< w32file_epoch
) {
1929 throw new ArgumentOutOfRangeException("file time is not valid");
1932 return (Ticks
- w32file_epoch
);
1935 public string ToLongDateString()
1937 return ToString ("D");
1940 public string ToLongTimeString()
1942 return ToString ("T");
1945 public double ToOADate ()
1947 long t
= this.Ticks
;
1948 // uninitialized DateTime case
1951 // we can't reach minimum value
1952 if (t
< 31242239136000000)
1953 return OAMinValue
+ 0.001;
1955 TimeSpan ts
= new TimeSpan (this.Ticks
- ticks18991230
);
1956 double result
= ts
.TotalDays
;
1957 // t < 0 (where 599264352000000000 == 0.0d for OA)
1958 if (t
< 599264352000000000) {
1959 // negative days (int) but decimals are positive
1960 double d
= Math
.Ceiling (result
);
1961 result
= d
- 2 - (result
- d
);
1964 // we can't reach maximum value
1965 if (result
>= OAMaxValue
)
1966 result
= OAMaxValue
- 0.00000001d
;
1971 public string ToShortDateString()
1973 return ToString ("d");
1976 public string ToShortTimeString()
1978 return ToString ("t");
1981 public override string ToString ()
1983 return ToString ("G", null);
1986 public string ToString (IFormatProvider provider
)
1988 return ToString (null, provider
);
1991 public string ToString (string format
)
1993 return ToString (format
, null);
1996 public string ToString (string format
, IFormatProvider provider
)
1998 DateTimeFormatInfo dfi
= DateTimeFormatInfo
.GetInstance (provider
);
2000 if (format
== null || format
== String
.Empty
)
2003 bool useutc
= false, use_invariant
= false;
2005 if (format
.Length
== 1) {
2006 char fchar
= format
[0];
2007 format
= DateTimeUtils
.GetStandardPattern (fchar
, dfi
, out useutc
, out use_invariant
);
2009 return DateTimeUtils
.ToString (ToUniversalTime (), format
, dfi
);
2010 // return ToUniversalTime()._ToString (format, dfi);
2013 throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
2016 // Don't convert UTC value. It just adds 'Z' for
2017 // 'u' format, for the same ticks.
2018 return DateTimeUtils
.ToString (this, format
, dfi
);
2021 public DateTime
ToLocalTime ()
2023 return TimeZone
.CurrentTimeZone
.ToLocalTime (this);
2026 public DateTime
ToUniversalTime()
2028 return TimeZone
.CurrentTimeZone
.ToUniversalTime (this);
2033 public static DateTime
operator +(DateTime d
, TimeSpan t
)
2035 DateTime ret
= new DateTime (true, d
.ticks
+ t
);
2040 public static bool operator ==(DateTime d1
, DateTime d2
)
2042 return (d1
.ticks
== d2
.ticks
);
2045 public static bool operator >(DateTime t1
,DateTime t2
)
2047 return (t1
.ticks
> t2
.ticks
);
2050 public static bool operator >=(DateTime t1
,DateTime t2
)
2052 return (t1
.ticks
>= t2
.ticks
);
2055 public static bool operator !=(DateTime d1
, DateTime d2
)
2057 return (d1
.ticks
!= d2
.ticks
);
2060 public static bool operator <(DateTime t1
, DateTime t2
)
2062 return (t1
.ticks
< t2
.ticks
);
2065 public static bool operator <=(DateTime t1
,DateTime t2
)
2067 return (t1
.ticks
<= t2
.ticks
);
2070 public static TimeSpan
operator -(DateTime d1
,DateTime d2
)
2072 return new TimeSpan((d1
.ticks
- d2
.ticks
).Ticks
);
2075 public static DateTime
operator -(DateTime d
,TimeSpan t
)
2077 DateTime ret
= new DateTime (true, d
.ticks
- t
);
2082 bool IConvertible
.ToBoolean(IFormatProvider provider
)
2084 throw new InvalidCastException();
2087 byte IConvertible
.ToByte(IFormatProvider provider
)
2089 throw new InvalidCastException();
2093 char IConvertible
.ToChar(IFormatProvider provider
)
2095 throw new InvalidCastException();
2098 System
.DateTime IConvertible
.ToDateTime(IFormatProvider provider
)
2103 decimal IConvertible
.ToDecimal(IFormatProvider provider
)
2105 throw new InvalidCastException();
2108 double IConvertible
.ToDouble(IFormatProvider provider
)
2110 throw new InvalidCastException();
2113 Int16 IConvertible
.ToInt16(IFormatProvider provider
)
2115 throw new InvalidCastException();
2118 Int32 IConvertible
.ToInt32(IFormatProvider provider
)
2120 throw new InvalidCastException();
2123 Int64 IConvertible
.ToInt64(IFormatProvider provider
)
2125 throw new InvalidCastException();
2128 SByte IConvertible
.ToSByte(IFormatProvider provider
)
2130 throw new InvalidCastException();
2133 Single IConvertible
.ToSingle(IFormatProvider provider
)
2135 throw new InvalidCastException();
2138 object IConvertible
.ToType (Type targetType
, IFormatProvider provider
)
2140 if (targetType
== null)
2141 throw new ArgumentNullException ("targetType");
2143 if (targetType
== typeof (DateTime
))
2145 else if (targetType
== typeof (String
))
2146 return this.ToString (provider
);
2147 else if (targetType
== typeof (Object
))
2150 throw new InvalidCastException();
2153 UInt16 IConvertible
.ToUInt16(IFormatProvider provider
)
2155 throw new InvalidCastException();
2158 UInt32 IConvertible
.ToUInt32(IFormatProvider provider
)
2160 throw new InvalidCastException();
2163 UInt64 IConvertible
.ToUInt64(IFormatProvider provider
)
2165 throw new InvalidCastException();
2168 void ISerializable
.GetObjectData (SerializationInfo info
, StreamingContext context
)
2170 long t
= ticks
.Ticks
;
2171 info
.AddValue ("ticks", t
);
2173 // This is the new .NET format, encodes the kind on the top bits
2174 info
.AddValue ("dateData", t
| (((uint)kind
) << 62));