Outputting Date and Time in C++ Using Std::Chrono

Outputting Date and Time in C++ using std::chrono

The <chrono> library only deals with time and not dates, except for the system_clock which has the ability to convert its timepoints to time_t. So using <chrono> for dates will not improve things much. Hopefully we get something like chrono::date in the not too distant future.

That said, you can use <chrono> in the following way:

#include <chrono>  // chrono::system_clock
#include <ctime> // localtime
#include <sstream> // stringstream
#include <iomanip> // put_time
#include <string> // string

std::string return_current_time_and_date()
{
auto now = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(now);

std::stringstream ss;
ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X");
return ss.str();
}

Note that std::localtime may cause data races. localtime_r or similar functions may be available on your platforms.

Update:

Using a new version of Howard Hinnant's date library you can write:

#include "date.h"
#include <chrono>
#include <string>
#include <sstream>

std::string return_current_time_and_date() {
auto now = std::chrono::system_clock::now();
auto today = date::floor<days>(now);

std::stringstream ss;
ss << today << ' ' << date::make_time(now - today) << " UTC";
return ss.str();
}

This will print out something like "2015-07-24 05:15:34.043473124 UTC".


On an unrelated note, returning const objects has become undesirable with C++11; const return values cannot be moved from. I also removed the trailing const because trailing const is only valid for member functions and this function has no need to be a member.

A class for date and time representation in C++11

Since I cannot use C++20 I ended up with this C++11 minimal std::chrono based implementation:

utctime.h

#include <chrono>
#include <string>

struct UTCClock
{
typedef std::chrono::microseconds duration;
typedef duration::rep rep;
typedef duration::period period;
typedef std::chrono::time_point<UTCClock, duration> time_point;
static const bool is_steady = true;

//
// every time_point will be generated from here
//
static time_point fromDate(int year= 0, int month= 0, int day= 0,
int hour= 0, int min = 0, int sec= 0,
int usec= 0);
//
// convert time_point to a date/time representation
//
static void toDate(const time_point &tp,
int &year, int &month, int &day,
int &hour, int &min, int &sec,
int &usec);

// NOT Supported, we don't need current time. We only
// want to represent UTC DateTime
// static time_point now();
};

using UTCTime = std::chrono::time_point<UTCClock, std::chrono::microseconds>;

utctime.cpp

#include "utctime.h"
#include <ctime>

namespace chrono = std::chrono;
using chrono::duration_cast;
using chrono::time_point_cast;

namespace {

std::time_t to_time_t(const UTCClock::time_point &tp) noexcept
{
return std::time_t(
duration_cast<chrono::seconds>(tp.time_since_epoch()).count());
}

UTCClock::time_point from_time_t(std::time_t tt) noexcept
{
return time_point_cast<UTCClock::duration>(
chrono::time_point<UTCClock,chrono::seconds>(chrono::seconds(tt)));
}

} // namespace

UTCClock::time_point UTCClock::fromDate(
int year, int month, int day, int hour, int min, int sec, int usec)
{
std::tm tm = {0};
tm.tm_year = year - 1900;
tm.tm_mon = month - 1;
tm.tm_mday = day;
tm.tm_hour = hour;
tm.tm_min = min;
tm.tm_sec = sec;
tm.tm_isdst = -1;
std::time_t tt = timegm(&tm);
return from_time_t(tt) + chrono::microseconds(usec);
}

void UTCClock::toDate(const UTCClock::time_point &tp,
int &year,
int &month,
int &day,
int &hour,
int &min,
int &sec,
int &usec)
{
std::time_t tt = to_time_t(tp);
std::tm tm;
gmtime_r(&tt, &tm);
year = tm.tm_year + 1900;
month = tm.tm_mon + 1;
day = tm.tm_mday;
hour = tm.tm_hour;
min = tm.tm_min;
chrono::microseconds leftover =
tp - from_time_t(tt) + chrono::seconds(tm.tm_sec);
sec = duration_cast<chrono::seconds>(leftover).count();
usec = (leftover-chrono::seconds(sec)).count();
}

It can be used like this:

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

using namespace std::chrono;

int main(int argc, char* argv[])
{
//
// use UTCClock::fromDate to generate a UTCTime
//
UTCTime t1 = UTCClock::fromDate(1901, 1, 1, 0, 0, 0, 0);
UTCTime t2 = UTCClock::fromDate(1901, 1, 1, 1, 0, 0, 0);

//
// Then we can make use of std::chrono algebra like
// subtracting time_point
//
microseconds timeDiff = t2 -t1;

std::cout << "t2-t1 difference in microseconds " <<
timeDiff.count() << std::endl;
std::cout << "t2-t1 difference in hours " <<
duration_cast<hours>(timeDiff).count() << std::endl;

//
// ...or adding/subtracting a duration to a time_point
//
UTCTime t3 = t1 - minutes{3};
std::cout << "t3-t1 difference in minutes " <<
duration_cast<minutes>(t3-t1).count() << std::endl;

t3 = t1 + milliseconds{123};
std::cout << "t3-t1 difference in milliseconds " <<
duration_cast<milliseconds>(t3-t1).count() << std::endl;

//
// ...we can also compare time_points
//
if ( t3 > t1 ) std::cout << "t3 is greater than t1" << std::endl;

//
// We can get a date/time back from a time_point with UTCClock::toDate
//
int year, month, day, hour, min, sec, usec;
UTCClock::toDate(t3, year, month, day, hour, min, sec, usec);

//
// std::chrono is also type safe and doesn't allow to
// mix dates generated by different clocks
//
system_clock::time_point systp = system_clock::now();

// NO: doesn't compile
// auto tx = t1 - systp;

// NO: doesn't compile
// if (t1 < systp);

// NO: doesn't compile
// UTCClock::toDate(systp, year, month, day, hour, min, sec, usec);

return 0;
}

