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();
Update for C++20:
This can now easily be done in C++20:
#include <chrono>
#include <format>
#include <iostream>
#include <string>
int
main()
{
using namespace std::chrono_literals;
std::chrono::time_point tp = std::chrono::sys_days{2016y/1/16} + 11h + 25min;
std::string s = std::format("{:%Y%m%d%H%M}", tp);
std::cout << s << '\n';
}
Output:
201601161125
Demo.
Original Answer:
Howard Hinnant's free, open source, header-only, portable date/time library is a modern way to do this that doesn't traffic through the old C API, and doesn't require that you discard all of your sub-second information. This library is also being proposed for standardization.
There is a lot of flexibility in formatting. The easiest way is to just stream out:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
std::cout << std::chrono::system_clock::now() << '\n';
}
This just output for me:
2017-09-15 13:11:34.356648
The using namespace date;
is required in order to find the streaming operator for the system_clock::time_point
(it isn't legal for my lib to insert it into namespace std::chrono
). No information is lost in this format: the full precision of your system_clock::time_point
will be output (microseconds
where I ran this on macOS).
The full suite of strftime
-like formatting flags is available for other formats, with minor extensions to handle things like fractional seconds. Here is another example that outputs with millisecond precision:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << format("%D %T %Z\n", floor<milliseconds>(system_clock::now()));
}
which just output for me:
09/15/17 13:17:40.466 UTC
Best Answer
A unix time stamp is defined as the number of seconds since January 1, 1970 UTC, except not counting all the seconds. This is somewhat ridiculous and one has to wonder what the point of it is, so I agree that this is a silly question.
Anyway, lets look at some platform documentation for
time_t
andtime()
.Linux:
Windows:
Mac OS X:
Similar documentation can be found for other systems, such as AIX, HP-UX, Solaris, etc.
So although not specified in C++ there is an easy and widely portable way to get a Unix timestamp:
And if you want a number of milliseconds since 1 Jan 1970 UTC (similarly not counting all of them) then you can do this:
Just remember that these values aren't real times, so you can't in general use unix timestamps in arithmetic. For example subtracting unix timestamps does not give you an accurate count of seconds between the times. Or if you did something like:
you would not get a time point actually corresponding to 1970-01-01 00:00:00+0000.
As Andy Prowl suggests you could do something silly like:
l
should now represent the (wrong) number of seconds since 1 Jan 1970 UTC. As long as there are no leap seconds between the system epoch and 1 Jan 1970 (system time zone), or within an equal amount of time in the other direction from the system epoch, then any counted leap seconds should cancel out andl
will be wrong in just the way that unix timestamps are wrong.Another option is to use a decent date library such as Howard Hinnant's
chrono::date
. (Howard Hinnant was one of the guys that worked on the C++11<chrono>
library.)If you want to handle leap seconds Howard Hinnant also provides a library that includes facilities for handling them as well as for parsing time zone databases as the source for leap second data.