Home > OS >  Consistently parse various date and time formats with Howard Hinnant's date library
Consistently parse various date and time formats with Howard Hinnant's date library

Time:11-09

I need to be able to parse and store various dates, times, or both according to a subset of the ISO-8601 standard.

The dates are in the formats:

  • YYYY
  • YYYY-mm
  • YYYY-mm-dd

The times are in the formats:

  • HH:MM:SS
  • HH:MM:SS.ffffff

If a date and time are both defined, then a timezone must also be defined, like so:

  • YYYY-mm-ddTHH:MM:SS.ffffff ZZ:ZZ
    • For example: 2012-03-04T05:06:07.123456 07:00

I tried to use Howard Hinnant's date library, the same one in the C 20 standard. It seems I need to use specific types to parse different formats which is slightly annoying. I would rather be able to parse and store any format within the same type.

To illustrate the problem:

sys_time<microseconds> sys_us;
microseconds us;
year_month ym;
year y;

std::istringstream iss;

iss.str("2012-03-04T05:06:07.123456 07:00");
iss >> date::parse("%FT%T%Ez", sys_us); // Only works with this type. (The others can't parse this much info.)
assert(!iss.fail());

iss.str("2012-03-04");
iss >> date::parse("%F", sys_us); // If the date has the full year, month, and day, this works.
assert(!iss.fail());

iss.str("2012-03");
// iss >> date::parse("%Y-%m", sys_us); // This fails; day is missing.
iss >> date::parse("%Y-%m", ym); // Works.
assert(!iss.fail());

iss.str("2012");
// iss >> date::parse("%Y", sys_us); // This fails.
// iss >> date::parse("%Y", ym); // Also fails; month is missing.
iss >> date::parse("%Y", y); // Works.
assert(!iss.fail());

iss.str("05:06:07.123456");
// iss >> date::parse("%T", sys_us); // Also fails; unhappy with missing date.
iss >> date::parse("%T", us); // Must use duration type for time instead.
assert(!iss.fail());

It would be much nicer if I could date::parse(format, obj) where obj didn't need to change types. Is that possible?

CodePudding user response:

The only way to store them all in the same type is to pick the one with the most information (sys_time<microseconds>), then do the parse in the partial types as you've shown and add defaults for those values not parsed.

For example:

iss.str("05:06:07.123456");
iss >> date::parse("%T", us); // Must use duration type for time     
sys_us = sys_days{year{0}/1/1}   us;  // Add defaulted date
  • Related