in Release/src/utilities/asyncrt_utils.cpp [1012:1388]
datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& dateString, date_format format)
{
datetime result = datetime::maximum();
int64_t secondsSince1601;
uint64_t fracSec = 0;
auto str = dateString.c_str();
if (format == RFC_1123)
{
int parsedWeekday = 0;
for (; parsedWeekday < 7; ++parsedWeekday)
{
if (string_starts_with(str, dayNames + parsedWeekday * 4) && str[3] == _XPLATSTR(',') &&
str[4] == _XPLATSTR(' '))
{
str += 5; // parsed day of week
break;
}
}
int monthDay;
if (ascii_isdigit3(str[0]) && ascii_isdigit(str[1]) && str[2] == _XPLATSTR(' '))
{
monthDay = atoi2(str); // validity checked later
str += 3; // parsed day
}
else if (ascii_isdigit(str[0]) && str[1] == _XPLATSTR(' '))
{
monthDay = str[0] - _XPLATSTR('0');
str += 2; // parsed day
}
else
{
return result;
}
if (monthDay == 0)
{
return result;
}
int month = 0;
for (;;)
{
if (string_starts_with(str, monthNames + month * 4))
{
break;
}
++month;
if (month == 12)
{
return result;
}
}
if (str[3] != _XPLATSTR(' '))
{
return result;
}
str += 4; // parsed month
if (!ascii_isdigit(str[0]) || !ascii_isdigit(str[1]) || !ascii_isdigit(str[2]) || !ascii_isdigit(str[3]) ||
str[4] != ' ')
{
return result;
}
int year = (str[0] - _XPLATSTR('0')) * 1000 + (str[1] - _XPLATSTR('0')) * 100 + (str[2] - _XPLATSTR('0')) * 10 +
(str[3] - _XPLATSTR('0'));
if (year < 1601)
{
return result;
}
year -= 1601;
// days in month validity check
if (!validate_day_month_1601(monthDay, month, year))
{
return result;
}
str += 5; // parsed year
const int yearDay = get_year_day_1601(month, monthDay, year);
if (!ascii_isdigit2(str[0]) || !ascii_isdigit(str[1]) || str[2] != _XPLATSTR(':') || !ascii_isdigit5(str[3]) ||
!ascii_isdigit(str[4]))
{
return result;
}
const int hour = atoi2(str);
if (hour > 23)
{
return result;
}
str += 3; // parsed hour
const int minute = atoi2(str);
str += 2; // parsed mins
int sec;
if (str[0] == ':')
{
if (!ascii_isdigit6(str[1]) || !ascii_isdigit(str[2]) || str[3] != _XPLATSTR(' '))
{
return result;
}
sec = atoi2(str + 1);
str += 4; // parsed seconds
}
else if (str[0] == _XPLATSTR(' '))
{
sec = 0;
str += 1; // parsed seconds
}
else
{
return result;
}
if (sec > 60)
{ // 60 to allow leap seconds
return result;
}
int daysSince1601 = year * DaysInYear + count_leap_years_1601(year) + yearDay;
if (parsedWeekday != 7)
{
const int actualWeekday = (daysSince1601 + 1) % 7;
if (parsedWeekday != actualWeekday)
{
return result;
}
}
secondsSince1601 =
static_cast<int64_t>(daysSince1601) * SecondsInDay + hour * SecondsInHour + minute * SecondsInMinute + sec;
if (!string_starts_with(str, "GMT") && !string_starts_with(str, "UT"))
{
// some timezone adjustment necessary
auto tzCh = _XPLATSTR('-');
int tzHours;
int tzMinutes = 0;
if (string_starts_with(str, "EDT"))
{
tzHours = 4;
}
else if (string_starts_with(str, "EST") || string_starts_with(str, "CDT"))
{
tzHours = 5;
}
else if (string_starts_with(str, "CST") || string_starts_with(str, "MDT"))
{
tzHours = 6;
}
else if (string_starts_with(str, "MST") || string_starts_with(str, "PDT"))
{
tzHours = 7;
}
else if (string_starts_with(str, "PST"))
{
tzHours = 8;
}
else if ((str[0] == _XPLATSTR('+') || str[0] == _XPLATSTR('-')) && ascii_isdigit2(str[1]) &&
ascii_isdigit(str[2]) && ascii_isdigit5(str[3]) && ascii_isdigit(str[4]))
{
tzCh = str[0];
tzHours = atoi2(str + 1);
tzMinutes = atoi2(str + 3);
}
else
{
return result;
}
secondsSince1601 = timezone_adjust(secondsSince1601, static_cast<unsigned char>(tzCh), tzHours, tzMinutes);
if (secondsSince1601 < 0)
{
return result;
}
}
}
else if (format == ISO_8601)
{
// parse year
if (!ascii_isdigit(str[0]) || !ascii_isdigit(str[1]) || !ascii_isdigit(str[2]) || !ascii_isdigit(str[3]))
{
return result;
}
int year = (str[0] - _XPLATSTR('0')) * 1000 + (str[1] - _XPLATSTR('0')) * 100 + (str[2] - _XPLATSTR('0')) * 10 +
(str[3] - _XPLATSTR('0'));
if (year < 1601)
{
return result;
}
year -= 1601;
str += 4;
if (*str == _XPLATSTR('-'))
{
++str;
}
// parse month
if (!ascii_isdigit1(str[0]) || !ascii_isdigit(str[1]))
{
return result;
}
int month = atoi2(str);
if (month < 1 || month > 12)
{
return result;
}
month -= 1;
str += 2;
if (*str == _XPLATSTR('-'))
{
++str;
}
// parse day
if (!ascii_isdigit3(str[0]) || !ascii_isdigit(str[1]))
{
return result;
}
int monthDay = atoi2(str);
if (!validate_day_month_1601(monthDay, month, year))
{
return result;
}
const int yearDay = get_year_day_1601(month, monthDay, year);
str += 2;
int daysSince1601 = year * DaysInYear + count_leap_years_1601(year) + yearDay;
if (str[0] != _XPLATSTR('T') && str[0] != _XPLATSTR('t'))
{
// No time
secondsSince1601 = static_cast<int64_t>(daysSince1601) * SecondsInDay;
result.m_interval = static_cast<interval_type>(secondsSince1601 * _secondTicks + fracSec);
return result;
}
++str; // skip 'T'
// parse hour
if (!ascii_isdigit2(str[0]) || !ascii_isdigit(str[1]))
{
return result;
}
const int hour = atoi2(str);
str += 2;
if (hour > 23)
{
return result;
}
if (*str == _XPLATSTR(':'))
{
++str;
}
// parse minute
if (!ascii_isdigit5(str[0]) || !ascii_isdigit(str[1]))
{
return result;
}
const int minute = atoi2(str);
// minute > 59 is impossible because we checked that the first digit is <= 5 in the basic format
// check above
str += 2;
if (*str == _XPLATSTR(':'))
{
++str;
}
// parse seconds
if (!ascii_isdigit6(str[0]) || !ascii_isdigit(str[1]))
{
return result;
}
const int sec = atoi2(str);
// We allow 60 to account for leap seconds
if (sec > 60)
{
return result;
}
str += 2;
if (str[0] == _XPLATSTR('.') && ascii_isdigit(str[1]))
{
++str;
int digits = 7;
for (;;)
{
fracSec *= 10;
fracSec += *str - _XPLATSTR('0');
--digits;
++str;
if (digits == 0)
{
while (ascii_isdigit(*str))
{
// consume remaining fractional second digits we can't use
++str;
}
break;
}
if (!ascii_isdigit(*str))
{
// no more digits in the input, do the remaining multiplies we need
for (; digits != 0; --digits)
{
fracSec *= 10;
}
break;
}
}
}
secondsSince1601 =
static_cast<int64_t>(daysSince1601) * SecondsInDay + hour * SecondsInHour + minute * SecondsInMinute + sec;
if (str[0] == _XPLATSTR('Z') || str[0] == _XPLATSTR('z'))
{
// no adjustment needed for zulu time
}
else if (str[0] == _XPLATSTR('+') || str[0] == _XPLATSTR('-'))
{
const unsigned char offsetDirection = static_cast<unsigned char>(str[0]);
if (!ascii_isdigit2(str[1]) || !ascii_isdigit(str[2]) || str[3] != _XPLATSTR(':') ||
!ascii_isdigit5(str[4]) || !ascii_isdigit(str[5]))
{
return result;
}
secondsSince1601 = timezone_adjust(secondsSince1601, offsetDirection, atoi2(str + 1), atoi2(str + 4));
if (secondsSince1601 < 0)
{
return result;
}
}
else
{
// the timezone is malformed, but cpprestsdk currently accepts this as no timezone
}
}
else
{
throw std::invalid_argument("unrecognized date format");
}
result.m_interval = static_cast<interval_type>(secondsSince1601 * _secondTicks + fracSec);
return result;
}