Outputting date in ISO 8601 format - c++

How can I get a date in the following format in C++:
2016-04-26T19:50:48Z
#include <chrono>
#include <ctime>
time_t _tm = time(NULL);
struct tm*curtime = localtime(&_tm);
And outputting as asctime(curtime)
The current output is: "Thu Apr 28 16:02:41 2016\n"

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

Based on #Uri's answer which fixes a few bugs and shows the time in the proper timezone along with the milliseconds in ISO8601 format:
auto now = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(now);
std::tm* now_tm = std::localtime(&time);
long long timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
std::cout << std::setfill('0')
<< std::put_time(now_tm, "%FT%H:%M:")
<< std::setw(2) << (timestamp / 1000) % 60 << '.'
<< std::setw(3) << timestamp % 1000
<< std::put_time(now_tm, "%z");

I'm combining the std::localtime which gives me calendar values, with std::chrono functions that gives me the precise methods. Here is my code:
#include <ctime>
#include <chrono>
...
auto now = std::chrono::system_clock::now();
auto now_c = std::chrono::system_clock::to_time_t(now)
auto now_tm = std::localtime(&now_c);
auto now_since_epoch = now.time_since_epoch(); // since 1970
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now_since_epoch).count();
std::cout << std::setfill('0') <<
std::setw(4) << now_tm->tm_year + 1900 << '-' <<
std::setw(2) << now_tm->tm_mon + 1 << '-' <<
std::setw(2) << now_tm->tm_mday << 'T' <<
std::setw(2) << now_ms % (24*60*60*1000) << ':' <<
std::setw(2) << now_ms % (60*60*1000) << ':' <<
std::setw(2) << now_ms % (60*1000) << '.' <<
std::setw(3) << now_ms % (1000);
Although verbose, it is actually doing less than strftime.

Related

Problems with conversion between mktime and gmtime_r

If I define a broken-down time using struct tm, then convert it to time_t using mktime and the result try to get back again as an struct tm I thought I was going to get the same result.
OK, maybe the first time something change because I define tm_isdst = -1 so mktime maybe affect that value, but not the second time.
The following code does that:
void print(const tm& t)
{
std::cout << t.tm_mday << '/'
<< t.tm_mon << '/'
<< t.tm_year << ' '
<< t.tm_hour << ':'
<< t.tm_min << ':'
<< t.tm_sec << "; "
<< t.tm_wday << '|'
<< t.tm_isdst << '\n';
}
int main(){
tm t;
t.tm_sec = 32;
t.tm_min = 22;
t.tm_hour = 0;
t.tm_mday = 6;
t.tm_mon = 0;
t.tm_year = 2023 - 1900;
t.tm_wday = 5;
t.tm_isdst = -1;
print(t);
time_t timet0 = mktime(&t);
std::cout << "time_t0 = " << timet0 << '\n';
gmtime_r(&timet0, &t);
print(t);
time_t timet1 = mktime(&t);
std::cout << "time_t1 - time_t0 = " << (timet1 - timet0) << '\n';
std::cout << "time_t1 = " << timet1 << '\n';
gmtime_r(&timet1, &t);
print(t);
timet1 = mktime(&t);
std::cout << "time_t = " << timet1 << '\n';
gmtime_r(&timet1, &t);
print(t);
}
And the result of executing it is
6/0/123 0:22:32; 5|-1
time_t0 = 1672960952
5/0/123 23:22:32; 4|0
time_t1 - time_t0 = -3600
time_t1 = 1672957352
5/0/123 22:22:32; 4|0
time_t = 1672953752
5/0/123 21:22:32; 4|0
Why am I losing an hour every time I call the pair mktime/gmtime_r?

How to measure execution time of a function?

