Trying to convert postgres time stamp string to c++ time stamp - c++

I have PostgreSQL timestamp string:
2020-07-06 09:30:00.646533
I'm trying to convert it to timeval struct, I tried using this answer, but I'm getting this output:
Thu Jan 1 00:33:40 1970
This is my code:
#include <iostream>
int main()
{
std::string ss("2020-07-06 09:30:00.646533");
auto t = atoll(ss.c_str());
time_t time = atoi(ss.c_str());
std::cout << asctime(gmtime(&time));
return 0;
}
When running with debugger, I see that this line
auto t = atoll(ss.c_str());
isn't working/set time with values.
How can i fix it?

atoll and atoi simply parse integers of various sizes from a string. They aren't great functions to use in general as they have no way of indicating that they have failed to parse the string. std::stoi and friends are the better functions to use. However in this case we don't have a number we have a date string so std::stoi won't work either (but it can at least tell you it didn't work).
c++20 comes with much better date support, until then Howard Hinnant's date library provides the same functionality:
#include "date.h"
#include <iostream>
#include <sstream>
#include <chrono>
int main()
{
std::stringstream ss("2020-07-06 09:30:00.646533");
// convert string to date time
std::chrono::system_clock::time_point time;
ss >> date::parse("%F %T", time);
if (!ss) {
std::cout << "invalid date\n";
return 1;
}
// get the amount of time since the epoch, assumes std::chrono::system_clock uses the same epoch as timeval
auto sinceEpoch = time.time_since_epoch();
// get the whole number of seconds
auto seconds = date::floor<std::chrono::seconds>(sinceEpoch);
// get the remaining microseconds
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(sinceEpoch - seconds);
std::cout << seconds.count() << ", " << microseconds.count() << "\n";
return 0;
}
If you must re-invent the wheel you can do it using the pre c++20 standard library:
#include <iostream>
#include <sstream>
#include <chrono>
#include <iomanip>
int main()
{
std::stringstream ss("2020-07-06 09:30:00.646533");
std::tm tm;
// convert string to date time
std::chrono::system_clock::time_point time;
double fraction;
ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S") >> fraction;
if (!ss) {
std::cout << "invalid date\n";
return 1;
}
time_t seconds = mktime(&tm);
int64_t microseconds = fraction * 1'000'000;
std::cout << seconds << ", " << microseconds << "\n";
return 0;
}
Note that the microseconds should really be parsed as an integer not a double but you have to be careful to handle strings with different numbers of digits after the decimal point and with leading zeros.

you can use like this:
#include<ctime>
#include<iotream>
int main()
{
std::string ss = "2020-07-06 09:30:00.646533";
auto i = ss.find_first_of('.');
std::string line(ss.begin()+(i+1),ss.end());
std::tm tm = {};
tm.tm_isdst = -1; // <- to set not to use day lghite saveing.
strptime(ss.c_str(), "%F %H:%M:%S", &tm); //<-enter the data to tm
start.tv_sec = mktime(&tm); //<-convert tm to time_t
start.tv_usec = stoi(line); // <- set the usec from the stirng
//IF you want the other why around
strftime(tmbuf, sizeof tmbuf, " %F %H:%M:%S", localtime(&start.tv_sec));
snprintf(buf, sizeof buf, "%s.%06ld", tmbuf, start.tv_usec);
std::cout << tmbuf;
return 0;
}
output:
2020-07-06 09:30:00.646533

Related

Converting epoch time to formatted GMT and back C++

