[System.Security.SecuritySafeCritical] // auto-generated internal static bool TryParse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, ref DateTimeResult result) { if (s == null) { result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, "s"); return false; } if (s.Length == 0) { result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null); return false; } Contract.Assert(dtfi != null, "dtfi == null"); #if _LOGGING DTFITrace(dtfi); #endif DateTime time; // // First try the predefined format. // DS dps = DS.BEGIN; // Date Parsing State. bool reachTerminalState = false; DateTimeToken dtok = new DateTimeToken(); // The buffer to store the parsing token. dtok.suffix = TokenType.SEP_Unk; DateTimeRawInfo raw = new DateTimeRawInfo(); // The buffer to store temporary parsing information. unsafe { Int32 * numberPointer = stackalloc Int32[3]; raw.Init(numberPointer); } raw.hasSameDateAndTimeSeparators = dtfi.DateSeparator.Equals(dtfi.TimeSeparator, StringComparison.Ordinal); result.calendar = dtfi.Calendar; result.era = Calendar.CurrentEra; // // The string to be parsed. Use a __DTString wrapper so that we can trace the index which // indicates the begining of next token. // __DTString str = new __DTString(s, dtfi); str.GetNext(); // // The following loop will break out when we reach the end of the str. // do { // // Call the lexer to get the next token. // // If we find a era in Lex(), the era value will be in raw.era. if (!Lex(dps, ref str, ref dtok, ref raw, ref result, ref dtfi, styles)) { TPTraceExit("0000", dps); return false; } // // If the token is not unknown, process it. // Otherwise, just discard it. // if (dtok.dtt != DTT.Unk) { // // Check if we got any CJK Date/Time suffix. // Since the Date/Time suffix tells us the number belongs to year/month/day/hour/minute/second, // store the number in the appropriate field in the result. // if (dtok.suffix != TokenType.SEP_Unk) { if (!ProcessDateTimeSuffix(ref result, ref raw, ref dtok)) { result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null); TPTraceExit("0010", dps); return false; } dtok.suffix = TokenType.SEP_Unk; // Reset suffix to SEP_Unk; } if (dtok.dtt == DTT.NumLocalTimeMark) { if (dps == DS.D_YNd || dps == DS.D_YN) { // Consider this as ISO 8601 format: // "yyyy-MM-dd'T'HH:mm:ss" 1999-10-31T02:00:00 TPTraceExit("0020", dps); return (ParseISO8601(ref raw, ref str, styles, ref result)); } else { result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null); TPTraceExit("0030", dps); return false; } } if (raw.hasSameDateAndTimeSeparators) { if (dtok.dtt == DTT.YearEnd || dtok.dtt == DTT.YearSpace || dtok.dtt == DTT.YearDateSep) { // When time and date separators are same and we are hitting a year number while the first parsed part of the string was recognized // as part of time (and not a date) DS.T_Nt, DS.T_NNt then change the state to be a date so we try to parse it as a date instead if (dps == DS.T_Nt) { dps = DS.D_Nd; } if (dps == DS.T_NNt) { dps = DS.D_NNd; } } bool atEnd = str.AtEnd(); if (dateParsingStates[(int)dps][(int)dtok.dtt] == DS.ERROR || atEnd) { switch (dtok.dtt) { // we have the case of Serbia have dates in forms 'd.M.yyyy.' so we can expect '.' after the date parts. // changing the token to end with space instead of Date Separator will avoid failing the parsing. case DTT.YearDateSep: dtok.dtt = atEnd ? DTT.YearEnd : DTT.YearSpace; break; case DTT.NumDatesep: dtok.dtt = atEnd ? DTT.NumEnd : DTT.NumSpace; break; case DTT.NumTimesep: dtok.dtt = atEnd ? DTT.NumEnd : DTT.NumSpace; break; case DTT.MonthDatesep: dtok.dtt = atEnd ? DTT.MonthEnd : DTT.MonthSpace; break; } } } // // Advance to the next state, and continue // dps = dateParsingStates[(int)dps][(int)dtok.dtt]; if (dps == DS.ERROR) { result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null); TPTraceExit("0040 (invalid state transition)", dps); return false; } else if (dps > DS.ERROR) { if ((dtfi.FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0) { if (!ProcessHebrewTerminalState(dps, ref result, ref styles, ref raw, dtfi)) { TPTraceExit("0050 (ProcessHebrewTerminalState)", dps); return false; } } else { if (!ProcessTerminaltState(dps, ref result, ref styles, ref raw, dtfi)) { TPTraceExit("0060 (ProcessTerminaltState)", dps); return false; } } reachTerminalState = true; // // If we have reached a terminal state, start over from DS.BEGIN again. // For example, when we parsed "1999-12-23 13:30", we will reach a terminal state at "1999-12-23", // and we start over so we can continue to parse "12:30". // dps = DS.BEGIN; } } } while (dtok.dtt != DTT.End && dtok.dtt != DTT.NumEnd && dtok.dtt != DTT.MonthEnd); if (!reachTerminalState) { result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null); TPTraceExit("0070 (did not reach terminal state)", dps); return false; } AdjustTimeMark(dtfi, ref raw); if (!AdjustHour(ref result.Hour, raw.timeMark)) { result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null); TPTraceExit("0080 (AdjustHour)", dps); return false; } // Check if the parased string only contains hour/minute/second values. bool bTimeOnly = (result.Year == -1 && result.Month == -1 && result.Day == -1); // // Check if any year/month/day is missing in the parsing string. // If yes, get the default value from today's date. // if (!CheckDefaultDateTime(ref result, ref result.calendar, styles)) { TPTraceExit("0090 (failed to fill in missing year/month/day defaults)", dps); return false; } if (!result.calendar.TryToDateTime(result.Year, result.Month, result.Day, result.Hour, result.Minute, result.Second, 0, result.era, out time)) { result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, "Format_BadDateTimeCalendar", null); TPTraceExit("0100 (result.calendar.TryToDateTime)", dps); return false; } if (raw.fraction > 0) { time = time.AddTicks((long)Math.Round(raw.fraction * Calendar.TicksPerSecond)); } // // We have to check day of week before we adjust to the time zone. // Otherwise, the value of day of week may change after adjustting to the time zone. // if (raw.dayOfWeek != -1) { // // Check if day of week is correct. // if (raw.dayOfWeek != (int)result.calendar.GetDayOfWeek(time)) { result.SetFailure(ParseFailureKind.Format, "Format_BadDayOfWeek", null); TPTraceExit("0110 (dayOfWeek check)", dps); return false; } } result.parsedDate = time; if (!DetermineTimeZoneAdjustments(ref result, styles, bTimeOnly)) { TPTraceExit("0120 (DetermineTimeZoneAdjustments)", dps); return false; } TPTraceExit("0130 (success)", dps); return true; }