///------------------------------------------------------------------------------ /// Get a time value from SYSTEMTIME structure. /// /// Returns number of milliseconds since Jan 1, 1970 ///------------------------------------------------------------------------------ double DateUtilities::TimeFromSt(SYSTEMTIME *pst) { return TvFromDate(pst->wYear,pst->wMonth-1,pst->wDay-1, DayTimeFromSt(pst)); }
bool DateImplementation::TryParseIsoString(const char16 *const str, const size_t length, double &timeValue, ScriptContext *scriptContext) { Assert(str); size_t i = 0; const Js::CharClassifier *classifier = scriptContext->GetCharClassifier(); // Skip leading whitespace (for cross-browser compatibility) // Also skip bidirectional characters, for Round tripping locale formatted date while ((classifier->IsWhiteSpace(str[i]) || classifier->IsBiDirectionalChar(str[i])) && ++i < length); // Minimum length must be 4 (YYYY) if(length - i < 4) return false; // YYYY|(+|-)YYYYYY int year; switch(str[i]) { case _u('+'): ++i; if(!TryParseDecimalDigits(str, length, i, 6, year)) return false; i += 6; break; case _u('-'): ++i; if(!TryParseDecimalDigits(str, length, i, 6, year) || year == 0) return false; year = -year; i += 6; break; case _u('0'): case _u('1'): case _u('2'): case _u('3'): case _u('4'): case _u('5'): case _u('6'): case _u('7'): case _u('8'): case _u('9'): if(!TryParseDecimalDigits(str, length, i, 4, year)) return false; i += 4; break; default: return false; } // Skip bidirectional characters, for Round tripping locale formatted date i += classifier->SkipBiDirectionalChars(str, i, length); int month = 0, day = 0, timePortionMilliseconds = 0, utcOffsetMilliseconds = 0; bool isLocalTime = false; do // while(false); { do // while(false); { // -MM if(i >= length || str[i] != _u('-')) break; ++i; if(!TryParseTwoDecimalDigits(str, length, i, month)) return false; --month; if(month < 0 || month > 11) return false; i += 2; // Skip bidirectional characters, for Round tripping locale formatted date i += classifier->SkipBiDirectionalChars(str, i, length); // -DD if(i >= length || str[i] != _u('-')) break; ++i; if(!TryParseTwoDecimalDigits(str, length, i, day)) return false; --day; if(day < 0 || day > 30) return false; i += 2; // Skip bidirectional characters, for Round tripping locale formatted date i += classifier->SkipBiDirectionalChars(str, i, length); } while(false); // THH:mm if(i >= length || str[i] != _u('T')) break; ++i; int t; if(!TryParseTwoDecimalDigits(str, length, i, t) || t > 24) return false; timePortionMilliseconds += t * (60 * 60 * 1000); i += 2; // Skip bidirectional characters, for Round tripping locale formatted date i += classifier->SkipBiDirectionalChars(str, i, length); if(i >= length || str[i] != _u(':')) return false; ++i; if(!TryParseTwoDecimalDigits(str, length, i, t) || t > 59) return false; timePortionMilliseconds += t * (60 * 1000); i += 2; // Skip bidirectional characters, for Round tripping locale formatted date i += classifier->SkipBiDirectionalChars(str, i, length); do // while(false); { // :ss if(i >= length || str[i] != _u(':')) break; ++i; if(!TryParseTwoDecimalDigits(str, length, i, t) || t > 59) return false; timePortionMilliseconds += t * 1000; i += 2; // Skip bidirectional characters, for Round tripping locale formatted date i += classifier->SkipBiDirectionalChars(str, i, length); // .sss if(i >= length || str[i] != _u('.')) break; ++i; // Require one or more decimal digits. Ignore digits beyond the third size_t foundDigits = 0; if(!TryParseMilliseconds(str, length, i, t, foundDigits)) return false; timePortionMilliseconds += t; i += foundDigits; // Skip bidirectional characters, for Round tripping locale formatted date i += classifier->SkipBiDirectionalChars(str, i, length); } while(false); // Z|(+|-)HH:mm if(i >= length) { isLocalTime = true; break; } const char16 utcOffsetSign = str[i]; if(utcOffsetSign == _u('Z')) { ++i; break; } if(utcOffsetSign != _u('+') && utcOffsetSign != _u('-')) { isLocalTime = true; break; } ++i; // In -version:6 we allow optional colons in the timezone offset if (!TryParseTwoDecimalDigits(str, length, i, t, scriptContext->GetConfig()->IsES6DateParseFixEnabled() /* Timezone may be 4 sequential digits */) || t > 24) return false; utcOffsetMilliseconds += t * (60 * 60 * 1000); i += 2; // Skip bidirectional characters, for Round tripping locale formatted date i += classifier->SkipBiDirectionalChars(str, i, length); if(i >= length) return false; // The ':' is optional in ISO 8601 if (str[i] == _u(':')) { ++i; } if(!TryParseTwoDecimalDigits(str, length, i, t) || t > 59) return false; utcOffsetMilliseconds += t * (60 * 1000); i += 2; // Skip bidirectional characters, for Round tripping locale formatted date i += classifier->SkipBiDirectionalChars(str, i, length); if(utcOffsetSign == _u('-')) utcOffsetMilliseconds = -utcOffsetMilliseconds; } while(false); // Skip trailing whitespace (for cross-browser compatibility) // Skip bidirectional characters, for Round tripping locale formatted date while (i < length && (classifier->IsWhiteSpace(str[i]) || classifier->IsBiDirectionalChar(str[i]))) ++i; // There should only have been whitespace remaining, if any if(i < length) return false; Assert(i == length); // Compute the time value timeValue = TvFromDate(year, month, day, timePortionMilliseconds - utcOffsetMilliseconds); if (isLocalTime) { // Compatibility note: // In ES5, it was unspecified how to handle date strings without the trailing time zone offset "Z|(+|-)HH:mm". // In ES5.1, an absent time zone offset defaulted to "Z", which contradicted ISO8601:2004(E). // This was corrected in an ES5.1 errata note. Moreover, the ES6 draft now follows ISO8601. timeValue = GetTvUtc(timeValue, scriptContext); } return true; }