Beispiel #1
0
chrono::system_clock::time_point cppkit::ck_iso_8601_to_time_point( const ck_string& str )
{
	const size_t tDex = str.find('T');

	if (tDex == string::npos)
        CK_THROW(("Invalid iso 8601 string: %s",str.c_str()));

	const size_t dotDex = str.find('.');
	const size_t zDex = str.find('Z');
	const size_t plusDex = str.find('+', 1);
	const size_t subDex = str.find('-', str.find('-', str.find('-') + 1) + 1);

	if (plusDex != string::npos && subDex != string::npos)
        CK_THROW(("Invalid iso 8601 string: %s",str.c_str()));

	size_t dtEnd = dotDex;

	if (dtEnd == string::npos || dtEnd > zDex)
		dtEnd = zDex;

	if (dtEnd == string::npos || dtEnd > plusDex)
		dtEnd = plusDex;

	if (dtEnd == string::npos || dtEnd > subDex)
		dtEnd = subDex;

	const string dateStr = str.substr(0, tDex);
	const string timeStr = str.substr(tDex + 1, (dtEnd - tDex) - 1);
	string fracSecStr;

	if (dotDex != string::npos)
	{
		size_t fsEnd = zDex;

		if (fsEnd == string::npos || fsEnd > plusDex)
			fsEnd = plusDex;

		if (fsEnd == string::npos || fsEnd > subDex)
			fsEnd = subDex;

		const size_t fsStart = dateStr.size() + 1 + timeStr.size();
		const size_t fsLen = fsEnd == string::npos ? string::npos : fsEnd - fsStart;

		fracSecStr = str.substr(fsStart, fsLen);
	}

	const size_t zoneDex = dateStr.size() + 1 + timeStr.size() + fracSecStr.size();
	const string zoneStr = zDex == str.size() ? "" : str.substr(zoneDex);

	tm ttm = tm();

	int yyyy = 0, mm = 0, dd = 0;
	SSCANF(dateStr.c_str(), "%4d-%2d-%2d", &yyyy, &mm, &dd);

	ttm.tm_year = yyyy - 1900;
	ttm.tm_mon = mm - 1; // Month since January 
	ttm.tm_mday = dd; // Day of the month [1-31]

	int HH = 0, MM = 0, SS = 0;
	SSCANF(timeStr.c_str(), "%2d:%2d:%2d", &HH, &MM, &SS);

	ttm.tm_hour = HH; // Hour of the day [00-23]
	ttm.tm_min = MM;
	ttm.tm_sec = SS;

	// We need to go from a broken down time (struct tm) to a time_t. BUT, we have to use the right function when converting
	// from struct tm. mktime() assumes the struct tm is in localtime. gmtime() assumes the struct tm is in UTC. If the incoming
	// iso 8601 string has a 'Z' then we need to use gmtime() (or _mkgmtime() on windows), else we can use mktime().
	time_t theTime = 0;
	if (zDex == string::npos) // input is local time
		theTime = mktime(&ttm);
	else // input is UTC
	{
#ifdef IS_WINDOWS
		theTime = _mkgmtime(&ttm);
#else
		theTime = timegm(&ttm);
#endif
	}

	system_clock::time_point time_point_result = std::chrono::system_clock::from_time_t(theTime);

	double fracSec = stod(fracSecStr);

	uint32_t numMillis = (uint32_t)(fracSec * 1000);

	time_point_result += std::chrono::milliseconds(numMillis);

	return time_point_result;
}