A better date and time C++ library

C++11 added a date and time utility library called chrono, available in namespace std::chrono and header <chrono>. The problem with it is that the library is a general purpose one and therefore lacks many useful features, such as working with dates, weeks, calendars, timezones and other related features. Fortunately, a rich date and time library based on chrono has been created by Howard Hinnant and is available on github. The library is called date and is actually a collection of several small libraries:

  • date: the main library, available in header date.h, defines new date and time classes and operations with them. All the other libraries are based on this one.
  • timezones: a library for timezones, available in files tz.h/tz.cpp, based on the IANA timezone database
  • chrono_io: a library for streaming durations, available in header chrono_io.h
  • iso_week: a library that implements the ISO week calendar, available in header iso_week.h
  • julian and islamic: libraries that implement the Julian and Islamic calendars, available in headers julian.h and islamic.h

You can find all the necessary documentation on github. Here are several links:

In this article we will look at some examples for working with dates and ISO weeks. This library introduces many new types to handle various date and time representations. Among these we will look at:

  • sys_days: A count of days since std::system_clock‘s epoch. This is a time_point with a resolution of a day, and is implicitly convertible to std::system_clock::time_point, that has a much smaller resolution (millisecond or nanosecond), but not the other way around. To go the other way you must use floor().
  • year_month_day: A type that holds a day with fields for year, month (1 to 12) and day (1 to 31).
  • year_month_weekday: A type that holds a day with fields for year, month (1 to 12), a day of the week (0 to 6), and an index in the range [1, 5] that indicates the number of the week in the month.
  • year_weeknum_weekday: A type that hold a year, a weeknum (1 to 53) and a weekday (0 to 6). This can convert implicitly to and from a sys_days.

For using the library we need the following:

  • include header date.h and namespaces date and date::literals
  • for iso weeks we also need header iso_week.h and namespaces iso_week and iso_week::literals
  • NOTICE: The namespaces date::literals and iso_week::literals define types and literal operators with the same name and therefore can lead to name collisions; therefore you should only include them in the scope where you need them.

We will use the following lambda expression to print various dates to the console:

NOTICE: All the ‘today’ and related dates below are based on 2016-10-31.

Let us look at some examples:

  • create sys_days objects (including literals):

  • create year_month_day objects (including literals):

  • creating year_month_weekday literals and converting to year_month_day

  • create year_month_day values for today, yesterday and tomorrow

  • create year_month_day values for first and last day of the month

    Update: The following, as indicated by Howard Hinnant in the comments, can also be used:

  • create iso_week literals

  • get the iso week number for today

We will look at more utilities and examples in another post.

, , , , , , Hits for this post: 4464 .

3 comments untill now

  1. Gravatar

    Awesome post!

    A few tiny nitpicks that should be easy to correct:

    * Re: “not compatible with the std::system_clock::time_point”

    sys_days is implicitly convertible to system_clock::time_point but not vice-versa. To go the other way use floor as shown in many places your article.

    * In the first code snippet, d1, d2 and d3 have type year_month_day. But you can manually make those sys_days instead of auto, and then it does exactly what you say.

    * Here are easier and more readable ways to get the first and last day of the current month:

    year_month_day first_day_this_month = today.year()/today.month()/1;
    year_month_day last_day_this_month = today.year()/today.month()/last;

    You could use auto for the first above. If you use auto for the second, the type is year_month_day_last, and that’s still ok. It will implicitly convert to year_month_day, but has the semantics of _always_ representing the last day of the month. For example you can add a month to it and get the last day of the next month.

  2. Gravatar

    I evidently have no idea how to format things here. 🙂

  3. Gravatar

    Thank you a lot for the feedback. I will make the necessary corrections.

Add your comment now