Reputation: 123
I have followed some good answers to similar questions like this one.
Yet my code seems to give output one hour later after converting string to time_point and back to string.
The code that gives the wrong answer:
#include <string>
#include <ctime>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <sstream>
using date_time = std::chrono::system_clock::time_point;
std::string dateTimeToString(date_time time) {
std::time_t now_c = std::chrono::system_clock::to_time_t(time);
auto tm = std::localtime(&now_c);
char buffer[32];
std::strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", tm);
return std::string(buffer);
}
date_time stringToDateTime(const std::string &s) {
std::tm timeDate = {};
std::istringstream ss(s);
ss >> std::get_time(&timeDate, "%Y-%m-%d %H:%M:%S");
return std::chrono::system_clock::from_time_t(mktime(&timeDate));
}
int main() {
std::string birthday = "2000-06-05 20:20:00";
std::cout << "Two birthday dates: \n" << birthday << " \nsecond one:\n" << dateTimeToString(stringToDateTime(birthday))
<< "\n******************\n";
return 0;
}
And the output:
Two birthday dates: 2000-06-05 20:20:00 second one: 2000-06-05 21:20:00
I have thought that this has something to do with timezones, but I am unable to solve this problem. What is wrong with my code?
Upvotes: 2
Views: 2983
Reputation: 117937
Not sure it helps but works for me. Add the UTC offset and TZ info (%z
and %Z
) in both steps:
std::string dateTimeToString(date_time time) {
std::time_t now_c = std::chrono::system_clock::to_time_t(time);
auto tm = std::localtime(&now_c);
char buffer[32];
std::strftime(buffer, 32, "%Y-%m-%d %H:%M:%S%z %Z", tm);
return std::string(buffer);
}
date_time stringToDateTime(const std::string& s) {
std::tm timeDate = {};
std::istringstream ss(s);
ss >> std::get_time(&timeDate, "%Y-%m-%d %H:%M:%S%z %Z");
return std::chrono::system_clock::from_time_t(mktime(&timeDate));
}
Upvotes: 1
Reputation: 3506
You can use boost
library for time management.
Look at boost::date_time::parse_date(const std::string& s, int order_spec = ymd_order_iso):
//! Generic function to parse a delimited date (eg: 2002-02-10)
/*! Accepted formats are: "2003-02-10" or " 2003-Feb-10" or
* "2003-Feburary-10"
* The order in which the Month, Day, & Year appear in the argument
* string can be accomodated by passing in the appropriate ymd_order_spec
*/
And at boost::date_time::parse_delimited_time_duration(const std::string& s):
//! Creates a time_duration object from a delimited string
/*! Expected format for string is "[-]h[h][:mm][:ss][.fff]".
* If the number of fractional digits provided is greater than the
* precision of the time duration type then the extra digits are
* truncated.
*
* A negative duration will be created if the first character in
* string is a '-', all other '-' will be treated as delimiters.
* Accepted delimiters are "-:,.".
*/
Boost made a wrapper function to those both methods, that can parse a date-time string:
template<class time_type>
inline time_type parse_delimited_time(const std::string& s, char sep) {
typedef typename time_type::time_duration_type time_duration;
typedef typename time_type::date_type date_type;
//split date/time on a unique delimiter char such as ' ' or 'T'
std::string date_string, tod_string;
split(s, sep, date_string, tod_string);
//call parse_date with first string
date_type d = parse_date<date_type>(date_string);
//call parse_time_duration with remaining string
time_duration td = parse_delimited_time_duration<time_duration>(tod_string);
//construct a time
return time_type(d, td);
}
If you want a different date format parser, I made a slightly different implementation:
posix_time::ptime parse_dmy_time(const std::string &s, char sep) {
typedef typename posix_time::ptime::time_duration_type time_duration;
typedef typename posix_time::ptime::date_type date_type;
//split date/time on a unique delimiter char such as ' ' or 'T'
std::string date_string, tod_string;
split(s, sep, date_string, tod_string);
//call parse_date with first string
auto d = parse_date<date_type>(date_string, ymd_order_dmy);
//call parse_time_duration with remaining string
auto td = parse_delimited_time_duration<time_duration>(tod_string);
//construct a time
return {d, td};
}
Upvotes: 1