I'm trying to convert epoch time to formatted GMT string and back. The first conversion is correct. I verified by https://www.epochconverter.com/
However, when I convert the formatted GMT back to epoch time, the result is incorrect at minute & second. The function get_time() seems to be correct but timegm() is not. Here is my code:
#include <string>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <time.h>
void cvt_epoch2formatGmt(double ts, std::string& format){
time_t timestamp = time_t(ts);
char time_buf[80];
struct tm gmt;
gmt = *gmtime(&timestamp);
strftime(time_buf, sizeof(time_buf), "%Y%m%d_%H%M%S", &gmt);
format = time_buf;
}
double cvt_formatGmt2epoch(const std::string& formatted_ts){
std::tm tm;
std::stringstream ss(formatted_ts);
ss >> std::get_time(&tm, "%Y%m%d_%H%M%S");
double epoch = timegm(&tm);
return epoch;
}
int main(){
std::string format;
double ts = 1671686472;
cvt_epoch2formatGmt(ts, format);
std::cout << format << std::endl;
double epoch = cvt_formatGmt2epoch(format);
std::cout << std::fixed << epoch << std::endl;
if (std::abs(epoch-ts) > 1){
std::cout << "wrong conversion" << std::endl;
return 1;
}
return 0;
}
Updated: I made wrong at return type (float) of the function cvt_formatGmt2epoch(). It must be the double. I updated the code, and it works correct now
float is not precise enough, so the result of timegm is rounded by returning from cvt_formatGmt2epoch. Use double as the return type.
Even better, use time_t, it's the return type of timegm and it's an integer so you avoid a myriad of other problems with floating-point numbers, year 2038, etc.

How to convert a "%Y%m%d" format string into a time_t variable in C++?

I'm trying to convert strings into time_t variables. Here's the code I tried:
#include "pch.h"
#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>
using namespace std;
time_t String_to_timet1(string endDate) {
tm tm = { 0 };
stringstream ss(endDate);
ss >> get_time(&tm, "%Y-%m-%d %H:%M:%S");
time_t epoch = mktime(&tm);
return epoch;
}
time_t String_to_timet2(string endDate) {
tm tm = { 0 };
stringstream ss(endDate);
ss >> get_time(&tm, "%Y%m%d");
time_t epoch = mktime(&tm);
return epoch;
}
int main()
{
time_t time_certainTime1 = String_to_timet1("2019-01-01 00:00:00");
cout << time_certainTime1 << endl;
time_t time_certainTime2 = String_to_timet2("20190101");
cout << time_certainTime2 << endl;
return 0;
}
I expected that the results would be the same, but when I run the code with Visual Studio 2017, the results are:
1546268400
-1
and when I run the same code on https://www.onlinegdb.com/online_c++_compiler, the results are:
1546300800
1546300800
Question: Why does Visual Studio give me -1 when it gets a "%Y%m%d" typed string (when the online compiler gives me the result I expected)? How to make a time_t variable with such format?
In the documentation for both %m and %d it says leading zeros permitted but not required. This means that it's actually underspecified if it will work without separators or not.

Parse date string to remove hours, minutes and seconds from timestamp

Suppose I receive from a web server a string to parse. This string contains a date in the format YYYY-MM-DD.
What I want is to convert it to the timestamp that represents the begin of that day, hence I don't want seconds, minutes and hours.
As a dummy example, I'm trying to extract the timestamp of the current day, once converted to the YYYY-MM-DD format. Here's the code:
#include <chrono>
#include <iomanip>
#include <iostream>
#include <sstream>
int main()
{
// Current time at GMT
std::time_t now = std::time(0);
std::tm *now_tm = std::gmtime(&now);
std::ostringstream oss;
// Extract yyyy-mm-dd = %F
oss << std::put_time(now_tm, "%F");
// Use oss to get a date without seconds from
// current time at gmt
std::tm tm;
std::istringstream ss(oss.str());
ss >> std::get_time(&tm, "%F");
std::time_t current_date = std::mktime(&tm);
std::cout << oss.str() << std::endl;
std::cout << "cd: " << current_date << std::endl;
return 0;
}
The output is:
2017-10-19
cd: 1908337984324104
The extracted timestamp is clearly wrong. Where's the problem in the parsing the 2017-10-19 string using the %F format?
You can do this without leaving the safety of the chrono type system by using Howard Hinnant's, free, open-source, header-only chrono-extension library.
#include "date/date.h"
#include <iostream>
int
main()
{
std::istringstream ss{"2017-10-19"};
date::sys_seconds tp;
ss >> date::parse("%F", tp);
std::cout << date::format("%F\n", tp);
using date::operator<<;
std::cout << "cd: " << tp.time_since_epoch() << '\n';
}
date::sys_seconds is a std::chrono::time_point that counts chrono::seconds in Unix Time. You can parse directly into it using %F. You can also format it, using the same format string (%F), and also inspect the underlying count of chrono::seconds. This program outputs:
2017-10-19
cd: 1508371200s
The documentation of std::get_time lists no conversion specifier %F. When checking the stream flag (which you always should do!), it will also tell that the conversion failed, at least with my compiler.
So by replacing it with %Y-%m-%d, the conversion succeeds. Finally, you default-constructed the tm variable without zeroing it (e.g. by value-initialization). When fixing this as well, the code works as expected:
#include <chrono>
#include <iomanip>
#include <iostream>
#include <sstream>
int main()
{
// Current time at GMT
std::time_t now = std::time(0);
std::tm *now_tm = std::gmtime(&now);
std::ostringstream oss;
// Extract yyyy-mm-dd = %F
oss << std::put_time(now_tm, "%Y-%m-%d");
// Use oss to get a date without seconds from
// current time at gmt
std::tm tm{ }; // value-initialize!
std::istringstream ss(oss.str());
ss >> std::get_time(&tm, "%Y-%m-%d");
if(!ss) std::cout << "conversion error\n";
else {
std::time_t current_date = std::mktime(&tm);
std::cout << current_date << '\n';
std::cout << "cd: " << current_date << '\n';
}
return 0;
}
http://coliru.stacked-crooked.com/a/d86aa1e1d890a14d

