Imported Upstream version 3.10.0

Former-commit-id: 172c8e3c300b39d5785c7a3e8dfb08ebdbc1a99b
This commit is contained in:
Jo Shields
2014-10-04 11:27:48 +01:00
parent fe777c5c82
commit 8b9b85e7f5
970 changed files with 20242 additions and 31308 deletions

View File

@@ -343,372 +343,21 @@ namespace System
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");
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 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;
result = DateTimeOffset.MinValue;
bool useutc = false, use_invariants = false;
if (format.Length == 1) {
format = DateTimeUtils.GetStandardPattern (format[0], dfi, out useutc, out use_invariants, true);
if (format == null)
return false;
}
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;
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 = dfi.Calendar.ToFourDigitYear (year);
} 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;
// The documentation is incorrect, they claim that K is the same as 'zz', but
// it actually allows the format to contain 4 digits for the offset
case 'K':
tokLen = 1;
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, 4, false, false, out off_h);
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 'z':
tokLen = DateTimeUtils.CountRepeat (format, fi, ch);
if (offset != TimeSpan.MinValue || tokLen > 3)
return false;
off_m = 0;
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;
case '\'':
case '"':
tokLen = 1;
while (ii < input.Length) {
var ftoken = format [fi + tokLen];
++tokLen;
if (ftoken == format [fi]) {
if (useutc && tokLen == 5 && input [ii - 3] == 'G' && input [ii - 2] == 'M' && input [ii - 1] == 'T') {
offset = TimeSpan.Zero;
}
break;
}
if (ftoken != input [ii++])
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) {
if ((styles & DateTimeStyles.AssumeUniversal) != 0) {
offset = TimeSpan.Zero;
} else if ((styles & DateTimeStyles.AssumeLocal) != 0) {
offset = use_invariants ?
TimeSpan.Zero :
TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.Now);
}
}
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 ++;
}
return char_parsed;
}
public TimeSpan Subtract (DateTimeOffset value)
{
return UtcDateTime - value.UtcDateTime;