Skip to content

Datetime

Datetime

C++20 includes date and time utilities in the chrono library.

These utilities were originally developed as the date library, and were finally merged to ISO C++ as of C++20.

date.h contains chrono extensions to deal with dates: - https://howardhinnant.github.io/date/date.html - https://howardhinnant.github.io/date/tz.html

The date library implementation is currently available on more compilers and platforms than the C++20 library.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
find_package(Date QUIET)
if (NOT Date_FOUND)
    # Find Threads library
    find_package(Threads)

    # Find Curl (to download timezone database)
    find_package(CURL QUIET)
    if (NOT CURL_FOUND)
        set(USE_SYSTEM_TZ_DB ON CACHE BOOL "Build tz library" FORCE)
    else ()
        set(USE_SYSTEM_TZ_DB OFF CACHE BOOL "Build tz library" FORCE)
    endif ()
    message("USE_SYSTEM_TZ_DB=${USE_SYSTEM_TZ_DB}")
    set(BUILD_TZ_LIB ON CACHE BOOL "Build tz library" FORCE)

    # Fetch date library
    FetchContent_Declare(date GIT_REPOSITORY https://github.com/HowardHinnant/date.git GIT_TAG v3.0.1)
    FetchContent_MakeAvailable(date)
endif ()

# Link library
add_executable(datetime datetime.cpp)
target_link_libraries(datetime date::date date::date-tz)

1
2
#include <date/date.h>
#include <date/tz.h>

1
2
3
4
    // Ensure operator<< it's not ambiguous with C++20 datetime
#if !defined(__cpp_lib_chrono) || __cpp_lib_chrono < 201907L
    using date::operator<<;
#endif

1
2
3
// - UTC time zone and microsecond precision
const std::chrono::time_point now = std::chrono::system_clock::now();
std::cout << "Now: " << now << '\n';

1
2
std::cout << "Formatted: "
          << date::format("%a, %b %d, %Y at %I:%M %p %Z", now) << '\n';

1
2
3
4
5
6
{
    using date::operator<<;
    std::cout << date::format(std::locale("de_DE"),
                              "%a, %b %d, %Y at %T %Z", now)
              << '\n';
}

1
2
3
4
std::cout << "Epoch: "
          << std::chrono::time_point<std::chrono::system_clock>(
                 std::chrono::seconds(0))
          << '\n';

1
2
3
4
5
// - This is a serial-based time-point
// - Good for day oriented arithmetic
date::sys_days today = date::floor<date::days>(now);
std::cout << "today: " << today.time_since_epoch().count()
          << " days since epoch" << '\n';

1
2
3
4
5
6
7
8
9
// - This is a field-based time-point
// - Good for returning field values
// - Good for month/year arithmetic
// Last day of March / 2015
using namespace date::literals;
date::year_month_day t_ymd = 2015_y / date::March / 22;
std::cout << "t_ymd: " << t_ymd << '\n';
std::cout << "t_ymd since epoch: "
          << date::sys_days(t_ymd).time_since_epoch().count() << '\n';

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// weekday
// This is a field-based time-point
date::year_month_weekday t_ymw =
    date::year{2015} / date::month{3} / date::Monday[2];
std::cout << "t_ymw: " << t_ymw << '\n';
std::cout << "t_ymw since epoch: "
          << date::sys_days(t_ymw).time_since_epoch().count() << '\n';
std::cout << "year_month_day(t3): "
          << date::sys_days(date::year_month_day(t_ymw))
                 .time_since_epoch()
                 .count()
          << '\n';

1
2
auto today_ymd = date::year_month_day{today};
std::cout << "Today is " << today_ymd << '\n';

1
2
3
4
5
// - Time since midnight (serial-based)
auto time_since_midnight = now - today;
std::cout << "Serial time since midnight "
          << duration_cast<std::chrono::seconds>(time_since_midnight)
          << '\n';

1
2
3
date::hh_mm_ss time_since_midnight_hms(time_since_midnight);
std::cout << "Field-based time since midnight: " << today_ymd << " - "
          << time_since_midnight_hms << '\n';

1
2
3
auto time_since_midnight_tod = date::make_time(time_since_midnight);
std::cout << "Field-based time since midnight: " << today_ymd << " - "
          << time_since_midnight_tod << '\n';

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// They are possible, and they might be even useful
std::cout << "All odd fridays this year: ";
date::year this_year = today_ymd.year();
for (auto m = 1; m <= 12; ++m) {
    auto first_friday =
        date::year_month_day(this_year / m / date::Friday[1]);
    std::cout << first_friday << ' ';
    auto third_friday = first_friday.year() / first_friday.month() /
                        (first_friday.day() + date::weeks{2});
    std::cout << third_friday << ' ';
    auto fifth_friday = third_friday.year() / third_friday.month() /
                        (third_friday.day() + date::weeks{2});
    if (fifth_friday.ok()) {
        std::cout << fifth_friday << ' ';
    }
}
std::cout << '\n';

1
2
// Zoned time is a wrapper that also keeps track of the shift from UTC
date::zoned_time local_tp = date::make_zoned(date::current_zone(), now);

1
2
3
4
5
6
7
8
9
// Little more efficient. Less convenient unless reusing the zone ptr.
auto berlin_zone = date::locate_zone("Europe/Berlin");
auto berlin_time = date::make_zoned(
    berlin_zone,
    floor<std::chrono::seconds>(std::chrono::system_clock::now()));
std::cout << "berlin time: "
          << date::format(std::locale("de_DE"), "%a, %b %d, %Y at %T %Z",
                          berlin_time)
          << '\n';

1
2
3
4
5
6
7
8
// Little less efficient. More convenient.
auto sp_time = date::make_zoned(
    "America/Sao_Paulo",
    floor<std::chrono::seconds>(std::chrono::system_clock::now()));
std::cout << "sao paulo time: "
          << date::format(std::locale("de_DE"), "%a, %b %d, %Y at %T %Z",
                          sp_time)
          << '\n';

1
2
3
std::cout << "local_tp: " << local_tp << '\n';
std::cout << "abbrev: " << local_tp.get_info().abbrev << '\n';
std::cout << "Sys time: " << local_tp.get_sys_time() << '\n';

1
2
3
std::cout << "offset: " << local_tp.get_info().offset << '\n';
std::cout << "save: " << local_tp.get_info().save << '\n';
std::cout << "Local time: " << local_tp.get_local_time() << '\n';

1
2
3
4
5
6
std::cout << "Formatted: "
          << date::format("%a, %b %d, %Y at %I:%M %p %Z", local_tp)
          << '\n';
std::cout << date::format(std::locale("de_DE"),
                          "%a, %b %d, %Y at %T %Z", local_tp)
          << '\n';

1
2
3
4
auto now_nanoseconds = date::floor<std::chrono::nanoseconds>(now);
auto local_tp_nanoseconds =
    date::make_zoned(date::current_zone(), now_nanoseconds);
std::cout << "In millisecs: " << local_tp_nanoseconds << '\n';

1
2
3
4
auto now_milliseconds = date::floor<std::chrono::milliseconds>(now);
auto local_tp_milliseconds =
    date::make_zoned(date::current_zone(), now_milliseconds);
std::cout << "In millisecs: " << local_tp_milliseconds << '\n';

1
2
3
4
auto now_milliseconds = date::floor<std::chrono::milliseconds>(now);
auto local_tp_milliseconds =
    date::make_zoned(date::current_zone(), now_milliseconds);
std::cout << "In millisecs: " << local_tp_milliseconds << '\n';

1
2
3
4
auto now_milliseconds = date::floor<std::chrono::milliseconds>(now);
auto local_tp_milliseconds =
    date::make_zoned(date::current_zone(), now_milliseconds);
std::cout << "In millisecs: " << local_tp_milliseconds << '\n';

1
2
3
4
auto now_milliseconds = date::floor<std::chrono::milliseconds>(now);
auto local_tp_milliseconds =
    date::make_zoned(date::current_zone(), now_milliseconds);
std::cout << "In millisecs: " << local_tp_milliseconds << '\n';

1
2
3
auto tokyo_tp = date::make_zoned("Asia/Tokyo", sp_time);
std::cout << sp_time << " in sao paulo is " << tokyo_tp << " in tokyo"
          << '\n';

Share Snippets