How to correctly add the date to the date?

I'm new in C++, and i have a problem with Unixtime adding. For example, I have a date 8.10.2014 14:49
I need to add 26 days, 12 hours, 44 minutes to it. This is my code:
#include <iostream>
#include <ctime>
struct Date {
int Minute;
int Hour;
int Day;
int Month;
int Year;
};
int main(){
time_t rawtime;
struct tm * timeinfo;
Date startDate;
std::cin >> startDate.Year;
std::cin >> startDate.Month;
std::cin >> startDate.Day;
std::cin >> startDate.Hour;
std::cin >> startDate.Minute;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
timeinfo->tm_year = startDate.Year - 1900;
timeinfo->tm_mon = startDate.Month -1;
timeinfo->tm_mday = startDate.Day;
timeinfo->tm_hour = startDate.Hour;
timeinfo->tm_min = startDate.Minute;
rawtime = mktime ( timeinfo ) + 2555027;
std::cout << rawtime << std::endl;
struct tm *tm = localtime(&rawtime);
char date[80];
strftime(date, sizeof(date), "%Y %m %d %H %M", tm);
std::cout << date;
}
The answers is approximately similar to the truth, but don't correct. Why?
If you have C++11 (or C++14) and a relatively up-to-date compiler, you can use this library:
http://howardhinnant.github.io/date/tz.html
like so:
#include <chrono>
#include <iostream>
#include "tz.h"
int
main()
{
using namespace date;
using namespace std::chrono_literals;
auto zone = current_zone();
auto time = make_zoned(current_zone(), local_days{8_d/10/2014} + 14h + 49min);
time = time.get_sys_time() + days{26} + 12h + 44min;
std::cout << time << '\n';
}
This is roughly equivalent to what you have, which assumes that the date you specified is in your computer's local timezone, and that you also want the results in your computer's local timezone. For me this outputs:
2014-11-04 02:33:00 EST
However you also mentioned "Unixtime", which to me means Unix time. This time is measured in UTC, which lacks complications such as daylight saving time. If it is the intent to do this in Unix time, you can do this more easily and cheaply with this library:
http://howardhinnant.github.io/date/date.html
like this:
#include <chrono>
#include <iostream>
#include "date.h"
int
main()
{
using namespace date;
using namespace std::chrono_literals;
auto time = sys_days{8_d/10/2014} + 14h + 49min + days{26} + 12h + 44min;
std::cout << time << '\n';
}
which will portably output:
2014-11-04 03:33
The use of the "chrono literals" (e.g. 14h) implies C++14. If you are in C++11, you can substitute in the more verbose hours{14} (hours is in namespace std::chrono). If you are in C++03, well, then, never mind. :-)

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

