Reputation: 2770
I am working with date/time string in the %Y-%m-%d %H:%M:%S%f
format.
I want to design a function that takes a date/time string in the America/New_York
timezone and returns a date/time string in the Europe/Paris
timezone.
I came up with the following
std::string ec2cet(const std::string &date_time_str)
{
using namespace boost::posix_time;
using namespace boost::gregorian;
using namespace boost::local_time;
tz_database tz_db;
time_zone_ptr et_tz = tz_db.time_zone_from_region("America/New_York");
time_zone_ptr cet_tz = tz_db.time_zone_from_region("Europe/Paris");
ptime absolute_time = time_from_string(date_time_str);
local_date_time ec_time(absolute_time, et_tz);
local_date_time cet_time = et_time.local_time_in(cet_tz);
return to_simple_string(cet_time);
}
When printing either et_time
or cet_time
with the input string 16:03:38.539000
I get
16:03:38.539000 UTC
I was expecting
et_time
to be something different than UTC
because I constructed it providing the et_tz
timezone object.cet_time
to be in a different timezone as I constructed it with local_time_in
and providing the cet_tz
timezone object.What am I doing wrong?
Upvotes: 2
Views: 460
Reputation: 218710
I don't know what is wrong with the boost implementation of ec2cet
. However I can show how to do this with this free, open source library quite easily. First the code, and then the line-by-line explanation:
#include "tz.h"
#include <iostream>
#include <sstream>
#include <string>
std::string
ec2cet(const std::string& date_time_str)
{
using namespace std; // 1
using namespace std::chrono; // 2
using namespace date; // 3
constexpr auto fmt = "%F %T"; // 4
istringstream in{date_time_str}; // 5
local_time<microseconds> tp; // 6
in >> parse(fmt, tp); // 7
if (in.fail()) // 8
return std::string{}; // 9
auto et_time = make_zoned("America/New_York", tp); // 10
auto cet_time = make_zoned("Europe/Paris", et_time); // 11
cout << "et_time = " << et_time << '\n'; // 12
cout << "cet_time = " << cet_time << '\n'; // 13
return format(fmt, cet_time); // 14
}
Lines 1-3 just bring everything into the local space so things aren't quite so verbose.
Line 4: Just write the format string in one place. "%F %T" is equivalent to "%Y-%m-%d %H:%M:%S" and you could use that too. (I'm lazy).
Line 5: This library will parse out of any stream, so we need to turn the input string date_time_str
into a stream (in
).
Line 6: You say that the input string is known to represent the local date/time in "America/New_York". The type local_time<microseconds>
is a chrono::time_point
which can represent the local time in any time zone to microseconds precision. An instance of this (tp
) is what we will parse date_time_str
into.
Line 7: Parse into tp
.
Line 8-9: Check for a parse error.
Line 10: Create a zoned_time<microseconds>
using the "America/New_York" time_zone
and the local_time tp
. You can think of a zoned_time
as simply a pair<time_zone, local_time>
though the details are slightly more complex than that.
Line 11: Create a zoned_time<microseconds>
from the time_zone
"Europe/Paris" and the zoned_time et_time
. This converts one local time to another, equating their UTC equivalents in the process.
Lines 12-13: Output these intermediate results (et_time
and cet_time
for debugging purposes).
Line 14: Format cet_time
into the desired std::string
and return it.
Running this with the following driver:
int
main()
{
auto s = ec2cet("2017-01-08 16:03:38.539000");
std::cout << "ec2cet = " << s << '\n';
}
Outputs:
et_time = 2017-01-08 16:03:38.539000 EST
cet_time = 2017-01-08 22:03:38.539000 CET
ec2cet = 2017-01-08 22:03:38.539000
This program tracks the current IANA timezone database, and will correctly follow the time zone rules for the complete history of the IANA database, which for these two timezones starts in the late 1800's.
If microseconds
precision isn't what you want, you can change that (in one place on line 6). If the input string should be UTC instead of "America/New_York", that is also a one-line change on line 6 (make the type of tp
sys_time<microseconds>
instead of local_time<microseconds>
).
Upvotes: 2