//
// System.DateTime.cs
//
-// author:
+// Authors:
// Marcel Narings (marcel@narings.nl)
// Martin Baulig (martin@gnome.org)
// Atsushi Enomoto (atsushi@ximian.com)
+// Marek Safar (marek.safar@gmail.com)
//
// (C) 2001 Marcel Narings
// Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System.Collections;
+using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
+using System.Runtime.Serialization;
namespace System
{
///
[Serializable]
[StructLayout (LayoutKind.Auto)]
- public struct DateTime : IFormattable, IConvertible, IComparable
-#if NET_2_0
- , IComparable<DateTime>, IEquatable <DateTime>
-#endif
+ public struct DateTime : IFormattable, IConvertible, IComparable, ISerializable, IComparable<DateTime>, IEquatable <DateTime>
{
- private TimeSpan ticks;
-
-#if NET_2_0
- DateTimeKind kind;
-#endif
-#if !NET_2_0
- internal struct DateTimeOffset {
- public DateTime DateTime;
- public TimeSpan Offset;
-
- public DateTimeOffset (DateTime dt) : this (dt, TimeSpan.Zero)
- {
- }
-
- public DateTimeOffset (long ticks, TimeSpan offset) : this (new DateTime (ticks), offset)
- {
- }
-
- public DateTimeOffset (DateTime dt, TimeSpan offset)
- {
- DateTime = dt;
- Offset = offset;
- }
- }
-#endif
+ //
+ // Encodes the DateTime in 64 bits, top two bits contain the DateTimeKind,
+ // the rest contains the 62 bit value for the ticks. This reduces the
+ // memory usage from 16 to 8 bytes, see bug: 592221. This also fixes the
+ // 622127 issue and simplifies the code in reflection.c to encode DateTimes
+ //
+ long encoded;
+ const long TicksMask = 0x3fffffffffffffff;
+ const long KindMask = unchecked ((long) 0xc000000000000000);
+ const int KindShift = 62;
private const int dp400 = 146097;
private const int dp100 = 36524;
private const double OAMinValue = -657435.0d;
private const double OAMaxValue = 2958466.0d;
- public static readonly DateTime MaxValue = new DateTime (false, new TimeSpan (MAX_VALUE_TICKS));
- public static readonly DateTime MinValue = new DateTime (false, new TimeSpan (0));
+ public static readonly DateTime MaxValue = new DateTime (3155378975999999999);
+ public static readonly DateTime MinValue = new DateTime (0);
// DateTime.Parse patterns
// Patterns are divided to date and time patterns. The algorithm will
// try combinations of these patterns. The algorithm also looks for
// day of the week, AM/PM GMT and Z independently of the patterns.
private static readonly string[] ParseTimeFormats = new string [] {
+ "H:m:s.fff zzz",
"H:m:s.fffffffzzz",
"H:m:s.fffffff",
+ "H:m:s.ffffff",
+ "H:m:s.ffffffzzz",
+ "H:m:s.fffff",
+ "H:m:s.ffff",
+ "H:m:s.fff",
+ "H:m:s.ff",
+ "H:m:s.f",
"H:m:s tt zzz",
"H:m:szzz",
"H:m:s",
"M/yyyy/dT",
"yyyy'\u5E74'M'\u6708'd'\u65E5",
-#if NET_2_0
+
"yyyy/d/MMMM",
"yyyy/MMM/d",
-#else
- "yyyy/MMMM/d",
- "yyyy/d/MMM",
-#endif
"d/MMMM/yyyy",
"MMM/d/yyyy",
"d/yyyy/MMMM",
"d/yy/MMM",
"yy/d/MMM",
};
+
+ private static readonly string[] ParseGenericYearMonthDayFormats = new string [] {
+ "yyyy/M/dT",
+ "yyyy/M/d",
+ "M/yyyy/dT",
+ "M/yyyy/d",
+ "yyyy'\u5E74'M'\u6708'd'\u65E5",
+ "yyyy'-'M'-'dT",
+ "yyyy'-'M'-'d",
+ };
// Patterns influenced by the MonthDayPattern in DateTimeFormatInfo.
// Note that these patterns cannot be followed by the time.
};
private static readonly string[] DayMonthShortFormats = new string [] {
"d/MMMM",
-#if NET_2_0
"MMM/yy",
-#else // In .Net 1.0 Feb 03 is always Feb 3rd (and not Feb 2003)
- "MMM/d",
-#endif
"yyyy/MMMM",
};
int M =1;
int[] days = daysmonth;
- int totaldays = this.ticks.Days;
+ int totaldays = (int) ((encoded & TicksMask) / TimeSpan.TicksPerDay);
num400 = (totaldays / dp400);
totaldays -= num400 * dp400;
return totaldays +1;
}
+ static void InvalidTickValue (long ticks)
+ {
+ string msg = Locale.GetText ("Value {0} is outside the valid range [0,{1}].", ticks, MAX_VALUE_TICKS);
+ throw new ArgumentOutOfRangeException ("ticks", msg);
+ }
// Constructors
///
public DateTime (long ticks)
{
- this.ticks = new TimeSpan (ticks);
- if (ticks < MinValue.Ticks || ticks > MaxValue.Ticks) {
- string msg = Locale.GetText ("Value {0} is outside the valid range [{1},{2}].",
- ticks, MinValue.Ticks, MaxValue.Ticks);
- throw new ArgumentOutOfRangeException ("ticks", msg);
- }
-#if NET_2_0
- kind = DateTimeKind.Unspecified;
-#endif
+ if (ticks < 0 || ticks > MAX_VALUE_TICKS)
+ InvalidTickValue (ticks);
+ encoded = ticks;
}
public DateTime (int year, int month, int day)
: this (year, month, day, hour, minute, second, 0) {}
public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
- {
- if ( year < 1 || year > 9999 ||
- month < 1 || month >12 ||
- day < 1 || day > DaysInMonth(year, month) ||
- hour < 0 || hour > 23 ||
- minute < 0 || minute > 59 ||
- second < 0 || second > 59 ||
- millisecond < 0 || millisecond > 999)
+ {
+ if (year < 1 || year > 9999 ||
+ month < 1 || month >12 ||
+ day < 1 || day > DaysInMonth(year, month) ||
+ hour < 0 || hour > 23 ||
+ minute < 0 || minute > 59 ||
+ second < 0 || second > 59 ||
+ millisecond < 0 || millisecond > 999)
throw new ArgumentOutOfRangeException ("Parameters describe an " +
- "unrepresentable DateTime.");
-
- ticks = new TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
+ "unrepresentable DateTime.");
-#if NET_2_0
- kind = DateTimeKind.Unspecified;
-#endif
+ encoded = new TimeSpan (AbsoluteDays (year,month,day), hour, minute, second, millisecond).Ticks;
}
public DateTime (int year, int month, int day, Calendar calendar)
{
if (calendar == null)
throw new ArgumentNullException ("calendar");
- ticks = calendar.ToDateTime (year, month, day, hour, minute, second, millisecond).ticks;
-#if NET_2_0
- kind = DateTimeKind.Unspecified;
-#endif
+ encoded = calendar.ToDateTime (year, month, day, hour, minute, second, millisecond).encoded;
}
- internal DateTime (bool check, TimeSpan value)
+ public DateTime (long ticks, DateTimeKind kind)
{
- if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
- throw new ArgumentOutOfRangeException ();
-
- ticks = value;
-
-#if NET_2_0
- kind = DateTimeKind.Unspecified;
-#endif
- }
+ if (ticks < 0 || ticks > MAX_VALUE_TICKS)
+ InvalidTickValue (ticks);
+ if (kind < 0 || kind > DateTimeKind.Local)
+ throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
-#if NET_2_0
- public DateTime (long ticks, DateTimeKind kind) : this (ticks)
- {
- CheckDateTimeKind (kind);
- this.kind = kind;
+ encoded = ((long)kind << KindShift) | ticks;
}
public DateTime (int year, int month, int day, int hour, int minute, int second, DateTimeKind kind)
: this (year, month, day, hour, minute, second)
{
- CheckDateTimeKind (kind);
- this.kind = kind;
+ if (kind < 0 || kind > DateTimeKind.Local)
+ throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
+ encoded |= ((long)kind << KindShift);
}
public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind)
: this (year, month, day, hour, minute, second, millisecond)
{
- CheckDateTimeKind (kind);
- this.kind = kind;
+ if (kind < 0 || kind > DateTimeKind.Local)
+ throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
+ encoded |= ((long)kind << KindShift);
}
public DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind)
: this (year, month, day, hour, minute, second, millisecond, calendar)
{
- CheckDateTimeKind (kind);
- this.kind = kind;
- }
-#endif
+ if (kind < 0 || kind > DateTimeKind.Local)
+ throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
+ encoded |= ((long)kind << KindShift);
+ }
+ //
+ // Not visible, but can be invoked during deserialization
+ //
+ DateTime (SerializationInfo info, StreamingContext context)
+ {
+ if (info.HasKey ("dateData")){
+ encoded = (Int64)info.GetUInt64 ("dateData");
+ } else if (info.HasKey ("ticks")){
+ encoded = info.GetInt64 ("ticks") & TicksMask;
+ } else {
+ encoded = 0;
+ }
+ }
+
+
/* Properties */
- public DateTime Date
- {
- get
- {
+ public DateTime Date {
+ get {
DateTime ret = new DateTime (Year, Month, Day);
-#if NET_2_0
- ret.kind = kind;
-#endif
+ ret.encoded |= encoded & KindMask;
return ret;
}
}
- public int Month
- {
- get
- {
- return FromTicks(Which.Month);
+ public int Month {
+ get {
+ return FromTicks (Which.Month);
}
}
- public int Day
- {
- get
- {
- return FromTicks(Which.Day);
+ public int Day {
+ get {
+ return FromTicks (Which.Day);
}
}
- public DayOfWeek DayOfWeek
- {
- get
- {
- return ( (DayOfWeek) ((ticks.Days+1) % 7) );
+ public DayOfWeek DayOfWeek {
+ get {
+ return (DayOfWeek) ((((encoded & TicksMask)/TimeSpan.TicksPerDay)+1) % 7);
}
}
- public int DayOfYear
- {
- get
- {
- return FromTicks(Which.DayYear);
+ public int DayOfYear {
+ get {
+ return FromTicks (Which.DayYear);
}
}
- public TimeSpan TimeOfDay
- {
- get
- {
- return new TimeSpan(ticks.Ticks % TimeSpan.TicksPerDay );
+ public TimeSpan TimeOfDay {
+ get {
+ return new TimeSpan ((encoded & TicksMask) % TimeSpan.TicksPerDay);
}
}
- public int Hour
- {
- get
- {
- return ticks.Hours;
+ public int Hour {
+ get {
+ return (int) ((encoded & TicksMask) % TimeSpan.TicksPerDay / TimeSpan.TicksPerHour);
}
}
- public int Minute
- {
- get
- {
- return ticks.Minutes;
+ public int Minute {
+ get {
+ return (int) ((encoded & TicksMask) % TimeSpan.TicksPerHour / TimeSpan.TicksPerMinute);
}
}
- public int Second
- {
- get
- {
- return ticks.Seconds;
+ public int Second {
+ get {
+ return (int) ((encoded & TicksMask) % TimeSpan.TicksPerMinute / TimeSpan.TicksPerSecond);
}
}
- public int Millisecond
- {
- get
- {
- return ticks.Milliseconds;
+ public int Millisecond {
+ get {
+ return (int) ((encoded & TicksMask) % TimeSpan.TicksPerSecond / TimeSpan.TicksPerMillisecond);
}
}
static object to_local_time_span_object;
static long last_now;
- public static DateTime Now
- {
- get
- {
+ public static DateTime Now {
+ get {
long now = GetNow ();
DateTime dt = new DateTime (now);
- if ((now - last_now) > TimeSpan.TicksPerMinute){
+ if (Math.Abs (now - last_now) > TimeSpan.TicksPerMinute){
to_local_time_span_object = TimeZone.CurrentTimeZone.GetLocalTimeDiff (dt);
last_now = now;
// This is boxed, so we avoid locking.
DateTime ret = dt + (TimeSpan) to_local_time_span_object;
-#if NET_2_0
- ret.kind = DateTimeKind.Local;
-#endif
+ ret.encoded |= ((long)DateTimeKind.Local << KindShift);
return ret;
}
}
- public long Ticks
- {
- get
- {
- return ticks.Ticks;
+ public long Ticks {
+ get {
+ return encoded & TicksMask;
}
}
- public static DateTime Today
- {
+ public static DateTime Today {
get {
DateTime now = Now;
DateTime today = new DateTime (now.Year, now.Month, now.Day);
-#if NET_2_0
- today.kind = now.kind;
-#endif
+ today.encoded |= ((long)DateTimeKind.Local << KindShift);
return today;
}
}
- public static DateTime UtcNow
- {
+ public static DateTime UtcNow {
get {
-#if NET_2_0
return new DateTime (GetNow (), DateTimeKind.Utc);
-#else
- return new DateTime (GetNow ());
-#endif
}
}
- public int Year
- {
- get
- {
- return FromTicks(Which.Year);
+ public int Year {
+ get {
+ return FromTicks (Which.Year);
}
}
-#if NET_2_0
public DateTimeKind Kind {
get {
- return kind;
+ return (DateTimeKind) ((ulong)encoded >> KindShift);
}
}
-#endif
/* methods */
public DateTime Add (TimeSpan value)
{
DateTime ret = AddTicks (value.Ticks);
-#if NET_2_0
- ret.kind = kind;
-#endif
return ret;
}
public DateTime AddTicks (long value)
{
- if ((value + ticks.Ticks) > MAX_VALUE_TICKS || (value + ticks.Ticks) < 0) {
+ long res = value + (encoded & TicksMask);
+ if (res < 0 || res > MAX_VALUE_TICKS)
throw new ArgumentOutOfRangeException();
- }
- DateTime ret = new DateTime (value + ticks.Ticks);
-#if NET_2_0
- ret.kind = kind;
-#endif
+
+ DateTime ret = new DateTime (res);
+ ret.encoded |= (encoded & KindMask);
return ret;
}
public DateTime AddMilliseconds (double value)
{
if ((value * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
- (value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
+ (value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
throw new ArgumentOutOfRangeException();
}
- long msticks = (long) (value * TimeSpan.TicksPerMillisecond);
+ long msticks = (long) Math.Round (value * TimeSpan.TicksPerMillisecond);
return AddTicks (msticks);
}
day = maxday;
temp = new DateTime (year, month, day);
-#if NET_2_0
- temp.kind = kind;
-#endif
+ temp.encoded |= encoded & KindMask;
return temp.Add (this.TimeOfDay);
}
public static int Compare (DateTime t1, DateTime t2)
{
- if (t1.ticks < t2.ticks)
+ long t1t = t1.encoded & TicksMask;
+ long t2t = t2.encoded & TicksMask;
+
+ if (t1t < t2t)
return -1;
- else if (t1.ticks > t2.ticks)
+ else if (t1t > t2t)
return 1;
else
return 0;
return Compare (this, (DateTime) value);
}
-#if NET_2_0
public bool IsDaylightSavingTime ()
{
- if (kind == DateTimeKind.Utc)
+ if ((int)((ulong)encoded >> KindShift) == (int) DateTimeKind.Utc)
return false;
return TimeZone.CurrentTimeZone.IsDaylightSavingTime (this);
}
public bool Equals (DateTime value)
{
- return value.ticks == ticks;
+ return (value.encoded & TicksMask) == (encoded & TicksMask);
}
public long ToBinary ()
{
- switch (kind) {
- case DateTimeKind.Utc:
- return Ticks | 0x4000000000000000;
- case DateTimeKind.Local:
+ if ((encoded & ((long)DateTimeKind.Local << KindShift)) != 0)
return (long) ((ulong) ToUniversalTime ().Ticks | 0x8000000000000000);
- default:
- return Ticks;
- }
+
+ return encoded;
}
public static DateTime FromBinary (long dateData)
{
- switch ((ulong)dateData >> 62) {
- case 1:
- return new DateTime (dateData ^ 0x4000000000000000, DateTimeKind.Utc);
- case 0:
+ switch ((ulong)dateData >> KindShift) {
+ case 1: // Utc
+ return new DateTime (dateData & TicksMask, DateTimeKind.Utc);
+ case 0: // Unspecified
return new DateTime (dateData, DateTimeKind.Unspecified);
- default:
- return new DateTime (dateData & 0x3fffffffffffffff, DateTimeKind.Utc).ToLocalTime ();
+ default: // Local
+ return new DateTime (dateData & TicksMask, DateTimeKind.Utc).ToLocalTime ();
}
}
return new DateTime (value.Ticks, kind);
}
-#else
-
- internal long ToBinary ()
- {
- return Ticks;
- }
-
- internal static DateTime FromBinary (long dateData)
- {
- return new DateTime (dateData & 0x3fffffffffffffff);
- }
-#endif
-
public static int DaysInMonth (int year, int month)
{
int[] days ;
if (!(value is System.DateTime))
return false;
- return ((DateTime) value).ticks == ticks;
+ return (((DateTime) value).encoded & TicksMask) == (encoded & TicksMask);
}
public static bool Equals (DateTime t1, DateTime t2 )
{
- return (t1.ticks == t2.ticks );
+ return (t1.encoded & TicksMask) == (t2.encoded & TicksMask);
}
public static DateTime FromFileTime (long fileTime)
return new DateTime (w32file_epoch + fileTime).ToLocalTime ();
}
-#if NET_1_1
public static DateTime FromFileTimeUtc (long fileTime)
{
if (fileTime < 0)
throw new ArgumentOutOfRangeException ("fileTime", "< 0");
- return new DateTime (w32file_epoch + fileTime);
+ return new DateTime (w32file_epoch + fileTime, DateTimeKind.Utc);
}
-#endif
public static DateTime FromOADate (double d)
{
{
DateTimeFormatInfo info = (DateTimeFormatInfo) provider.GetFormat (typeof(DateTimeFormatInfo));
// return GetDateTimeFormats (info.GetAllDateTimePatterns ());
- ArrayList al = new ArrayList ();
+ var l = new List<string> ();
foreach (char c in "dDgGfFmMrRstTuUyY")
- al.AddRange (GetDateTimeFormats (c, info));
- return al.ToArray (typeof (string)) as string [];
+ l.AddRange (GetDateTimeFormats (c, info));
+ return l.ToArray ();
}
public string[] GetDateTimeFormats(char format,IFormatProvider provider )
return results;
}
-#if NET_2_0
- private void CheckDateTimeKind (DateTimeKind kind) {
- if ((kind != DateTimeKind.Unspecified) && (kind != DateTimeKind.Utc) && (kind != DateTimeKind.Local))
- throw new ArgumentException ("Invalid DateTimeKind value.", "kind");
- }
-#endif
-
public override int GetHashCode ()
{
- return (int) ticks.Ticks;
+ return (int) encoded;
}
public TypeCode GetTypeCode ()
internal static bool CoreParse (string s, IFormatProvider provider, DateTimeStyles styles,
out DateTime result, out DateTimeOffset dto, bool setExceptionOnError, ref Exception exception)
{
- dto = new DateTimeOffset (9, TimeSpan.Zero);
+ dto = new DateTimeOffset (0, TimeSpan.Zero);
if (s == null || s.Length == 0) {
if (setExceptionOnError)
exception = new FormatException (formatExceptionMessage);
DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
// Try first all the combinations of ParseAllDateFormats & ParseTimeFormats
- string[] allDateFormats = YearMonthDayFormats (dfi, setExceptionOnError, ref exception);
+ string[] allDateFormats = YearMonthDayFormats (dfi);
if (allDateFormats == null){
result = MinValue;
return false;
if (!setExceptionOnError)
return false;
-#if NET_2_0
// .NET 2.x does not throw an ArgumentOutOfRangeException, but .NET 1.1 does.
exception = new FormatException (formatExceptionMessage);
-#else
- if (longYear)
- exception = new ArgumentOutOfRangeException ("year", "Valid values are between 1 and 9999, inclusive.");
- else
- exception = new FormatException (formatExceptionMessage);
-#endif
return false;
}
return ParseExact (s, format, provider, DateTimeStyles.None);
}
- private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi, bool setExceptionOnError, ref Exception exc)
+ private static string[] YearMonthDayFormats (DateTimeFormatInfo dfi)
{
int dayIndex = dfi.ShortDatePattern.IndexOf('d');
int monthIndex = dfi.ShortDatePattern.IndexOf('M');
int yearIndex = dfi.ShortDatePattern.IndexOf('y');
- if (dayIndex == -1 || monthIndex == -1 || yearIndex == -1){
- if (setExceptionOnError)
- exc = new FormatException (Locale.GetText("Order of year, month and date is not defined by {0}", dfi.ShortDatePattern));
- return null;
- }
+ if (dayIndex == -1 || monthIndex == -1 || yearIndex == -1)
+ return ParseGenericYearMonthDayFormats;
if (yearIndex < monthIndex)
if (monthIndex < dayIndex)
return ParseYearDayMonthFormats;
else {
// The year cannot be between the date and the month
- if (setExceptionOnError)
- exc = new FormatException (Locale.GetText("Order of date, year and month defined by {0} is not supported", dfi.ShortDatePattern));
- return null;
+ return ParseGenericYearMonthDayFormats;
}
else if (dayIndex < monthIndex)
return ParseDayMonthYearFormats;
return ParseMonthDayYearFormats;
else {
// The year cannot be between the month and the date
- if (setExceptionOnError)
- exc = new FormatException (Locale.GetText("Order of month, year and date defined by {0} is not supported", dfi.ShortDatePattern));
- return null;
+ return ParseGenericYearMonthDayFormats;
}
}
if (maxlength <= 0)
maxlength = value.Length;
- if (sPos + maxlength <= s.Length && String.Compare (s, sPos, value, 0, maxlength, true, CultureInfo.InvariantCulture) == 0) {
+ if (sPos + maxlength <= s.Length && String.CompareOrdinalCaseInsensitive (s, sPos, value, 0, maxlength) == 0) {
num_parsed = maxlength;
return true;
}
bool use_invariant = false;
bool sloppy_parsing = false;
dto = new DateTimeOffset (0, TimeSpan.Zero);
-#if !NET_2_0
- bool afterTimePart = firstPartIsDate && secondPart == "";
-#endif
bool flexibleTwoPartsParsing = !exact && secondPart != null;
incompleteFormat = false;
int valuePos = 0;
if (format == null)
return false;
+ if (s == null)
+ return false;
+
if ((style & DateTimeStyles.AllowLeadingWhite) != 0) {
format = format.TrimStart (null);
int ampm = -1;
int tzsign = -1, tzoffset = -1, tzoffmin = -1;
bool isFirstPart = true;
+ bool format_with_24_hours = false;
for (; ; )
{
if (flexibleTwoPartsParsing && pos + num == 0)
{
bool isLetter = IsLetter(s, valuePos);
-#if NET_2_0
if (isLetter) {
-#else
- if (afterTimePart && isLetter) {
-#endif
if (s [valuePos] == 'Z')
num_parsed = 1;
else
chars = format;
len = chars.Length;
isFirstPart = false;
-#if !NET_2_0
- if (!firstPartIsDate || format == "")
- afterTimePart = true;
-#endif
continue;
}
break;
if (hour >= 24)
return false;
-// ampm = -2;
+ format_with_24_hours = true;
break;
case 'm':
if (minute != -1)
return false;
break;
-#if NET_2_0
case 'F':
leading_zeros = false;
goto case 'f';
-#endif
case 'f':
if (num > 6 || fractionalSeconds != -1)
return false;
num_parsed = 0;
}
break;
-#if NET_2_0
case 'K':
if (s [valuePos] == 'Z') {
valuePos++;
return false;
}
break;
-#endif
+
// LAMESPEC: This should be part of UTCpattern
// string and thus should not be considered here.
//
num = 0;
break;
+ case '.':
+ if (s[valuePos] == '.') {
+ num = 0;
+ num_parsed = 1;
+ break;
+ }
+
+ // '.FFF....' can be mapped to nothing
+ if (pos + 1 < len && chars[pos + 1] == 'F') {
+ ++pos;
+ while (pos < len && chars[pos + 1] == 'F') {
+ ++pos;
+ }
+
+ num = 0;
+ num_parsed = 0;
+ break;
+ }
+
+ return false;
+
default:
if (s [valuePos] != chars [pos])
return false;
switch (chars [pos]) {
case 'm':
case 's':
-#if NET_2_0
case 'F':
-#endif
case 'f':
case 'z':
if (s.Length > valuePos && s [valuePos] == 'Z' &&
num = 0;
}
-#if NET_2_0
if (pos + 1 < len && chars [pos] == '.' && chars [pos + 1] == 'F') {
pos++;
while (pos < len && chars [pos] == 'F') // '.FFF....' can be mapped to nothing. See bug #444103
}
while (pos < len && chars [pos] == 'K') // 'K' can be mapped to nothing
pos++;
-#endif
+
if (pos < len)
return false;
else
year = DateTime.Today.Year;
}
-
- if (ampm == 0 && hour == 12)
- hour = 0;
-
- if (ampm == 1 && (!flexibleTwoPartsParsing || hour < 12))
- hour = hour + 12;
+
+ if (ampm == 0) { // AM designator
+ if (hour >= 12 && format_with_24_hours && exact)
+ return false;
+
+ if (hour == 12)
+ hour = 0;
+ } else if (ampm == 1) { // PM designator
+ if (hour < 12) {
+ if (format_with_24_hours && exact)
+ return false;
+
+ hour += 12;
+ }
+ }
// For anything out of range
// return false
return false;
if (tzsign == -1) {
- if (result != DateTime.MinValue)
- dto = new DateTimeOffset (result);
+ if (result != DateTime.MinValue) {
+ try {
+ dto = new DateTimeOffset (result);
+ } catch { } // We handle this error in DateTimeOffset.Parse
+ }
} else {
if (tzoffmin == -1)
tzoffmin = 0;
tzoffset = -tzoffset;
tzoffmin = -tzoffmin;
}
- dto = new DateTimeOffset (result, new TimeSpan (tzoffset, tzoffmin, 0));
+ try {
+ dto = new DateTimeOffset (result, new TimeSpan (tzoffset, tzoffmin, 0));
+ } catch {} // We handle this error in DateTimeOffset.Parse
}
bool adjustToUniversal = (style & DateTimeStyles.AdjustToUniversal) != 0;
if (tzsign != -1) {
- long newticks = (result.ticks - dto.Offset).Ticks;
+ long newticks = (result - dto.Offset).Ticks;
if (newticks < 0)
newticks += TimeSpan.TicksPerDay;
- result = new DateTime (false, new TimeSpan (newticks));
-#if NET_2_0
- result.kind = DateTimeKind.Utc;
+ result = new DateTime (newticks, DateTimeKind.Utc);
if ((style & DateTimeStyles.RoundtripKind) != 0)
result = result.ToLocalTime ();
-#endif
- }
-#if NET_2_0
- else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
- result.kind = DateTimeKind.Utc;
+ } else if (useutc || ((style & DateTimeStyles.AssumeUniversal) != 0))
+ result.encoded |= ((long) DateTimeKind.Utc << KindShift);
else if ((style & DateTimeStyles.AssumeLocal) != 0)
- result.kind = DateTimeKind.Local;
+ result.encoded |= ((long) DateTimeKind.Local << KindShift);
bool adjustToLocal = !adjustToUniversal && (style & DateTimeStyles.RoundtripKind) == 0;
- if (result.kind != DateTimeKind.Unspecified)
- {
+ if ((DateTimeKind)(((ulong) result.encoded >> KindShift)) != DateTimeKind.Unspecified) {
if (adjustToUniversal)
result = result.ToUniversalTime ();
else if (adjustToLocal)
result = result.ToLocalTime ();
}
-#else
- if (!adjustToUniversal && (useutc || tzsign != -1))
- result = result.ToLocalTime ();
-#endif
return true;
}
+
public static DateTime ParseExact (string s, string format,
IFormatProvider provider, DateTimeStyles style)
DateTimeStyles style)
{
DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
-#if NET_2_0
CheckStyle (style);
-#endif
if (s == null)
throw new ArgumentNullException ("s");
if (formats == null)
return result;
}
-#if NET_2_0
private static void CheckStyle (DateTimeStyles style)
{
if ( (style & DateTimeStyles.RoundtripKind) != 0)
DateTimeStyles style,
out DateTime result)
{
- DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
+ try {
+ DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (provider);
- bool longYear = false;
- Exception e = null;
- return ParseExact (s, formats, dfi, style, out result, true, ref longYear, false, ref e);
+ bool longYear = false;
+ Exception e = null;
+ return ParseExact (s, formats, dfi, style, out result, true, ref longYear, false, ref e);
+ } catch {
+ result = MinValue;
+ return false;
+ }
}
-#endif
private static bool ParseExact (string s, string [] formats,
DateTimeFormatInfo dfi, DateTimeStyles style, out DateTime ret,
public TimeSpan Subtract (DateTime value)
{
- return new TimeSpan (ticks.Ticks) - value.ticks;
+ return new TimeSpan (Ticks) - new TimeSpan (value.Ticks);
}
public DateTime Subtract(TimeSpan value)
{
- TimeSpan newticks;
+ long newticks;
- newticks = (new TimeSpan (ticks.Ticks)) - value;
- DateTime ret = new DateTime (true,newticks);
-#if NET_2_0
- ret.kind = kind;
-#endif
+ newticks = Ticks - value.Ticks;
+ if (newticks < 0 || newticks > MAX_VALUE_TICKS)
+ throw new ArgumentOutOfRangeException ();
+ DateTime ret = new DateTime (newticks);
+ ret.encoded |= (encoded & KindMask);
return ret;
}
return(universalTime.Ticks - w32file_epoch);
}
-#if NET_1_1
public long ToFileTimeUtc()
{
+ if (Kind == DateTimeKind.Local)
+ return ToFileTime ();
+
if (Ticks < w32file_epoch) {
throw new ArgumentOutOfRangeException("file time is not valid");
}
return (Ticks - w32file_epoch);
}
-#endif
public string ToLongDateString()
{
if (format == null || format == String.Empty)
format = "G";
- bool useutc = false, use_invariant = false;
-
if (format.Length == 1) {
char fchar = format [0];
+ bool use_invariant, useutc;
format = DateTimeUtils.GetStandardPattern (fchar, dfi, out useutc, out use_invariant);
if (fchar == 'U')
return DateTimeUtils.ToString (ToUniversalTime (), format, dfi);
if (format == null)
throw new FormatException ("format is not one of the format specifier characters defined for DateTimeFormatInfo");
+
+ if (use_invariant)
+ dfi = DateTimeFormatInfo.InvariantInfo;
}
// Don't convert UTC value. It just adds 'Z' for
public static DateTime operator +(DateTime d, TimeSpan t)
{
- DateTime ret = new DateTime (true, d.ticks + t);
-#if NET_2_0
- ret.kind = d.kind;
-#endif
- return ret;
+ try {
+ long res = checked ((d.encoded & TicksMask) + t.Ticks);
+ if (res < 0 || res > MAX_VALUE_TICKS){
+ throw new ArgumentOutOfRangeException ();
+ }
+
+ return new DateTime (res, d.Kind);
+ } catch (OverflowException){
+ throw new ArgumentOutOfRangeException ();
+ }
}
public static bool operator ==(DateTime d1, DateTime d2)
{
- return (d1.ticks == d2.ticks);
+ return ((d1.encoded & TicksMask) == (d2.encoded & TicksMask));
}
public static bool operator >(DateTime t1,DateTime t2)
{
- return (t1.ticks > t2.ticks);
+ return ((t1.encoded & TicksMask) > (t2.encoded & TicksMask));
}
public static bool operator >=(DateTime t1,DateTime t2)
{
- return (t1.ticks >= t2.ticks);
+ return ((t1.encoded & TicksMask) >= (t2.encoded & TicksMask));
}
public static bool operator !=(DateTime d1, DateTime d2)
{
- return (d1.ticks != d2.ticks);
+ return ((d1.encoded & TicksMask) != (d2.encoded & TicksMask));
}
- public static bool operator <(DateTime t1, DateTime t2)
+ public static bool operator <(DateTime t1, DateTime t2)
{
- return (t1.ticks < t2.ticks );
+ return ((t1.encoded & TicksMask) < (t2.encoded & TicksMask));
}
- public static bool operator <=(DateTime t1,DateTime t2)
+ public static bool operator <=(DateTime t1, DateTime t2)
{
- return (t1.ticks <= t2.ticks);
+ return ((t1.encoded & TicksMask) <= (t2.encoded & TicksMask));
}
- public static TimeSpan operator -(DateTime d1,DateTime d2)
+ public static TimeSpan operator -(DateTime d1, DateTime d2)
{
- return new TimeSpan((d1.ticks - d2.ticks).Ticks);
+ return new TimeSpan ((d1.encoded & TicksMask) - (d2.encoded & TicksMask));
}
- public static DateTime operator -(DateTime d,TimeSpan t)
+ public static DateTime operator -(DateTime d, TimeSpan t)
{
- DateTime ret = new DateTime (true, d.ticks - t);
-#if NET_2_0
- ret.kind = d.kind;
-#endif
- return ret;
+ try {
+ long res = checked ((d.encoded & TicksMask) - t.Ticks);
+ if (res < 0 || res > MAX_VALUE_TICKS)
+ throw new ArgumentOutOfRangeException ();
+ return new DateTime (res, d.Kind);
+ } catch (OverflowException){
+ throw new ArgumentOutOfRangeException ();
+ }
}
- bool IConvertible.ToBoolean(IFormatProvider provider)
+ bool IConvertible.ToBoolean (IFormatProvider provider)
{
throw new InvalidCastException();
}
- byte IConvertible.ToByte(IFormatProvider provider)
+ byte IConvertible.ToByte (IFormatProvider provider)
{
throw new InvalidCastException();
}
- char IConvertible.ToChar(IFormatProvider provider)
+ char IConvertible.ToChar (IFormatProvider provider)
{
throw new InvalidCastException();
}
- System.DateTime IConvertible.ToDateTime(IFormatProvider provider)
+ System.DateTime IConvertible.ToDateTime (IFormatProvider provider)
{
return this;
}
- decimal IConvertible.ToDecimal(IFormatProvider provider)
+ decimal IConvertible.ToDecimal (IFormatProvider provider)
{
throw new InvalidCastException();
}
- double IConvertible.ToDouble(IFormatProvider provider)
+ double IConvertible.ToDouble (IFormatProvider provider)
{
throw new InvalidCastException();
}
- Int16 IConvertible.ToInt16(IFormatProvider provider)
+ Int16 IConvertible.ToInt16 (IFormatProvider provider)
{
throw new InvalidCastException();
}
- Int32 IConvertible.ToInt32(IFormatProvider provider)
+ Int32 IConvertible.ToInt32 (IFormatProvider provider)
{
throw new InvalidCastException();
}
- Int64 IConvertible.ToInt64(IFormatProvider provider)
+ Int64 IConvertible.ToInt64 (IFormatProvider provider)
{
throw new InvalidCastException();
}
-#if ONLY_1_1
-#pragma warning disable 3019
- [CLSCompliant (false)]
-#endif
- SByte IConvertible.ToSByte(IFormatProvider provider)
+ SByte IConvertible.ToSByte (IFormatProvider provider)
{
throw new InvalidCastException();
}
-#if ONLY_1_1
-#pragma warning restore 3019
-#endif
- Single IConvertible.ToSingle(IFormatProvider provider)
+ Single IConvertible.ToSingle (IFormatProvider provider)
{
throw new InvalidCastException();
}
- object IConvertible.ToType (Type type, IFormatProvider provider)
+ object IConvertible.ToType (Type targetType, IFormatProvider provider)
{
- if (type == null)
- throw new ArgumentNullException ("type");
+ if (targetType == null)
+ throw new ArgumentNullException ("targetType");
- if (type == typeof (DateTime))
+ if (targetType == typeof (DateTime))
return this;
- else if (type == typeof (String))
+ else if (targetType == typeof (String))
return this.ToString (provider);
- else if (type == typeof (Object))
+ else if (targetType == typeof (Object))
return this;
else
throw new InvalidCastException();
}
-#if ONLY_1_1
-#pragma warning disable 3019
- [CLSCompliant (false)]
-#endif
- UInt16 IConvertible.ToUInt16(IFormatProvider provider)
+ UInt16 IConvertible.ToUInt16 (IFormatProvider provider)
{
throw new InvalidCastException();
}
-#if ONLY_1_1
-#pragma warning restore 3019
-#endif
-#if ONLY_1_1
-#pragma warning disable 3019
- [CLSCompliant (false)]
-#endif
- UInt32 IConvertible.ToUInt32(IFormatProvider provider)
+ UInt32 IConvertible.ToUInt32 (IFormatProvider provider)
{
throw new InvalidCastException();
}
-#if ONLY_1_1
-#pragma warning restore 3019
-#endif
-#if ONLY_1_1
-#pragma warning disable 3019
- [CLSCompliant (false)]
-#endif
- UInt64 IConvertible.ToUInt64(IFormatProvider provider)
+ UInt64 IConvertible.ToUInt64 (IFormatProvider provider)
{
throw new InvalidCastException();
}
-#if ONLY_1_1
-#pragma warning restore 3019
+
+ void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
+ {
+ long t = Ticks;
+ info.AddValue ("ticks", t);
+
+ // This is the new .NET format, encodes the kind on the top bits
+ info.AddValue ("dateData", (UInt64)encoded);
+ }
+
+#if MONOTOUCH
+ static DateTime () {
+ if (MonoTouchAOTHelper.FalseFlag) {
+ var comparer = new System.Collections.Generic.GenericComparer <DateTime> ();
+ var eqcomparer = new System.Collections.Generic.GenericEqualityComparer <DateTime> ();
+ }
+ }
#endif
}
}