I've searched SO and found relevant questions answered but I'm confused about the three different clock definitions. Considering I compile with Mingw on Windows;
I wonder whether the code below is OK or not? (I do not really need nanoseconds or microseconds precision; just testing...)
Which one should I use?
std::chrono::high_resolution_clock
std::chrono::system_clock
std::chrono::steady_clock
#include <iostream>
#include <chrono>
...
...
...
void printTimeElapsed(
std::chrono::high_resolution_clock::time_point t0,
std::chrono::high_resolution_clock::time_point t1)
{
int64_t hh; // hour
int64_t mm; // min
int64_t ss; // sec
int64_t ml; // millisec
int64_t mc; // microsec
int64_t ns; // nanosec
ns = std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0).count();
std::cout << ns << std::endl;
mc = ns / 1000;
ns %= 1000;
ml = mc / 1000;
mc %= 1000;
ss = ml / 1000;
ml %= 1000;
mm = ss / 60;
ss %= 60;
hh = mm / 60;
mm %= 60;
std::cout
<< std::setfill('0') << std::setw(3) << hh << ":"
<< std::setfill('0') << std::setw(2) << mm << ":"
<< std::setfill('0') << std::setw(2) << ss << "."
<< std::setfill('0') << std::setw(3) << ml << "."
<< std::setfill('0') << std::setw(3) << mc << "."
<< std::setfill('0') << std::setw(3) << ns << std::endl;
return;
}
...
...
...
int main(
int argc,
char *argv[])
{
std::chrono::high_resolution_clock::time_point t0;
std::chrono::high_resolution_clock::time_point t1;
...
...
t0 = std::chrono::high_resolution_clock::now();
/* call the function to be measured */
t1 = std::chrono::high_resolution_clock::now();
printTimeElapsed(t0, t1);
...
...
return (0);
}
system_clock is not steady: is subject to time adjustments.
high_resolution_clock is not guaranteed to be steady.
It means for users to use steady_clock for measurement, and because of this, implementers need to make the steady_clock of a high resolution.
Windows implementation of steady_clock should be based on QueryPerformanceCounter / QueryPerformanceFrequency, which is highest resolution of available API. This is true for MSVC, need to check for MinGW.

NTP timestamp is not correctly parsed c++

I want to send an SNTP req and then parse the response, hence I started by simply creating a timestamp convert it to ntp and then try to read the seconds and the fractional part. The issue is that the seconds part is not correctly parsed in the first place, always shifted by a few seconds. This is what I have done:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream> // Needed to perform IO operations
#include <ctime>
constexpr auto SECONDS_SINCE_FIRST_EPOCH = (2208988800ULL);
constexpr auto NTP_SCALE_FRAC = (4294967296ULL);
using namespace std;
int main()
{
std::time_t _timeEpoch = std::time(nullptr);
unsigned long long tv_ntp, tv_usecs, tv_time;
tv_ntp = _timeEpoch + SECONDS_SINCE_FIRST_EPOCH;
tv_usecs = (NTP_SCALE_FRAC * _timeEpoch) / 1000000UL;
tv_time = (tv_ntp << 32) | tv_usecs;
std::cout << "GetUtcTimeMilliSeconds UTC sec: " << _timeEpoch << " 1900: " << tv_ntp << " fraction of second " << tv_usecs << " tv_time " << tv_time << std::endl;
uint32_t msw = (tv_time >> 32) & 0xFFFFFFFF;
uint32_t lsw = tv_time & 0xFFFFFFFF;
std::cout << "GetUtcTimeMilliSeconds msw " << msw << " lsw: " << lsw << std::endl;
return 0;
}
I expected msw to be equal to tv_ntp and lsw to tv_usecs but they are not
GetUtcTimeMilliSeconds UTC sec: 1572103823 1900: 3781092623 fraction of second 6752134505701 tv_time 16239671495839982821
GetUtcTimeMilliSeconds msw 3781093167 lsw: 445916389

Converting chrono::duration type to std::tm type

