C++ chrono: How do I convert an integer into a time point - c++

I managed to convert a time point into an integer and write it into a file using code that looks like the following code:
std::ofstream outputf("data");
std::chrono::time_point<std::chrono::system_clock> dateTime;
dateTime = std::chrono::system_clock::now();
auto dateTimeSeconds = std::chrono::time_point_cast<std::chrono::seconds>(toSerialize->dateTime);
unsigned long long int serializeDateTime = toSerialize->dateTime.time_since_epoch().count();
outputf << serializeDateTime << "\n";
Now I'm trying to read that integer from the file, convert it into a time_point, and print it. Right now, my code looks something like this:
std::ifstream inputf("data");
unsigned long long int epochDateTime;
inputf >> epochDateTime;
std::chrono::seconds durationDateTime(epochDateTime);
std::chrono::time_point<std::chrono::system_clock> dateTime2(durationDateTime);
std::time_t tt = std::chrono::system_clock::to_time_t(dateTime2);
char timeString[30];
ctime_s(timeString, sizeof(timeString), &tt);
std::cout << timeString;
However, it doesn't print anything. Does anyone know where I went wrong?

You have some strange conversions and assign to a variable that you don't use. If you want to store system_clock::time_points as std::time_ts and restore the time_points from those, don't involve other types and use the functions made for this: to_time_t and from_time_t. Also, check that opening the file and that extraction from the file works.
Example:
#include <chrono>
#include <ctime>
#include <fstream>
#include <iostream>
int main() {
{ // save a time_point as a time_t
std::ofstream outputf("data");
if(outputf) {
std::chrono::time_point<std::chrono::system_clock> dateTime;
dateTime = std::chrono::system_clock::now();
outputf << std::chrono::system_clock::to_time_t(dateTime) << '\n';
}
}
{ // restore the time_point from a time_t
std::ifstream inputf("data");
if(inputf) {
std::time_t epochDateTime;
if(inputf >> epochDateTime) {
// use epochDateTime with ctime-like functions if you want:
std::cout << std::ctime(&epochDateTime) << '\n';
// get the time_point back (usually rounded to whole seconds):
auto dateTime = std::chrono::system_clock::from_time_t(epochDateTime);
// ...
}
}
}
}

Putting aside the possibility of the wrong date value, the problem here is with sizeof(timeString). It appears that you think it is 30, but it in fact is the size of the char*, likely 8 (or maybe 4).
According to ctime_s:
the following errors are detected at runtime and call the currently installed constraint handler function:
buf or timer is a null pointer
bufsz is less than 26 or greater than RSIZE_MAX

Related

How to correctly read and increment dates in c++ using localtime and mktime?

