86

How can I extract the year, month, day, hour, minute, second and millisecond from an std::chrono::time_point object?

I only saw examples on how to extract the total amount of e.g. seconds from a duration.

bytecode77
  • 14,163
  • 30
  • 110
  • 141
  • possible duplicate of [How to convert std::chrono::time\_point to calendar datetime string with fractional seconds?](http://stackoverflow.com/questions/12835577/how-to-convert-stdchronotime-point-to-calendar-datetime-string-with-fraction) – Ali Apr 11 '13 at 20:19
  • See also [Efficient algorithm for converting number of days to years (including leap years)](https://stackoverflow.com/questions/11609769/efficient-algorithm-for-converting-number-of-days-to-years-including-leap-years/74210332#74210332) – ThibaultDC Oct 26 '22 at 15:32

2 Answers2

133

You can only extract this information from a system_clock::time_point. This is the only system-supplied clock that has a relationship with the civil calendar. Here is how to get the current time_point using this clock:

 system_clock::time_point now = system_clock::now();

You can then convert this to a time_t with:

time_t tt = system_clock::to_time_t(now);

Using the C library you can then convert a time_t to a tm, but you must choose whether you want that conversion to happen in the UTC timezone, or you local timezone:

tm utc_tm = *gmtime(&tt);
tm local_tm = *localtime(&tt);

Then you can print out the components of the tm, for example:

std::cout << local_tm.tm_year + 1900 << '\n';
std::cout << local_tm.tm_mon + 1 << '\n';
std::cout << local_tm.tm_mday << '\n';

Additionally

If you want, you can take advantage of this non-guaranteed information:

Every implementation of system_clock I'm aware of is based on unix time. I.e. the number of seconds since New Years 1970 UTC, neglecting leap seconds. And the precision of this count is usually finer than seconds. Here is a complete program which extracts all of this information:

#include <chrono>
#include <ctime>
#include <iostream>

int
main()
{
    using namespace std;
    using namespace std::chrono;
    typedef duration<int, ratio_multiply<hours::period, ratio<24> >::type> days;
    system_clock::time_point now = system_clock::now();
    system_clock::duration tp = now.time_since_epoch();
    days d = duration_cast<days>(tp);
    tp -= d;
    hours h = duration_cast<hours>(tp);
    tp -= h;
    minutes m = duration_cast<minutes>(tp);
    tp -= m;
    seconds s = duration_cast<seconds>(tp);
    tp -= s;
    std::cout << d.count() << "d " << h.count() << ':'
              << m.count() << ':' << s.count();
    std::cout << " " << tp.count() << "["
              << system_clock::duration::period::num << '/'
              << system_clock::duration::period::den << "]\n";

    time_t tt = system_clock::to_time_t(now);
    tm utc_tm = *gmtime(&tt);
    tm local_tm = *localtime(&tt);
    std::cout << utc_tm.tm_year + 1900 << '-';
    std::cout << utc_tm.tm_mon + 1 << '-';
    std::cout << utc_tm.tm_mday << ' ';
    std::cout << utc_tm.tm_hour << ':';
    std::cout << utc_tm.tm_min << ':';
    std::cout << utc_tm.tm_sec << '\n';
}

It is handy to create a custom duration to model days:

typedef duration<int, ratio_multiply<hours::period, ratio<24> >::type> days;

Now you can get the time since the epoch, to as fine a precision as it can manage, with:

system_clock::duration tp = now.time_since_epoch();

Then truncate it to days, and subtract that off.

Then truncate it to hours, and subtract that off.

Continue until you've subtracted off the seconds.

What you're left with is the fraction of a second with the units of system_clock::duration. So print out that run time value and the compile time units of that value as shown.

For me this program prints out:

15806d 20:31:14 598155[1/1000000]
2013-4-11 20:31:14

My output indicates the system_clock::duration precision is microseconds. If desired, that can be truncated to milliseconds with:

milliseconds ms = duration_cast<milliseconds>(tp);

Update

This header-only C++11/14 library encapsulates the work above, reducing client work down to:

#include "date.h"
#include <iostream>

int
main()
{
    // Reduce verbosity but let you know what is in what namespace
    namespace C = std::chrono;
    namespace D = date;
    namespace S = std;

    auto tp = C::system_clock::now(); // tp is a C::system_clock::time_point
    {
        // Need to reach into namespace date for this streaming operator
        using namespace date;
        S::cout << tp << '\n';
    }
    auto dp = D::floor<D::days>(tp);  // dp is a sys_days, which is a
                                      // type alias for a C::time_point
    auto ymd = D::year_month_day{dp};
    auto time = D::make_time(C::duration_cast<C::milliseconds>(tp-dp));
    S::cout << "year        = " << ymd.year() << '\n';
    S::cout << "month       = " << ymd.month() << '\n';
    S::cout << "day         = " << ymd.day() << '\n';
    S::cout << "hour        = " << time.hours().count() << "h\n";
    S::cout << "minute      = " << time.minutes().count() << "min\n";
    S::cout << "second      = " << time.seconds().count() << "s\n";
    S::cout << "millisecond = " << time.subseconds().count() << "ms\n";
}

Which just output for me:

2015-07-10 20:10:36.023017
year        = 2015
month       = Jul
day         = 10
hour        = 20h
minute      = 10min
second      = 36s
millisecond = 23ms

Another Update

This library grew into a C++ standards proposal and is now in the C++20 working draft. The syntax for extracting these fields from a system_clock::time_point in C++20 will be:

#include <chrono>

int
main()
{
    using namespace std::chrono;
    auto tp = system_clock::now();
    auto dp = floor<days>(tp);
    year_month_day ymd{dp};
    hh_mm_ss time{floor<milliseconds>(tp-dp)};
    auto y = ymd.year();
    auto m = ymd.month();
    auto d = ymd.day();
    auto h = time.hours();
    auto M = time.minutes();
    auto s = time.seconds();
    auto ms = time.subseconds();
}

The above assumes you want these fields in UTC. If you prefer them in some other time zone, that will also be possible. For example, here is how to do it in your computer's current local time zone:

#include <chrono>

int
main()
{
    using namespace std::chrono;
    auto tp = zoned_time{current_zone(), system_clock::now()}.get_local_time();
    auto dp = floor<days>(tp);
    year_month_day ymd{dp};
    hh_mm_ss time{floor<milliseconds>(tp-dp)};
    auto y = ymd.year();
    auto m = ymd.month();
    auto d = ymd.day();
    auto h = time.hours();
    auto M = time.minutes();
    auto s = time.seconds();
    auto ms = time.subseconds();
}

The only difference above is the construction of tp which now has type local_time as opposed to sys_time in the UTC example. Alternatively one could have picked an arbitrary time zone with this small change:

auto tp = zoned_time{"Europe/London", system_clock::now()}.get_local_time();
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • The problem with `tm` is that it doesn't have millisecond precision, which is something I need. – bytecode77 Apr 11 '13 at 20:31
  • @Devils Child: In that case, you can convert the resulting time_t back to a system_clock::time_point using `from_time_t`. And then subtract the two. You should get a duration that contains the fractional seconds, which you can manipulate further. – Dave S Apr 11 '13 at 20:36
  • Thanks. I will go with your solution :) – bytecode77 Apr 11 '13 at 20:43
  • 1
    Howard, IIRC you were working on calendar classes to extend chrono - which is really about clock time. Where did that go? any chance we could see it for C++14? Thx... – emsr Apr 12 '13 at 03:17
  • The LWG intensely disliked http://home.roadrunner.com/~hinnant/bloomington/date.html . Coincidentally I've lately put some weekend-time into a system evolved from my paper, which takes into account some of the comments I received. I don't know if I'll end up proposing it or not. It is currently an experiment too preliminary to share. However it starts with `days` as defined above, and `typedef std::chrono::time_point < std::chrono::system_clock, days > day_point;` – Howard Hinnant Apr 12 '13 at 16:02
  • 3
    Fwiw, the weekend-time I mention in my comment above this one produced this: http://home.roadrunner.com/~hinnant/date_algorithms.html It is not a date proposal. But it might help someone else create a date proposal. – Howard Hinnant Sep 04 '13 at 20:27
  • @HowardHinnant thanks for putting that up here. Is there anything we can subscribe to (by way of RSS/twitter feed) so we don't miss stuff? – sehe Apr 09 '14 at 07:26
  • @sehe: I keep a very low tech website here: http://home.roadrunner.com/~hinnant/ No push, you pull, sorry. – Howard Hinnant Apr 09 '14 at 14:50
  • 2
    Date library published as a GitHub repo here: https://github.com/HowardHinnant/date – Emile Cormier Jul 28 '15 at 18:40
  • 3
    `tm local_tm = *localtime(&tt);` is not thread-safe in general (although it is in Windows) – M.M Apr 08 '16 at 10:50
  • @M.M: The library at https://github.com/HowardHinnant/date avoids the thread safety issues associated with the C lib. – Howard Hinnant Apr 08 '16 at 13:28
  • 1
    Really?! ``Date.h`` is 8000+ lines long. Classical case of over engineering, given all anyone really needed were fixed versions of the crappy ``asctime, localtime,...`` dinosaur functions in the standard namespace, e.g. ``void localtime( time_t t, struct tm * destination);``, removing those oh so 1960 data races. Alternatively, ``std::chrono::time_point_cast(std::chrono::system_clock::now() ).to_string()``. It makes no sense that you can cast durations to miliseconds and it does not use the same style for casting time points. – BitTickler Oct 14 '18 at 22:34
  • 2
    @BitTickler: Glad I could help you get that off your chest. Feel better now? – Howard Hinnant Oct 15 '18 at 02:37
  • @HowardHinnant Glad I could help ;) Don't get me starting another rant about ``std::chrono::system_clock::now()`` being a ``duration`` and not a ``DateTime`` kind of dedicated type of its own. A lot of problems ensue from that decision to have ``TimeSpan`` aka ``duration`` being made to also depict a fixed, absolute point in time. But hey - I feel good. I use the Win32 FileTime functions instead :) – BitTickler Oct 15 '18 at 08:22
  • 6
    @BitTickler: `decltype(std::chrono::system_clock::now())` is `std::chrono::system_clock::time_point`, not `system_clock::duration`. If you would like to learn about the `` library, I can help. If you just want to rant, please educate yourself enough to rant with facts. – Howard Hinnant Oct 15 '18 at 13:57
  • Hi! We are finally in 2020 and `year_month_day` is even documented on cppreference.com, however I am not able to leverage on that neither on my local machine (running a bleeding edge rolling linux distribution) neither on online compilers such as coliru. Do you know what is the "diffusion" status? Thanks! – DarioP Mar 10 '20 at 16:21
  • Vendors are working on it. But I don't know their schedules. For now the only implementation I'm aware of is still at https://github.com/HowardHinnant/date – Howard Hinnant Mar 10 '20 at 19:22
  • 1
    @HowardHinnant How do you assign year() month() and day() to integers? I looked at the source but couldn't tell. – intrigued_66 Jul 28 '20 at 14:20
  • 1
    For `year` there is an explicit conversion to `int`. I use this syntax: `int iy{y};`. For `month` and `day` it is the same except use `unsigned` instead of `int`. An easy way to remember this is going the other way, from integral to `year`, is the same: an explicit conversion from `int` to `year`: `year y{iy};` – Howard Hinnant Jul 28 '20 at 14:38
  • I prefer verbosity in this 10 lines of code – Yola Jun 25 '21 at 13:51
  • @HowardHinnant how do you print hours minutes seconds milliseconds ? – kramer Nov 10 '21 at 20:48
  • `cout << hh_mm_ss{floor(some-duration)} << '\n';` – Howard Hinnant Nov 10 '21 at 21:11
  • @HowardHinnant could you be more explicit. How to define some and duration? – kramer Nov 11 '21 at 11:22
  • 2
    Usually people ask detailed questions with a Stack Overflow Question. The comment section does not leave enough room or formatting flexibility to make question/answer efficient. However I can recommend a basic C++11 chrono tutorial: https://www.youtube.com/watch?v=P32hvk8b13M and a view of the new C++20 chrono facilities: https://www.youtube.com/watch?v=adSAN282YIw – Howard Hinnant Nov 11 '21 at 13:51
  • `zoned_time` is a template class, but your code above initializes it like it is an object `zoned_time{current_zone(), system_clock::now()}`. How? What am I missing here?! – ZoomIn Aug 22 '22 at 08:17
  • This is using a new language feature available in C++17 called CTAD. The template arguments of `zoned_time` are deduced from the arguments supplied to the `zoned_time` constructor. More info: https://en.cppreference.com/w/cpp/language/class_template_argument_deduction – Howard Hinnant Aug 23 '22 at 12:30
1

Once I came up with this implementation. Might not be the best but works fine for my home-grown project.

One can get everything but milliseconds from timeinfo and milliseconds from ms.

static std::wstring GetDateTime()
{
    time_t rawtime;
    struct tm timeinfo;
    wchar_t buffer[20];

    time(&rawtime);
    localtime_s(&timeinfo, &rawtime);

    auto now = std::chrono::system_clock::now();
    auto tt = std::chrono::system_clock::to_time_t(now);
    auto nowTruncated = std::chrono::system_clock::from_time_t(tt);
    auto ms = (now - nowTruncated).count();

    wcsftime(buffer, 20, L"%Y-%m-%d %H:%M:%S", &timeinfo);

    return std::wstring(buffer) + L"." + std::to_wstring(ms).substr(0, 3);
}

Example output:

2021-06-25 10:18:48.295

Yola
  • 18,496
  • 11
  • 65
  • 106