in sdk/core/azure-core/src/datetime.cpp [450:745]
DateTime DateTime::Parse(std::string const& dateTime, DateFormat format)
{
// The values that are not supposed to be read before they are written are set to -123... to avoid
// warnings on some compilers, yet provide a clearly bad value to make it obvious if things don't
// work as expected.
int16_t year = -12345;
int8_t month = -123;
int8_t day = -123;
int8_t hour = 0;
int8_t minute = 0;
int8_t second = 0;
int32_t fracSec = 0;
int8_t dayOfWeek = -1;
int8_t localDiffHours = 0;
int8_t localDiffMinutes = 0;
bool roundFracSecUp = false;
{
std::string::size_type const DateTimeLength = dateTime.length();
std::string::size_type minDateTimeLength = 0;
std::string::size_type cursor = 0;
if (format == DateFormat::Rfc1123)
{
// Shortest possible string: "1 Jan 0001 00:00 UT"
// Longest possible string: "Fri, 31 Dec 9999 23:59:60 +9959"
IncreaseAndCheckMinLength(&minDateTimeLength, DateTimeLength, 19);
if (dateTime[cursor + 3] == ',')
{
dayOfWeek = SubstringEqualsAny(dateTime, cursor, 3, DayNames);
if (dayOfWeek == -1 || dateTime[cursor + 4] != ' ')
{
ThrowParseError("day of week");
}
cursor += 5;
IncreaseAndCheckMinLength(&minDateTimeLength, DateTimeLength, 5);
}
{
auto const parsingArea = "day";
auto const oldCursor = cursor;
day = ParseNumber<decltype(day)>(&cursor, dateTime, DateTimeLength, parsingArea, 1, 2);
IncreaseAndCheckMinLength(&minDateTimeLength, DateTimeLength, (cursor - oldCursor) - 1);
ParseSingleChar(&cursor, dateTime, parsingArea, ' ');
}
{
month = 1 + SubstringEqualsAny(dateTime, cursor, 3, MonthNames);
if (month == 0 || dateTime[cursor + 3] != ' ')
{
ThrowParseError("month");
}
cursor += 4;
}
{
auto const parsingArea = "year";
year = ParseNumber<decltype(year)>(&cursor, dateTime, DateTimeLength, parsingArea, 4, 4);
ParseSingleChar(&cursor, dateTime, parsingArea, ' ');
}
{
auto parsingArea = "hour and minute";
hour = ParseNumber<decltype(hour)>(&cursor, dateTime, DateTimeLength, "hour", 2, 2);
ParseSingleChar(&cursor, dateTime, parsingArea, ':');
minute = ParseNumber<decltype(minute)>(&cursor, dateTime, DateTimeLength, "minute", 2, 2);
if (dateTime[cursor] == ':')
{
++cursor;
parsingArea = "second";
second
= ParseNumber<decltype(second)>(&cursor, dateTime, DateTimeLength, parsingArea, 2, 2);
IncreaseAndCheckMinLength(&minDateTimeLength, DateTimeLength, 3);
}
ParseSingleChar(&cursor, dateTime, parsingArea, ' ');
}
if (!SubstringEquals(dateTime, cursor, 2, "UT"))
{
IncreaseAndCheckMinLength(&minDateTimeLength, DateTimeLength, 1);
if (!SubstringEquals(dateTime, cursor, 3, "GMT"))
{
static std::string const TimeZones[]
= {"EST", "EDT", "CST", "CDT", "MST", "MDT", "PST", "PDT"};
static int8_t const HourAdjustments[] = {-5, -4, -6, -5, -7, -6, -8, -7};
auto tz = SubstringEqualsAny(dateTime, cursor, 3, TimeZones);
if (tz >= 0)
{
localDiffHours = HourAdjustments[tz];
}
else
{
IncreaseAndCheckMinLength(&minDateTimeLength, DateTimeLength, 2);
auto const parsingArea = "time zone";
int8_t sign = 0;
if (dateTime[cursor] == '+')
{
sign = +1;
}
else if (dateTime[cursor] == '-')
{
sign = -1;
}
else
{
ThrowParseError(parsingArea);
}
++cursor;
localDiffHours = sign
* ParseNumber<decltype(localDiffHours)>(
&cursor, dateTime, DateTimeLength, parsingArea, 2, 2);
localDiffMinutes = sign
* ParseNumber<decltype(localDiffMinutes)>(
&cursor, dateTime, DateTimeLength, parsingArea, 2, 2);
}
}
}
}
else if (format == DateFormat::Rfc3339)
{
// Shortest possible string: "00010101"
// "Longest" possible string: "9999-12-31T23:59:60.1234567*+99:59"
// * - any fractional second digits after the 7th are ignored.
IncreaseAndCheckMinLength(&minDateTimeLength, DateTimeLength, 8);
{
auto const parsingArea = "year";
year = ParseNumber<decltype(year)>(&cursor, dateTime, DateTimeLength, parsingArea, 4, 4);
ParseSingleOptionalChar(&cursor, dateTime, '-', &minDateTimeLength, DateTimeLength);
}
{
auto const parsingArea = "month";
month = ParseNumber<decltype(month)>(&cursor, dateTime, DateTimeLength, parsingArea, 2, 2);
ParseSingleOptionalChar(&cursor, dateTime, '-', &minDateTimeLength, DateTimeLength);
}
{
auto const parsingArea = "day";
day = ParseNumber<decltype(day)>(&cursor, dateTime, DateTimeLength, parsingArea, 2, 2);
}
if (cursor < DateTimeLength
&& (dateTime[cursor] == 'T' || dateTime[cursor] == 't' || dateTime[cursor] == ' '))
{
++cursor;
IncreaseAndCheckMinLength(&minDateTimeLength, DateTimeLength, 7);
{
auto const parsingArea = "hour";
hour = ParseNumber<decltype(hour)>(&cursor, dateTime, DateTimeLength, parsingArea, 2, 2);
ParseSingleOptionalChar(&cursor, dateTime, ':', &minDateTimeLength, DateTimeLength);
}
{
auto const parsingArea = "minute";
minute
= ParseNumber<decltype(minute)>(&cursor, dateTime, DateTimeLength, parsingArea, 2, 2);
ParseSingleOptionalChar(&cursor, dateTime, ':', &minDateTimeLength, DateTimeLength);
}
{
auto const parsingArea = "second";
second
= ParseNumber<decltype(second)>(&cursor, dateTime, DateTimeLength, parsingArea, 2, 2);
}
if (cursor + 1 < DateTimeLength)
{
if (dateTime[cursor] == '.')
{
++minDateTimeLength;
++cursor;
}
{
auto oldCursor = cursor;
fracSec = ParseNumber<decltype(fracSec)>(
&cursor, dateTime, DateTimeLength, "second fraction", 0, 7);
auto const charsRead = (cursor - oldCursor);
{
auto const zerosToAdd = static_cast<int>(7 - charsRead);
for (auto i = 0; i < zerosToAdd; ++i)
{
fracSec *= 10;
}
}
minDateTimeLength += charsRead;
if (charsRead == 7 && (DateTimeLength - cursor) > 0)
{
auto const ch = dateTime[cursor];
if (Core::_internal::StringExtensions::IsDigit(ch))
{
auto const num = static_cast<int>(static_cast<unsigned char>(ch) - '0');
if (num > 4)
{
if (fracSec < 9999999)
{
++fracSec;
}
else
{
roundFracSecUp = true;
}
}
++cursor;
}
}
}
for (auto i = DateTimeLength - cursor; i > 0; --i)
{
if (Core::_internal::StringExtensions::IsDigit(dateTime[cursor]))
{
++minDateTimeLength;
++cursor;
}
else
{
break;
}
}
if (DateTimeLength - cursor > 0)
{
auto const parsingArea = "time zone";
int8_t sign = 0;
if (dateTime[cursor] == '+')
{
sign = +1;
}
else if (dateTime[cursor] == '-')
{
sign = -1;
}
if (sign != 0)
{
++cursor;
IncreaseAndCheckMinLength(&minDateTimeLength, DateTimeLength, 6);
localDiffHours = sign
* ParseNumber<decltype(localDiffHours)>(
&cursor, dateTime, DateTimeLength, parsingArea, 2, 2);
if (dateTime[cursor] == ':')
{
++cursor;
}
else
{
ThrowParseError(parsingArea);
}
localDiffMinutes = sign
* ParseNumber<decltype(localDiffMinutes)>(
&cursor, dateTime, DateTimeLength, parsingArea, 2, 2);
}
}
}
}
}
else
{
throw std::invalid_argument("Unrecognized date format.");
}
return DateTime(
year,
month,
day,
hour,
minute,
second,
fracSec,
dayOfWeek,
localDiffHours,
localDiffMinutes,
roundFracSecUp);
}
}