I am struggling to execute a simple task. I want to take a date parameter from the command line argument and increment it several times by 1 day. The basic program should:
read the command line argument as the starting date, and
loop several times, incrementing that date by 1 day every time.
I convert the char* command line argument to a struct tm, then convert the struct tm to a time_t and add 60 * 60 * 24 = 1 day to it. I convert it back to struct tm to print it.
Here is the code:
#include <iostream>
#include <cstdlib>
#include <string>
#include "time.h"
int main(int argc, char *argv[])
{
char* start_date;
tm tm_start_date = {}; // solution: needs initialization
start_date = argv[1];
strptime(start_date, "%Y-%m-%d", &tm_start_date); // YYYY-MM-DD
char ch_stmt_date[11] = "";
time_t t_stmt_date = 0;
tm tm_stmt_date = {}; // solution: needs initialization;
tm_stmt_date = tm_start_date;
// time_t -> tm localtime_r(time_t, tm)
// tm -> time_t mktime(tm) returns time_t
std::cout << "start_date: " << start_date << " / tm_start_date: " << std::to_string(1900 + tm_start_date.tm_year) + std::to_string(tm_start_date.tm_mon + 1) +
std::to_string(tm_start_date.tm_mday) << std::endl;
// increment by 1 day per iteration
for (int i=0; i<5; i++)
{
// tm -> t_time
t_stmt_date = mktime(&tm_stmt_date);
std::cout << "t_stmt_date: " << t_stmt_date << std::endl;
// + 1 day
t_stmt_date += 60*60*24;
std::cout << "t_stmt_date: " << t_stmt_date << std::endl;
// time_t -> tm
localtime_r(&t_stmt_date, &tm_stmt_date);
strftime (ch_stmt_date, 11, "%Y-%m-%d", &tm_stmt_date);
std::cout << "ch_stmt_date: " << ch_stmt_date << std::endl;
}
return EXIT_SUCCESS;
}
The start date is correctly read and parsed into the struct tm.
However, subsequently I get one of two behaviors of the program:
Either I get a -1 on the first call of t_stmt_date = mktime(&tm_stmt_date); and a value of t_stmt_date: 86399 (1970-01-02) in the output. The rest of the loop then works correctly and iterates 5 times, incrementing 1970-01-02 by 1 day.
Or, the same code using the same command line parameter parses a nonsensical value on the first call of t_stmt_date = mktime(&tm_stmt_date); in the loop which is not a valid date, which, however is also correctly incremented by 60*60*24 on each of the 5 loops.
At this point I am desperate to understand the issue. I am working on Ubuntu 20.04 using gcc.
Thanks for your help.
Edit: Initializing the struct tm did the trick!
[NOTE]
You explicitly mention "using localtime and mktime" in the question's title, but I wasn't sure though after reading the rest of the text if that was mandatory, or you just needed to get a task done.
If you cannot use other libraries, just let me know and I'll remove this answer.
You could use std::chrono and Howard Hinnant's date library (C++11 onwards, header-only).
Or, should you be able to use a C++20 compiler, you would only need std::chrono.
[Demo]
#include <chrono>
#include <iostream> // cout
#include <sstream> // istringstream
#include <string>
#include "date/date.h"
int main()
{
namespace ch = std::chrono;
namespace dt = date;
const std::string start_date{"2022-01-31"}; // date
std::istringstream iss{ start_date }; // to string stream
dt::sys_days start_day{}; // to a time point with a day duration
dt::from_stream(iss, "%Y-%m-%d", start_day);
for (auto day{start_day}, end_day{start_day + dt::days{3}};
day < end_day;
day += dt::days{1}) // with which we can do date arithmetic
{
std::cout << dt::format("%Y-%m-%d\n", day);
}
}
// Outputs:
//
// 2022-01-31
// 2022-02-01
// 2022-02-02

Get std::chrono timestamp as string in %H.%M.%S format

I'm working on a logging system for my console, and I'm trying to get a timestamp for when a entry was added to the log. I tried doing this;
time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
char time_buffer[16] = { 0 };
std::strftime(time_buffer, sizeof(time_buffer), "%H.%M.%S", std::localtime(&now));
TextWrapped(time_buffer);
This almost works. The issue is that this works more as a clock then as a timestamp as it will not stay at the time of when the entry was logged, but increment... I think that I might have to use std::chrono::time_point, but I didn't really understand how to use it.
In C++20 there are a number of nice functions in std::chrono to do this:
#include <iostream>
#include <chrono>
#include <format>
int main()
{
// get the current time
auto now = std::chrono::system_clock::now();
// floor till the start of day
auto start_of_day = std::chrono::floor<std::chrono::days>(now);
// round time till nearest seconds
auto time_since_start_of_day = std::chrono::round<std::chrono::seconds>(now - start_of_day);
// convert to hour minute second type
std::chrono::hh_mm_ss hms { time_since_start_of_day };
std::cout << time_since_start_of_day << "\n"; // will output number of seconds since start of day
std::cout << hms << "\n"; // will output formatted time in hh:mm::ss
auto string = std::format("{}", hms);
std::cout << string << "\n"; // will output formatted time in hh:mm::ss
return 0;
}
So I figured it out.
The issue is that since my code snipped is in my render function, it will always update. My fix was to move the snippet above into my "add_log()" function, then write those timestamps into a new array, then in my for loop I would just grab from both arrays.
Kinda like so;
for (int i = 0; i < items.Size; i++) {
TextWrapped(items[i]);
TextWrapped(timestamps[i]);
}
It's a hacky solution, but it works.