I am writing a program that takes input a date from the user, uses it to initialize a tm struct, then using chrono::time_points performs some chrono::duration operation, such as getting the age.
Here is my code:
#include <iostream>
#include <chrono>
#include <ctime>
#include <iomanip>
using namespace std;
int main(){
//representing a date
tm *birthday = new tm{00, 30, 00, 07, 11, 97};
//convert to time t
time_t bt = mktime(birthday);
//convert time_t to time_point
chrono::system_clock::time_point t = chrono::system_clock::from_time_t(bt);
chrono::system_clock::time_point now = chrono::system_clock::now();
/*.. Testing
time_t nn = chrono::system_clock::to_time_t(now);
time_t tnn = chrono::system_clock::to_time_t(t);
*/
chrono::system_clock::duration lft = now - t;
//convert to timepoint
chrono::system_clock::time_point tlft{lft};
time_t lifetime = chrono::system_clock::to_time_t(tlft);
cout << put_time(localtime(&lifetime), "%F %T") << endl;
return 0;
}
And my output is something like this:
$> 1990-02-10 09:42:46
So, according to my understanding, it performs a plain mathematical subtraction on the ticks and using localtime, converts it to a date since EPOCH that is why it is giving me 1990. I want to know, is there any way, to convert the duration straight into struct tm, so that I should get something like 20 years?
Here is how you extract a duration in the unit of your choice:
std::chrono::duration<double> lft = now - t;
using year = std::chrono::duration<int, std::ratio<31557600>>;
auto nby = std::chrono::duration_cast<year>(lft);
std::cout << nby.count() << "\n";
With this in mind, I'll suggest an implementation of the taste of:
struct Age
{
using year = std::chrono::duration<int, std::ratio<31'557'600>>;
using month = std::chrono::duration<int, std::ratio< 2'592'000>>;
using day = std::chrono::duration<int, std::ratio< 86'400>>;
using hour = std::chrono::hours;
using minute = std::chrono::minutes;
using second = std::chrono::seconds;
Age(std::chrono::system_clock::time_point birth)
: _age(std::chrono::system_clock::now() - birth)
{}
template<class Duration>
auto extract()
{
const auto result = std::chrono::duration_cast<Duration>(_age);
_age -= result;
return result;
}
friend std::ostream& operator<<(std::ostream& os, Age age)
{
const auto years = age.extract<year>();
const auto monthes = age.extract<month>();
const auto days = age.extract<day>();
const auto hours = age.extract<hour>();
const auto minutes = age.extract<minute>();
const auto seconds = age.extract<second>();
return os << years.count()
<< ":" << std::setw(2) << std::setfill('0') << monthes.count()
<< ":" << std::setw(2) << std::setfill('0') << days.count()
<< " " << std::setw(2) << std::setfill('0') << hours.count()
<< ":" << std::setw(2) << std::setfill('0') << minutes.count()
<< ":" << std::setw(2) << std::setfill('0') << seconds.count()
;
}
private:
std::chrono::duration<double> _age;
};
Prints 20:01:10 12:43:40 with your example date (live demo).

C++ Boost convert UNIX Timestamp to MySQL compatible DATETIME String

I'm trying to convert a UNIX Timestamp which is in long to a Date Time string that needs to be stored in MySQL, in this format 2016-02-01 03:15:10
This is what i have so far. Its not working on the time extraction part. I couldn't find any constructor for boost::posix_time::time_duration that can take directly a boost::posix_time::ptime object. So i tried to include a workaround. But it doesn't work in the hours() part.
static inline std::string getDateTime(long timestamp) {
std::stringstream date_str;
boost::posix_time::ptime pt_1 = boost::posix_time::from_time_t(timestamp);
/* workaround to somehow get a time_duration object constructed */
boost::posix_time::ptime pt_temp = boost::posix_time::from_time_t(0);
boost::gregorian::date d = pt_1.date();
boost::posix_time::time_duration td = pt_1 - pt_temp;
/* construct the Date Time string */
date_str << d.year() << "-" << std::setw(2) << std::setfill('0') << d.month().as_number() << "-" << std::setw(2) << std::setfill('0') << d.day() << " "
<< td.hours() << ":" << td.minutes() << ":" << td.seconds();
return date_str.str();
}
With an Timestamp input such as 1455892259 i'm getting this 2016-02-19 404414:30:59 as a DateTime String from the function. How to actually get the correct Date Time string which in this case would be 2016-02-19 14:30:59. Using Boost for this is compulsory.
UPDATE
This is the final working function rewritten using the answer provided by Jarra McIntyre below.
static inline std::string getDateTime(long timestamp) {
std::stringstream date_str;
boost::posix_time::ptime pt_1 = boost::posix_time::from_time_t(timestamp);
boost::gregorian::date d = pt_1.date();
auto td = pt_1.time_of_day();
/* construct the Date Time string */
date_str << d.year() << "-" << std::setw(2) << std::setfill('0') << d.month().as_number() << "-" << std::setw(2) << std::setfill('0') << d.day() << " "
<< td.hours() << ":" << td.minutes() << ":" << td.seconds();
return date_str.str();
}
Use
auto td = pt_1.time_of_day();
There is no need for a workaround to get the time of day. The number of hours being displayed in your question is probably the number of hours between 1970-01-01 00:00 and 2016-02-19 14:00. For your method of getting the time_duration to work you would have to construct a ptime on the same day not at unix time 0.