I am trying to write a chrono::zoned_seconds object as text to a file and then retrieve it and construct another chrono::zoned_seconds object later. How can this be done in a fairly efficient way?
I don't think the code snippet below shows the correct result:
#include <fstream>
#include <print>
#include <chrono>
#include <format>
#include <string>
#include <sstream>
int main()
{
{
std::ofstream file("data.txt");
if (!file) {
std::println( "Unable to open file.\n" );
return 1;
}
auto now = std::chrono::system_clock::now();
const std::chrono::zoned_seconds zs { "America/New_York", std::chrono::time_point_cast<std::chrono::seconds>( now ) };
std::format_to(std::ostreambuf_iterator<char>(file), "{:%F %T %Z}", zs);
std::println( "{:%F %T %Z}", zs ); // correct time
}
{
std::ifstream file("data.txt");
if (!file) {
std::println( "Unable to open file.\n" );
return 1;
}
std::string str;
std::getline(file, str);
std::istringstream iss { str };
std::chrono::sys_seconds tp;
std::string zone_name;
iss >> std::chrono::parse("%F %T %Z", tp, zone_name);
std::chrono::zoned_seconds zs { zone_name, tp };
std::println( "{:%F %T %Z}", zs ); // incorrect time!!
}
}
As can be seen, I used std::chrono::parse but the outputs don't match:
2024-03-01 13:35:20 EST
2024-03-01 08:35:20 EST
There are two bugs in your code. To show them I'm going to read and write from a
stringstreamto enable demos at https://wandbox.org (which does not allow file creation). However parsing and streaming tostringstreamis identical to parsing and streaming tofstreamexcept for construction/opening of the stream.Here is your code virtually unchanged, except using
stringstream:And the output currently looks like:
The reason for the large discrepancy in time is that when your format a
zoned_timeit displays the local time, not UTC. But when you read it in above, you are parsing as if the time parsed is UTC, not local:By changing the above line to:
you change the semantics of
2024-03-01 14:04:28from UTC to local time.Output:
Although this looks right, it is still subtly wrong.
ESTis a IANA time zone with no DST rules. It has a fixed UTC offset of -5h.America/New_Yorkis the same asESTbetweensys_days{Sunday[1]/November/y} + 6handsys_days{Sunday[2]/March/(y+1)} + 7h, and otherwise is on daylight saving with a UTC offset of -4h. So the program above will only be correct when daylight saving is not in effect forAmerica/New_York.To see this more clearly, replace:
with:
I.e. Let's see how this program behaves in the Summer time.
This line:
throws a
std::runtime_errorexception because it is trying to locate a time zone named "EDT" and is failing to find it. IANA has lots of time zones with an abbreviation of "EDT", but none that have that name.gcc provides a helpful message in the
runtime_error::what()message:To correct this bug,
"America/New_York"must be streamed tofileinstead of"EST"or"EDT". This can be fixed by changing one line:to:
I.e. this outputs the actual time zone name as opposed to the time zone abbreviation.
Output:
So now this line:
is guaranteed to use the same time zone name as was used in this line:
Here is the complete fixed example for reference: