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(×tamp);
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.
Related
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
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.
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
I have a requirement where I have to convert given string in date time format to milliseconds from epoch.
In Javascript there is date to time conversion api but in c++ I couldn't find anything as such.
Input would look like '2016-Mar-15 09:23:58.665068'
output should be in milliseconds say 14520000785.
I have tried looking into boost but still couldn't find(or understand) how to do?
Also, going through google I find the other way round i.e. converting milliseconds to date format but not what I require nor any helpful post for same.
Any help will be much appreciated.
Using only standard library features:
#include <ctime>
#include <chrono>
#include <iostream>
int main()
{
std::tm tm = {};
const char* snext = ::strptime("2016-Mar-15 09:23:58.665068", "%Y-%b-%d %H:%M:%S", &tm);
auto time_point = std::chrono::system_clock::from_time_t(std::mktime(&tm));
long long duration_ms = time_point.time_since_epoch() / std::chrono::milliseconds(1) + std::atof(snext) * 1000.0f;
std::cout << duration_ms << std::endl;
}
Prints: 1458033838665
See std::chrono::system_clock::now and std::chrono::milliseconds.
Most straightforward would be to just spell it out:
auto pt = boost::lexical_cast<ptime>("2016-Mar-15 09:23:58.665068");
std::cout << (pt - ptime { {1970,0,0}, {} }).total_milliseconds();
Live On Coliru
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/date_time.hpp>
#include <sstream>
int main() {
using boost::posix_time::ptime;
ptime pt;
{
std::istringstream iss("2016-Mar-15 09:23:58.665068");
auto* f = new boost::posix_time::time_input_facet("%Y-%b-%d %H:%M:%S%f");
std::locale loc(std::locale(""), f);
iss.imbue(loc);
iss >> pt;
}
std::cout << pt << " " << (pt - ptime{{1970,1,1},{}}).total_milliseconds();
}
Prints
2016-Mar-15 09:23:58.665068 1458033838665
Of course, extract the parsing in a helper function. Keep the locale around for reuse etc.
time_t seconds;
time(&seconds);
cout << seconds << endl;
This gives me a timestamp. How can I get that epoch date into a string?
std::string s = seconds;
does not work
Try std::stringstream.
#include <string>
#include <sstream>
std::stringstream ss;
ss << seconds;
std::string ts = ss.str();
A nice wrapper around the above technique is Boost's lexical_cast:
#include <boost/lexical_cast.hpp>
#include <string>
std::string ts = boost::lexical_cast<std::string>(seconds);
And for questions like this, I'm fond of linking The String Formatters of Manor Farm by Herb Sutter.
UPDATE:
With C++11, use to_string().
Try this if you want to have the time in a readable string:
#include <ctime>
std::time_t now = std::time(NULL);
std::tm * ptm = std::localtime(&now);
char buffer[32];
// Format: Mo, 15.06.2009 20:20:00
std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm);
For further reference of strftime() check out cppreference.com
The top answer here does not work for me.
See the following examples demonstrating both the stringstream and lexical_cast answers as suggested:
#include <iostream>
#include <sstream>
int main(int argc, char** argv){
const char *time_details = "2017-01-27 06:35:12";
struct tm tm;
strptime(time_details, "%Y-%m-%d %H:%M:%S", &tm);
time_t t = mktime(&tm);
std::stringstream stream;
stream << t;
std::cout << t << "/" << stream.str() << std::endl;
}
Output: 1485498912/1485498912
Found here
#include <boost/lexical_cast.hpp>
#include <string>
int main(){
const char *time_details = "2017-01-27 06:35:12";
struct tm tm;
strptime(time_details, "%Y-%m-%d %H:%M:%S", &tm);
time_t t = mktime(&tm);
std::string ts = boost::lexical_cast<std::string>(t);
std::cout << t << "/" << ts << std::endl;
return 0;
}
Output: 1485498912/1485498912
Found: here
The 2nd highest rated solution works locally:
#include <iostream>
#include <string>
#include <ctime>
int main(){
const char *time_details = "2017-01-27 06:35:12";
struct tm tm;
strptime(time_details, "%Y-%m-%d %H:%M:%S", &tm);
time_t t = mktime(&tm);
std::tm * ptm = std::localtime(&t);
char buffer[32];
std::strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", ptm);
std::cout << t << "/" << buffer;
}
Output: 1485498912/2017-01-27 06:35:12
Found: here
Standard C++ does not have any time/date functions of its own - you need to use the C localtime and related functions.
the function "ctime()" will convert a time to a string.
If you want to control the way its printed, use "strftime". However, strftime() takes an argument of "struct tm". Use "localtime()" to convert the time_t 32 bit integer to a struct tm.
The C++ way is to use stringstream.
The C way is to use snprintf() to format the number:
char buf[16];
snprintf(buf, 16, "%lu", time(NULL));
Here's my formatter -- comments welcome. This q seemed like it had the most help getting me to my a so posting for anyone else who may be looking for the same.
#include <iostream>
#include "Parser.h"
#include <string>
#include <memory>
#include <ctime>
#include <chrono>
#include <iomanip>
#include <thread>
using namespace std;
string to_yyyyMMddHHmmssffffff();
string to_yyyyMMddHHmmssffffff() {
using namespace std::chrono;
high_resolution_clock::time_point pointInTime = high_resolution_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(pointInTime);
microseconds micros = duration_cast<microseconds>(pointInTime.time_since_epoch());
std::size_t fractional_microseconds = micros.count() % 1'000'000;
std:stringstream microstream;
microstream << "00000" << fractional_microseconds;
string formatted = microstream.str();
int index = formatted.length() - 6;
formatted = formatted.substr(index);
std::stringstream dateStream;
dateStream << std::put_time(std::localtime(&now_c), "%F %T") << "." << formatted;
formatted = dateStream.str();
return formatted;
}
There are a myriad of ways in which you might want to format time (depending on the time zone, how you want to display it, etc.), so you can't simply implicitly convert a time_t to a string.
The C way is to use ctime or to use strftime plus either localtime or gmtime.
If you want a more C++-like way of performing the conversion, you can investigate the Boost.DateTime library.
localtime did not work for me. I used localtime_s:
struct tm buf;
char dateString[26];
time_t time = time(nullptr);
localtime_s(&buf, &time);
asctime_s(dateString, 26, &buf);