How to convert std::chrono::time_point to calendar datetime string with fractional seconds?
For example:
"10-10-2012 12:38:40.123456"
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
Self-explanatory code follows which first creates a std::tm corresponding to 10-10-2012 12:38:40, converts that to a std::chrono::system_clock::time_point, adds 0.123456 seconds, and then prints that out by converting back to a std::tm. How to handle the fractional seconds is in the very last step.
#include <iostream>
#include <chrono>
#include <ctime>
int main()
{
// Create 10-10-2012 12:38:40 UTC as a std::tm
std::tm tm = {0};
tm.tm_sec = 40;
tm.tm_min = 38;
tm.tm_hour = 12;
tm.tm_mday = 10;
tm.tm_mon = 9;
tm.tm_year = 112;
tm.tm_isdst = -1;
// Convert std::tm to std::time_t (popular extension)
std::time_t tt = timegm(&tm);
// Convert std::time_t to std::chrono::system_clock::time_point
std::chrono::system_clock::time_point tp =
std::chrono::system_clock::from_time_t(tt);
// Add 0.123456 seconds
// This will not compile if std::chrono::system_clock::time_point has
// courser resolution than microseconds
tp += std::chrono::microseconds(123456);
// Now output tp
// Convert std::chrono::system_clock::time_point to std::time_t
tt = std::chrono::system_clock::to_time_t(tp);
// Convert std::time_t to std::tm (popular extension)
tm = std::tm{0};
gmtime_r(&tt, &tm);
// Output month
std::cout << tm.tm_mon + 1 << '-';
// Output day
std::cout << tm.tm_mday << '-';
// Output year
std::cout << tm.tm_year+1900 << ' ';
// Output hour
if (tm.tm_hour <= 9)
std::cout << '0';
std::cout << tm.tm_hour << ':';
// Output minute
if (tm.tm_min <= 9)
std::cout << '0';
std::cout << tm.tm_min << ':';
// Output seconds with fraction
// This is the heart of the question/answer.
// First create a double-based second
std::chrono::duration<double> sec = tp -
std::chrono::system_clock::from_time_t(tt) +
std::chrono::seconds(tm.tm_sec);
// Then print out that double using whatever format you prefer.
if (sec.count() < 10)
std::cout << '0';
std::cout << std::fixed << sec.count() << '\n';
}
For me this outputs:
10-10-2012 12:38:40.123456
Your std::chrono::system_clock::time_point may or may not be precise enough to hold microseconds.
Update
An easier way is to just use this date library. The code simplifies down to (using C++14 duration literals):
#include "date.h"
#include <iostream>
#include <type_traits>
int
main()
{
using namespace date;
using namespace std::chrono;
auto t = sys_days{10_d/10/2012} + 12h + 38min + 40s + 123456us;
static_assert(std::is_same<decltype(t),
time_point<system_clock, microseconds>>{}, "");
std::cout << t << '\n';
}
which outputs:
2012-10-10 12:38:40.123456
You can skip the static_assert if you don't need to prove that the type of t is a std::chrono::time_point.
If the output isn't to your liking, for example you would really like dd-mm-yyyy ordering, you could:
#include "date.h"
#include <iomanip>
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
using namespace std;
auto t = sys_days{10_d/10/2012} + 12h + 38min + 40s + 123456us;
auto dp = floor<days>(t);
auto time = make_time(t-dp);
auto ymd = year_month_day{dp};
cout.fill('0');
cout << ymd.day() << '-' << setw(2) << static_cast<unsigned>(ymd.month())
<< '-' << ymd.year() << ' ' << time << '\n';
}
which gives exactly the requested output:
10-10-2012 12:38:40.123456
Update
Here is how to neatly format the current time UTC with milliseconds precision:
#include "date.h"
#include <iostream>
int
main()
{
using namespace std::chrono;
std::cout << date::format("%F %T\n", time_point_cast<milliseconds>(system_clock::now()));
}
which just output for me:
2016-10-17 16:36:02.975
C++17 will allow you to replace time_point_cast<milliseconds> with floor<milliseconds>. Until then date::floor is available in "date.h".
std::cout << date::format("%F %T\n", date::floor<milliseconds>(system_clock::now()));
Update C++20
In C++20 this is now simply:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
auto t = sys_days{10d/10/2012} + 12h + 38min + 40s + 123456us;
std::cout << t << '\n';
}
Or just:
std::cout << std::chrono::system_clock::now() << '\n';
std::format will be available to customize the output.
In general, you can't do this in any straightforward fashion. time_point is essentially just a duration from a clock-specific epoch.
If you have a std::chrono::system_clock::time_point, then you can use std::chrono::system_clock::to_time_t to convert the time_point to a time_t, and then use the normal C functions such as ctime or strftime to format it.
Example code:
std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(tp);
std::tm timetm = *std::localtime(&time);
std::cout << "output : " << std::put_time(&timetm, "%c %Z") << "+"
<< std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count() % 1000 << std::endl;
This worked for me for a format like YYYY.MM.DD-HH.MM.SS.fff. Attempting to make this code capable of accepting any string format will be like reinventing the wheel (i.e. there are functions for all this in Boost.
std::chrono::system_clock::time_point string_to_time_point(const std::string &str)
{
using namespace std;
using namespace std::chrono;
int yyyy, mm, dd, HH, MM, SS, fff;
char scanf_format[] = "%4d.%2d.%2d-%2d.%2d.%2d.%3d";
sscanf(str.c_str(), scanf_format, &yyyy, &mm, &dd, &HH, &MM, &SS, &fff);
tm ttm = tm();
ttm.tm_year = yyyy - 1900; // Year since 1900
ttm.tm_mon = mm - 1; // Month since January
ttm.tm_mday = dd; // Day of the month [1-31]
ttm.tm_hour = HH; // Hour of the day [00-23]
ttm.tm_min = MM;
ttm.tm_sec = SS;
time_t ttime_t = mktime(&ttm);
system_clock::time_point time_point_result = std::chrono::system_clock::from_time_t(ttime_t);
time_point_result += std::chrono::milliseconds(fff);
return time_point_result;
}
std::string time_point_to_string(std::chrono::system_clock::time_point &tp)
{
using namespace std;
using namespace std::chrono;
auto ttime_t = system_clock::to_time_t(tp);
auto tp_sec = system_clock::from_time_t(ttime_t);
milliseconds ms = duration_cast<milliseconds>(tp - tp_sec);
std::tm * ttm = localtime(&ttime_t);
char date_time_format[] = "%Y.%m.%d-%H.%M.%S";
char time_str[] = "yyyy.mm.dd.HH-MM.SS.fff";
strftime(time_str, strlen(time_str), date_time_format, ttm);
string result(time_str);
result.append(".");
result.append(to_string(ms.count()));
return result;
}
I would have put this in a comment on the accepted answer, since that's where it belongs, but I can't. So, just in case anyone gets unreliable results, this could be why.
Be careful of the accepted answer, it fails if the time_point is before the epoch.
This line of code:
std::size_t fractional_seconds = ms.count() % 1000;
will yield unexpected values if ms.count() is negative (since size_t is not meant to hold negative values).
In my case I use chrono and c function localtime_r which is thread-safe (in opposition to std::localtime).
#include <iostream>
#include <chrono>
#include <ctime>
#include <time.h>
#include <iomanip>
int main() {
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::chrono::milliseconds now2 = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
struct tm currentLocalTime;
localtime_r(&currentTime, &currentLocalTime);
char timeBuffer[80];
std::size_t charCount { std::strftime( timeBuffer, 80,
"%b %d %T",
&currentLocalTime)
};
if (charCount == 0) return -1;
std::cout << timeBuffer << "." << std::setfill('0') << std::setw(3) << now2.count() % 1000 << std::endl;
return 0;
}
If you are to format a system_clock::time_point in the format of numpy datetime64, you could use:
std::string format_time_point(system_clock::time_point point)
{
static_assert(system_clock::time_point::period::den == 1000000000 && system_clock::time_point::period::num == 1);
std::string out(29, '0');
char* buf = &out[0];
std::time_t now_c = system_clock::to_time_t(point);
std::strftime(buf, 21, "%Y-%m-%dT%H:%M:%S.", std::localtime(&now_c));
sprintf(buf+20, "%09ld", point.time_since_epoch().count() % 1000000000);
return out;
}
sample output: 2019-11-19T17:59:58.425802666