Output:

t2-t1 difference in microseconds 3600000000
t2-t1 difference in hours 1
t3-t1 difference in minutes -3
t3-t1 difference in milliseconds 123
t3 is greater than t1

How to get current time and date in C++?

Since C++ 11 you can use std::chrono::system_clock::now()

Example (copied from en.cppreference.com):

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

int main()
{
auto start = std::chrono::system_clock::now();
// Some computation here
auto end = std::chrono::system_clock::now();

std::chrono::duration<double> elapsed_seconds = end-start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);

std::cout << "finished computation at " << std::ctime(&end_time)
<< "elapsed time: " << elapsed_seconds.count() << "s"
<< std::endl;
}

This should print something like this:

finished computation at Mon Oct  2 00:59:08 2017
elapsed time: 1.88232s

How can I input a set start and end time using Chrono or ctime libaray

The std::tm* returned from std::localtime is not a good place to store data in. Note that all the different offsets in the std::tm struct are well documented.

Using only year, month and weekday as you do isn't really enough. There are more than one day in each month having a Saturday for example.

You can do like this:

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

int main() {
std::tm now{}; // declare and initialize your own tm
std::chrono::system_clock::time_point cc;

std::cout << "enter\nyear month day\n";

std::cin >> now.tm_year >> now.tm_mon >> now.tm_mday;

// compensate for offsets
now.tm_year -= 1900;
now.tm_mon -= 1;

// convert to std::time_t
std::time_t n = std::mktime(&now);

// here you get a chrono time_point from the user input
cc = std::chrono::system_clock::from_time_t(n);

// convert back to std::time_t
n = std::chrono::system_clock::to_time_t(cc);

// print the result
std::cout << std::put_time(std::localtime(&n), "%FT%T") << "\n";
}

Example input/output:

enter
year month day
2019 11 20
2019-11-20T00:00:00

How to convert std::chrono::time_point to calendar datetime string with fractional seconds?

If system_clock, this class have time_t conversion.

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

using namespace std::chrono;

int main()
{
system_clock::time_point p = system_clock::now();

std::time_t t = system_clock::to_time_t(p);
std::cout << std::ctime(&t) << std::endl; // for example : Tue Sep 27 14:21:13 2011
}

example result:

Thu Oct 11 19:10:24 2012

EDIT:
But, time_t does not contain fractional seconds.
Alternative way is to use time_point::time_since_epoch() function. This function returns duration from epoch.
Follow example is milli second resolution's fractional.

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

using namespace std::chrono;

int main()
{
high_resolution_clock::time_point p = high_resolution_clock::now();

milliseconds ms = duration_cast<milliseconds>(p.time_since_epoch());

seconds s = duration_cast<seconds>(ms);
std::time_t t = s.count();
std::size_t fractional_seconds = ms.count() % 1000;

std::cout << std::ctime(&t) << std::endl;
std::cout << fractional_seconds << std::endl;
}

example result:

Thu Oct 11 19:10:24 2012

925

Output time and date with fractional time without using C++11

Using localtime and this post Getting current time with milliseconds:

#include <time.h>
#include <cstdio> // handle type conversions
#include <sys/time.h>

int main (void) {

timeval curTime;
gettimeofday(&curTime, NULL);
int milli = curTime.tv_usec / 1000;

char buffer [80];
strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", localtime(&curTime.tv_sec));

char currentTime[84] = "";
sprintf(currentTime, "%s.%d", buffer, milli);
printf("current date time: %s \n", currentTime);

return 0;
}

outputs:

current date time: 2018-01-28 14:45:52.486

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

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).

How to convert std::chrono::time_point to string

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

C++ Errors involving outputting chrono duration

In C++11/14/17, there is no streaming operator for chrono::duration types. You have two choices:

  1. Extract the .count():

|

 os << right.eR[i].duration.count() << "s ";

  1. Use this open-source, header-only date/time library:

|

#include "date/date.h"
// ...
using date::operator<<;
os << right.eR[i].duration << " ";

The above datelib is now part of C++20, but is not yet shipping. Vendors are working on it. When you port to it, you can just drop the #include "date/date.h" and using date::operator<<;.

Outputting date in ISO 8601 format

Documentation is your friend:

std::time_t t
= std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::cout << std::put_time( std::localtime( &t ), "%FT%T%z" );

in my system yields

2016-04-29T02:48:56+0200


Related Topics



Leave a reply



Submit