Search code examples
c++boostiso8601

Represent ISO 8601 Durations in C++/Boost depending on current date


ISO 8601 declares duration format as P[n]Y[n]M[n]DT[n]H[n]M[n]S. For example, P3Y0.5MT6M means "3 years, half of the month and 3 minutes".

There are various ways to convert it to unixtime/chrono::duration/whatever, but all solutions I found uses average month and year duration in seconds, which is not correct according to the standard. Instead, it should depend on the date, for example 01 Feb + P1M should be 01 Mar (+28 days), while 01 Mar + P1M should be 01 Apr (+31 days).

Which way could I implement this? Do I have any better choise than manual implementation with all these leap-years and other nasty things handling?


Solution

  • It would be best to use the date/time library that's being standardized for C++20. The cleverly named Date library can do the manipulations you suggest. It's year_month_day type can do month and year addition the way you want it to work.

    Also, the conversion to a time_point is correct, to within the accuracy of the time_point's integer type:

    system_clock::time_point tp = sys_days{sun[5]/may/2016};
    

    The year_month_day type is implemented in terms of the Gregorian calendar, which is incorporated into ISO 8601. This conversion therefore does not care about "averages" or anything. It gets the system-clock's epoch, and counts the actual number of days from that epoch to the given date. It will factor in all of the idiosyncrasies of the Gregorian calendar. Including leap years. Including those years that ought to be leap years but aren't. These will be counted correctly.

    tp will therefore be the correct number of days, before the epoch or since, to the date in question.