Same function outputs different results when calculating difference between two timestamps

I'm currently facing a weird issue where the same function outputs a different result. The function is supposed to calculate the time difference between a provided date and the current time. Since this function is supposed to work with milliseconds, my function currently looks like this:
int calcDelay(std::string dropTime) {
struct tm tm;
std::istringstream iss(dropTime);
iss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S");
time_t time = mktime(&tm);
SYSTEMTIME t;
GetSystemTime(&t);
struct tm tm1;
memset(&tm1, 0, sizeof(tm1));
tm1.tm_year = t.wYear - 1900;
tm1.tm_mon = t.wMonth - 1;
tm1.tm_mday = t.wDay;
tm1.tm_hour = t.wHour - 1;
tm1.tm_min = t.wMinute;
tm1.tm_sec = t.wSecond;
time_t time2 = mktime(&tm1);
//std::cout << "Input:" << dropTime << " Output:" << (int)(difftime(time, time2) * 1000) - t.wMilliseconds << std::endl;
int retVal = (int)(difftime(time, time2) * 1000) - t.wMilliseconds;
return retVal;
}
The provided date (dropTime) is in UTC/GMT and the WinAPI function GetSystemTime should also return the time in UTC.
I have two different threads that call this function. When the first thread calls this function, it returns the correct time difference. However, when my other thread calls this function with the exactly same input it returns a value that is exactly 3600000 ms larger - this equals the time of exactly one hour.
What's the cause of this bug?
Edit: It seems that the bug is caused by the get_time function. Even though the same string (2021-05-25T21:03:04) is used to parse the time, it sometimes adds a hour and sometimes it doesn't...
Could it be that the get_time function simply cannot be used across multiple threads?
I appreciate all help.
In C++20 your calcDelay can be greatly simplified. And there exists a preview of this functionality in a free, open-source, header-only library1 which works with C++11/14/17.
#include "date/date.h"
#include <chrono>
#include <sstream>
int calcDelay(std::string dropTime) {
using std::chrono::milliseconds;
date::sys_time<milliseconds> time;
std::istringstream iss(dropTime);
iss >> date::parse("%Y-%m-%dT%H:%M:%S", time);
auto time2 = date::floor<milliseconds>(std::chrono::system_clock::now());
return (time - time2).count();
}
As you state in your question, the input is UTC, and the current time is UTC. Time zones are not involved. And unlike the "C version", this version optionally supports millisecond-precision input:
std::cout << calcDelay("2021-05-26T00:41:01.568") << '\n';
Output:
12456
To port the above calcDelay to C++20:
Drop #include "date/date.h"
Change date:: to std::chrono:: (3 places)
You can also (optionally) simplify the parse string from "%Y-%m-%dT%H:%M:%S" to "%FT%T".
Also optional, you could increase type safety in the client code by returning std::chrono::milliseconds instead of int.
1 Full disclosure: I am the lead author of this library. I am not pursuing any financial gain from this effort. But sometimes people get upset if I don't fully disclose this information.
t.wHour - 1 is incorrect. Both the tm and SYSTEMTIME structures use hours from 0...23.
According to std::get_time API, The I/O manipulator std::get_time uses the std::time_get facet of the I/O stream's locale to convert text input to a std::tm object. And maybe all of your threads which are in the same process have the same native locale which is default behavior. So GetSystemTime(&t); has no problem.
The follwing code is API’s example:
#include <iostream>
#include <sstream>
#include <locale>
#include <iomanip>
int main()
{
std::tm t = {};
std::istringstream ss("2011-Februar-18 23:12:34");
ss.imbue(std::locale("de_DE.utf-8"));
ss >> std::get_time(&t, "%Y-%b-%d %H:%M:%S");
if (ss.fail()) {
std::cout << "Parse failed\n";
} else {
std::cout << std::put_time(&t, "%c") << '\n';
}
}

