Creating a `std::chrono::time_point` from a calendar date known at compile time

If you have c++20, or will use Howard Hinnant date/time library, then Howard Hannant's answer is better, as it gives you a constexpr time_point.

However, if one doesn't yet have c++20 and wants to avoid adding more external libraries, then this answer is still useful.

You can set the members of the std::tm individually in the initializer, to avoid parsing a string.

// 9th January, 2014
#define DAY 9
#define MONTH 1
#define YEAR 2014

std::tm tm = { /* .tm_sec  = */ 0,
               /* .tm_min  = */ 0,
               /* .tm_hour = */ 0,
               /* .tm_mday = */ (DAY),
               /* .tm_mon  = */ (MONTH) - 1,
               /* .tm_year = */ (YEAR) - 1900,
             };
tm.tm_isdst = -1; // Use DST value from local time zone
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));

The designated initializers are commented out since they are only available in C++20 (though gcc has supported trivial designated initializers as an extension for some time and would work with this case). The fields initialized to zero could be omitted if one had full C++20 designated initializers and wanted midnight on the target date.

It is important to note that mktime will interpret the tm as local time, not GMT nor UTC. If tm_isdst is not set to -1, it will be local standard time, even if daylight savings (summer time) would be in use in the local time zone for the time specified.

Producing a UTC time point from a std::tm, a problem shared with your example, is addressed in other questions, such as Easy way to convert a struct tm (expressed in UTC) to time_t type


Yes, you can do the entire computation at compile time, creating a constexpr system_clock::time_point using Howard Hinnant's date/time library.

#include "date/date.h"
#include <chrono>

int
main()
{
    using namespace date;
    using namespace std::chrono;
    constexpr system_clock::time_point tp = sys_days{January/9/2014} + 12h + 35min + 34s;
    static_assert(tp == system_clock::time_point{1389270934s}, "");
}

This is assuming that the date/time is UTC. If it isn't, you will have to manually add/subtract the UTC offset to make it so. As time zone rules are changed at the whim of politicians all the time, there is little hope in making them constexpr. Even historical time zone rules are updated when misunderstandings come to light.

Also this program will port to C++20 by dropping #include "date/date.h" and using namespace date;. Also using Howard Hinnant's date/time library requires C++14 constexpr muscle. C++11 constexpr is not sufficient (but you can do it at run-time, dropping the constexpr and static_assert).

Tags:

C++

C++14

Chrono