* Marek Safar (marek.safar@gmail.com)
*
* Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+ * Copyright 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
return new DateTimeOffset (dt.AddHours (hours).Ticks, utc_offset);
}
- public static DateTimeOffset operator + (DateTimeOffset dateTimeTz, TimeSpan timeSpan)
+ public static DateTimeOffset operator + (DateTimeOffset dateTimeOffset, TimeSpan timeSpan)
{
- return dateTimeTz.Add (timeSpan);
+ return dateTimeOffset.Add (timeSpan);
}
public DateTimeOffset AddMilliseconds (double milliseconds)
DateTime d;
DateTimeOffset dto;
Exception exception = null;
- if (!DateTime.CoreParse (input, formatProvider, styles, out d, out dto, true, ref exception))
- throw exception;
+ try {
+ if (!DateTime.CoreParse (input, formatProvider, styles, out d, out dto, true, ref exception))
+ throw exception;
+ } catch (ArgumentOutOfRangeException ex) {
+ throw new FormatException ("The UTC representation falls outside the 1-9999 year range", ex);
+ }
if (d.Ticks != 0 && dto.Ticks == 0)
- throw new ArgumentOutOfRangeException ("The UTC representation falls outside the 1-9999 year range");
+ throw new FormatException ("The UTC representation falls outside the 1-9999 year range");
return dto;
}
if ((styles & DateTimeStyles.AssumeLocal) != 0 && (styles & DateTimeStyles.AssumeUniversal) != 0)
throw new ArgumentException ("styles parameter contains incompatible flags");
+ DateTimeFormatInfo dfi = DateTimeFormatInfo.GetInstance (formatProvider);
+ DateTime d;
DateTimeOffset result;
- if (!ParseExact (input, formats, DateTimeFormatInfo.GetInstance (formatProvider), styles, out result))
- throw new FormatException ("Invalid format string");
-
- return result;
- }
-
- private static bool ParseExact (string input, string [] formats,
- DateTimeFormatInfo dfi, DateTimeStyles styles, out DateTimeOffset ret)
- {
- foreach (string format in formats)
- {
- if (format == null || format == String.Empty)
- throw new FormatException ("Invalid format string");
-
- DateTimeOffset result;
- if (DoParse (input, format, false, out result, dfi, styles)) {
- ret = result;
- return true;
- }
- }
- ret = DateTimeOffset.MinValue;
- return false;
- }
-
- private static bool DoParse (string input,
- string format,
- bool exact,
- out DateTimeOffset result,
- DateTimeFormatInfo dfi,
- DateTimeStyles styles)
- {
- if ((styles & DateTimeStyles.AllowLeadingWhite) != 0) {
- format = format.TrimStart (null);
- input = input.TrimStart (null);
- }
-
- if ((styles & DateTimeStyles.AllowTrailingWhite) != 0) {
- format = format.TrimEnd (null);
- input = input.TrimEnd (null);
- }
-
- bool allow_white_spaces = false;
- if ((styles & DateTimeStyles.AllowInnerWhite) != 0)
- allow_white_spaces = true;
-
- bool useutc = false, use_invariants = false;
- if (format.Length == 1)
- format = DateTimeUtils.GetStandardPattern (format[0], dfi, out useutc, out use_invariants, true);
-
- int year = -1;
- int month = -1;
- int day = -1;
- int partial_hour = -1; // for 'hh tt' formats
- int hour = -1;
- int minute = -1;
- int second = -1;
- double fraction = -1;
- int temp_int = -1;
- TimeSpan offset = TimeSpan.MinValue;
-
- result = DateTimeOffset.MinValue;
-
- int fi = 0; //format iterator
- int ii = 0; //input iterator
- while (fi < format.Length) {
- int tokLen;
- char ch = format [fi];
-
- switch (ch) {
- case 'd':
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- if (day != -1 || tokLen > 4)
- return false;
-
- if (tokLen <= 2)
- ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out day);
- else
- ii += ParseEnum (input, ii, tokLen == 3 ? dfi.AbbreviatedDayNames : dfi.DayNames, allow_white_spaces, out temp_int);
- break;
- case 'f':
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- ii += ParseNumber (input, ii, tokLen, true, allow_white_spaces, out temp_int);
- if (fraction >= 0 || tokLen > 7 || temp_int == -1)
- return false;
- fraction = (double)temp_int / Math.Pow (10, tokLen);
- break;
- case 'F':
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- int digits;
- int read = ParseNumber (input, ii, tokLen, true, allow_white_spaces, out temp_int, out digits);
- if (temp_int == -1)
- ii += ParseNumber (input, ii, digits, true, allow_white_spaces, out temp_int);
- else
- ii += read;
- if (fraction >= 0 || tokLen > 7 || temp_int == -1)
- return false;
- fraction = (double)temp_int / Math.Pow (10, digits);
- break;
- case 'h':
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- if (hour != -1 || tokLen > 2)
- return false;
-
- ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out temp_int);
- if (temp_int == -1)
- return false;
-
- if (partial_hour == -1)
- partial_hour = temp_int;
- else
- hour = partial_hour + temp_int;
- break;
- case 'H':
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- if (hour != -1 || tokLen > 2)
- return false;
-
- ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out hour);
- break;
- case 'm':
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- if (minute != -1 || tokLen > 2)
- return false;
-
- ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out minute);
- break;
- case 'M':
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- if (month != -1 || tokLen > 4)
- return false;
-
- if (tokLen <= 2)
- ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out month);
- else {
- ii += ParseEnum (input, ii, tokLen == 3 ? dfi.AbbreviatedMonthNames : dfi.MonthNames, allow_white_spaces, out month);
- month += 1;
- }
-
- break;
- case 's':
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- if (second != -1 || tokLen > 2)
- return false;
- ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out second);
- break;
- case 't':
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- if (hour != -1 || tokLen > 2)
- return false;
-
- ii += ParseEnum (input, ii,
- tokLen == 1 ? new string[] {new string (dfi.AMDesignator[0], 1), new string (dfi.PMDesignator[0], 0)}
- : new string[] {dfi.AMDesignator, dfi.PMDesignator},
- allow_white_spaces, out temp_int);
- if (temp_int == -1)
- return false;
-
- if (partial_hour == -1)
- partial_hour = temp_int * 12;
- else
- hour = partial_hour + temp_int * 12;
- break;
- case 'y':
- if (year != -1)
- return false;
-
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- if (tokLen <= 2) {
- ii += ParseNumber (input, ii, 2, tokLen == 2, allow_white_spaces, out year);
- if (year != -1)
- year += DateTime.Now.Year - DateTime.Now.Year % 100;
- } else if (tokLen <= 4) { // yyy and yyyy accept up to 5 digits with leading 0
- int digit_parsed;
- ii += ParseNumber (input, ii, 5, false, allow_white_spaces, out year, out digit_parsed);
- if (digit_parsed < tokLen || (digit_parsed > tokLen && (year / Math.Pow (10, digit_parsed - 1) < 1)))
- return false;
- } else
- ii += ParseNumber (input, ii, tokLen, true, allow_white_spaces, out year);
- break;
- case 'z':
- tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
- if (offset != TimeSpan.MinValue || tokLen > 3)
- return false;
-
- int off_h, off_m = 0, sign;
- temp_int = 0;
- ii += ParseEnum (input, ii, new string [] {"-", "+"}, allow_white_spaces, out sign);
- ii += ParseNumber (input, ii, 2, tokLen != 1, false, out off_h);
- if (tokLen == 3) {
- ii += ParseEnum (input, ii, new string [] {dfi.TimeSeparator}, false, out temp_int);
- ii += ParseNumber (input, ii, 2, true, false, out off_m);
- }
- if (off_h == -1 || off_m == -1 || sign == -1)
- return false;
-
- if (sign == 0)
- sign = -1;
- offset = new TimeSpan (sign * off_h, sign * off_m, 0);
- break;
- case ':':
- tokLen = 1;
- ii += ParseEnum (input, ii, new string [] {dfi.TimeSeparator}, false, out temp_int);
- if (temp_int == -1)
- return false;
- break;
- case '/':
- tokLen = 1;
- ii += ParseEnum (input, ii, new string [] {dfi.DateSeparator}, false, out temp_int);
- if (temp_int == -1)
- return false;
- break;
- case '%':
- tokLen = 1;
- if (fi != 0)
- return false;
- break;
- case ' ':
- tokLen = 1;
- ii += ParseChar (input, ii, ' ', false, out temp_int);
- if (temp_int == -1)
- return false;
- break;
- case '\\':
- tokLen = 2;
- ii += ParseChar (input, ii, format [fi + 1], allow_white_spaces, out temp_int);
- if (temp_int == -1)
- return false;
- break;
- default:
- //Console.WriteLine ("un-parsed character: {0}", ch);
- tokLen = 1;
- ii += ParseChar (input, ii, format [fi], allow_white_spaces, out temp_int);
- if (temp_int == -1)
- return false;
- break;
- }
- fi += tokLen;
- }
-
- //Console.WriteLine ("{0}-{1}-{2} {3}:{4} {5}", year, month, day, hour, minute, offset);
- if (offset == TimeSpan.MinValue && (styles & DateTimeStyles.AssumeLocal) != 0)
- offset = TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.Now);
-
- if (offset == TimeSpan.MinValue && (styles & DateTimeStyles.AssumeUniversal) != 0)
- offset = TimeSpan.Zero;
-
- if (hour < 0) hour = 0;
- if (minute < 0) minute = 0;
- if (second < 0) second = 0;
- if (fraction < 0) fraction = 0;
- if (year > 0 && month > 0 && day > 0) {
- result = new DateTimeOffset (year, month, day, hour, minute, second, 0, offset);
- result = result.AddSeconds (fraction);
- if ((styles & DateTimeStyles.AdjustToUniversal) != 0)
- result = result.ToUniversalTime ();
- return true;
- }
-
- return false;
- }
-
- private static int ParseNumber (string input, int pos, int digits, bool leading_zero, bool allow_leading_white, out int result)
- {
- int digit_parsed;
- return ParseNumber (input, pos, digits, leading_zero, allow_leading_white, out result, out digit_parsed);
- }
-
- private static int ParseNumber (string input, int pos, int digits, bool leading_zero, bool allow_leading_white, out int result, out int digit_parsed)
- {
- int char_parsed = 0;
- digit_parsed = 0;
- result = 0;
- for (; allow_leading_white && pos < input.Length && input[pos] == ' '; pos++)
- char_parsed++;
-
- for (; pos < input.Length && Char.IsDigit (input[pos]) && digits > 0; pos ++, char_parsed++, digit_parsed++, digits --)
- result = 10 * result + (byte) (input[pos] - '0');
-
- if (leading_zero && digits > 0)
- result = -1;
-
- if (digit_parsed == 0)
- result = -1;
-
- return char_parsed;
- }
-
- private static int ParseEnum (string input, int pos, string [] enums, bool allow_leading_white, out int result)
- {
- int char_parsed = 0;
- result = -1;
- for (; allow_leading_white && pos < input.Length && input[pos] == ' '; pos++)
- char_parsed ++;
-
- for (int i = 0; i < enums.Length; i++)
- if (input.Substring(pos).StartsWith (enums [i])) {
- result = i;
- break;
- }
-
- if (result >= 0)
- char_parsed += enums[result].Length;
-
- return char_parsed;
- }
-
- private static int ParseChar (string input, int pos, char c, bool allow_leading_white, out int result)
- {
- int char_parsed = 0;
- result = -1;
- for (; allow_leading_white && pos < input.Length && input[pos] == ' '; pos++, char_parsed++)
- ;
-
- if (pos < input.Length && input[pos] == c){
- result = (int) c;
- char_parsed ++;
+ Exception exception = null;
+ bool longYear = false;
+ try {
+ if (!DateTime.CoreParseExact (input, formats, dfi, styles, out d, out result, true, ref longYear, true, ref exception, true))
+ throw exception;
+ } catch (ArgumentOutOfRangeException ex) {
+ throw new FormatException ("The UTC representation falls outside the 1-9999 year range", ex);
}
- return char_parsed;
+ return result;
}
public TimeSpan Subtract (DateTimeOffset value)
return left.Subtract (right);
}
- public static DateTimeOffset operator - (DateTimeOffset dateTimeTz, TimeSpan timeSpan)
+ public static DateTimeOffset operator - (DateTimeOffset dateTimeOffset, TimeSpan timeSpan)
{
- return dateTimeTz.Subtract (timeSpan);
+ return dateTimeOffset.Subtract (timeSpan);
}
public long ToFileTime ()