convert minutes::rep to hours::rep

How should I proceed to convert std::chrono::minutes::rep type value to hours representation.
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
int main() {
minutes::rep time = 4;
std::cout << time; // outputs as minutes, need in hours
// duration cast doesn't seems to work here because it
// needs minutes instead of minutes::rep probably
return 0;
}
minutes::rep time = 4;
std::cout << time; // outputs as minutes, need in hours
Because time is just an (implementation-defined) integer type, it has nothing to do with minutes or hours, and doesn't know anything about underlying time representation.
You want to stay in the duration realm:
minutes time{4};
auto as_hours = std::duration_cast<hours>(time);
std::cout << as_hours.count(); // prints 0
Or, likely:
auto as_hours_dbl = std::duration_cast<duration<double, hours::period>>(time);
std::cout << as_hours_dbl.count(); // prints 0.0666667

How to get higher precision (fractions of a second) in a printout of current time?

I've tried a couple methods to print out time from the system_clock but I can't get anything other than whole seconds:
system_clock::time_point now = system_clock::now();
std::time_t now_c = system_clock::to_time_t(now);
std::cout<<ctime(&now_c);
std::cout<<std::put_time(std::localtime(&now_c), "%T")<<" ";
Does the now() function actually hold high precision data, or is that I just can't find the function that extracts that information for printing?
Note: I am not looking to calculate a time interval. I want the current time with fractions of a second, and to print it out via cout. I just can't find a way to do this.
And I know about std::chrono::high_resolution_clock but also see no way to print out its now(). Additionally, the setprecision function has no effect on the output of put_time or ctime.
I've been getting answers that do not actually address this question.
You can do the following:
#include <chrono>
#include <ctime>
#include <iostream>
#include <string>
std::string GetLocalTime() {
auto now(std::chrono::system_clock::now());
auto seconds_since_epoch(
std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()));
// Construct time_t using 'seconds_since_epoch' rather than 'now' since it is
// implementation-defined whether the value is rounded or truncated.
std::time_t now_t(
std::chrono::system_clock::to_time_t(
std::chrono::system_clock::time_point(seconds_since_epoch)));
char temp[10];
if (!std::strftime(temp, 10, "%H:%M:%S.", std::localtime(&now_t)))
return "";
return std::string(temp) +
std::to_string((now.time_since_epoch() - seconds_since_epoch).count());
}
int main() {
std::cout << GetLocalTime() << '\n';
return 0;
}
The existing answer is great, but it misses the leading zeros on the fractional part of the seconds, so 21:10:30.01 would be returned as 21:10:30.1
I don't have the rep to comment and my edit was rejected, so here's a fixed version:
#include <chrono>
#include <ctime>
#include <iostream>
#include <string>
std::string GetLocalTime() {
auto now(std::chrono::system_clock::now());
auto seconds_since_epoch(
std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()));
// Construct time_t using 'seconds_since_epoch' rather than 'now' since it is
// implementation-defined whether the value is rounded or truncated.
std::time_t now_t(
std::chrono::system_clock::to_time_t(
std::chrono::system_clock::time_point(seconds_since_epoch)));
char temp[10];
if (!std::strftime(temp, 10, "%H:%M:%S.", std::localtime(&now_t)))
return "";
std::string nanoseconds = std::to_string(
(std::chrono::duration<long long, std::nano>(
now.time_since_epoch() - seconds_since_epoch)).count());
return std::string(temp) + std::string(9-nanoseconds.length(),'0') + nanoseconds;
}
int main() {
std::cout << GetLocalTime() << '\n';
return 0;
}
Try std::chrono::high_resolution_clock.
(I think its c++11 only)