in Include/json_cpp/details/asyncrt_utils.hpp [723:929]
datetime __cdecl datetime::from_string(const utility::string_t& dateString, date_format format)
{
// avoid floating point math to preserve precision
uint64_t ufrac_second = 0;
#ifdef _WIN32
datetime result;
if (format == RFC_1123)
{
SYSTEMTIME sysTime = {0};
std::wstring month(3, L'\0');
std::wstring unused(3, L'\0');
const wchar_t * formatString = L"%3c, %2d %3c %4d %2d:%2d:%2d %3c";
auto n = swscanf_s(dateString.c_str(), formatString,
unused.data(), unused.size(),
&sysTime.wDay,
month.data(), month.size(),
&sysTime.wYear,
&sysTime.wHour,
&sysTime.wMinute,
&sysTime.wSecond,
unused.data(), unused.size());
if (n == 8)
{
std::wstring monthnames[12] = {L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec"};
auto loc = std::find_if(monthnames, monthnames+12, [&month](const std::wstring& m) { return m == month;});
if (loc != monthnames+12)
{
sysTime.wMonth = (short) ((loc - monthnames) + 1);
if (system_type_to_datetime(&sysTime, ufrac_second, &result))
{
return result;
}
}
}
}
else if (format == ISO_8601)
{
// Unlike FILETIME, SYSTEMTIME does not have enough precision to hold seconds in 100 nanosecond
// increments. Therefore, start with seconds and milliseconds set to 0, then add them separately
// Try to extract the fractional second from the timestamp
utility::string_t input;
extract_fractional_second(dateString, input, ufrac_second);
{
SYSTEMTIME sysTime = { 0 };
const wchar_t * formatString = L"%4d-%2d-%2dT%2d:%2d:%2dZ";
auto n = swscanf_s(input.c_str(), formatString,
&sysTime.wYear,
&sysTime.wMonth,
&sysTime.wDay,
&sysTime.wHour,
&sysTime.wMinute,
&sysTime.wSecond);
if (n == 3 || n == 6)
{
if (system_type_to_datetime(&sysTime, ufrac_second, &result))
{
return result;
}
}
}
{
SYSTEMTIME sysTime = {0};
DWORD date = 0;
const wchar_t * formatString = L"%8dT%2d:%2d:%2dZ";
auto n = swscanf_s(input.c_str(), formatString,
&date,
&sysTime.wHour,
&sysTime.wMinute,
&sysTime.wSecond);
if (n == 1 || n == 4)
{
sysTime.wDay = date % 100;
date /= 100;
sysTime.wMonth = date % 100;
date /= 100;
sysTime.wYear = (WORD)date;
if (system_type_to_datetime(&sysTime, ufrac_second, &result))
{
return result;
}
}
}
{
SYSTEMTIME sysTime = {0};
GetSystemTime(&sysTime); // Fill date portion with today's information
sysTime.wSecond = 0;
sysTime.wMilliseconds = 0;
const wchar_t * formatString = L"%2d:%2d:%2dZ";
auto n = swscanf_s(input.c_str(), formatString,
&sysTime.wHour,
&sysTime.wMinute,
&sysTime.wSecond);
if (n == 3)
{
if (system_type_to_datetime(&sysTime, ufrac_second, &result))
{
return result;
}
}
}
}
return datetime();
#else
std::string input(dateString);
struct tm output = tm();
if (format == RFC_1123)
{
strptime(input.data(), "%a, %d %b %Y %H:%M:%S GMT", &output);
}
else
{
// Try to extract the fractional second from the timestamp
utility::string_t input;
extract_fractional_second(dateString, input, ufrac_second);
auto result = strptime(input.data(), "%Y-%m-%dT%H:%M:%SZ", &output);
if (result == nullptr)
{
result = strptime(input.data(), "%Y%m%dT%H:%M:%SZ", &output);
}
if (result == nullptr)
{
// Fill the date portion with the epoch,
// strptime will do the rest
memset(&output, 0, sizeof(struct tm));
output.tm_year = 70;
output.tm_mon = 1;
output.tm_mday = 1;
result = strptime(input.data(), "%H:%M:%SZ", &output);
}
if (result == nullptr)
{
result = strptime(input.data(), "%Y-%m-%d", &output);
}
if (result == nullptr)
{
result = strptime(input.data(), "%Y%m%d", &output);
}
if (result == nullptr)
{
return datetime();
}
}
#if (defined(ANDROID) || defined(__ANDROID__))
// HACK: The (nonportable?) POSIX function timegm is not available in
// bionic. As a workaround[1][2], we set the C library timezone to
// UTC, call mktime, then set the timezone back. However, the C
// environment is fundamentally a shared global resource and thread-
// unsafe. We can protect our usage here, however any other code might
// manipulate the environment at the same time.
//
// [1] http://linux.die.net/man/3/timegm
// [2] http://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html
time_t time;
static boost::mutex env_var_lock;
{
boost::lock_guard<boost::mutex> lock(env_var_lock);
std::string prev_env;
auto prev_env_cstr = getenv("TZ");
if (prev_env_cstr != nullptr)
{
prev_env = prev_env_cstr;
}
setenv("TZ", "UTC", 1);
time = mktime(&output);
if (prev_env_cstr)
{
setenv("TZ", prev_env.c_str(), 1);
}
else
{
unsetenv("TZ");
}
}
#else
time_t time = timegm(&output);
#endif
struct timeval tv = timeval();
tv.tv_sec = time;
auto result = timeval_to_datetime(tv);
// fractional seconds are already in correct format so just add them.
result = result + ufrac_second;
return result;
#endif
}