英文:
Why are my time conversions inconsistent?
问题
以下是您要翻译的代码部分:
Quick background: my application accesses multiple data sources that report timestamped data, each timestamp is reported as Unix epoch seconds, e.g. data reports `1656331210`. The user can input a requested time to report as an ISO date string, such as `2022-06-27T12:00:10Z`. These two values are considered equivalent. My problem is consistently converting back and forth.
My function `formatTimestamp` shown below correctly converts the given timestamp value to an ISO string. However, my function to convert from a string to the same value produces a different value. I know there is an error in my logic and/or understanding.
(As a side note, I've scoured the docs for `chrono` and Howard Hinnant's date.h libraries for understanding as well. I stumble greatly on converting from one type to another and can never seem to come up with a simple and consistent solution. I know there is one, but I'm not there yet.)
Please take a look at my sample code below and correct the error of my ways:
```c++
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
uint64_t from_isoTimeString(std::string iso_time_string)
{
//--- takes an UTC ISO formatted time/date string and converts it to a timestamp value
std::tm tmb;
std::stringstream ss(iso_time_string);
ss >> std::get_time(&tmb, "%Y-%m-%dT%TZ");
if (ss.fail())
{
std::string errmsg = "unable to convert Timestamp '" + iso_time_string + "' from ISO 8601 format";
throw std::invalid_argument(errmsg);
}
std::time_t tt;
tt = mktime(&tmb); // returns 1656345610, expecting 1656331210
tt = mktime(&tmb) - _timezone; // returns 1656327610, expecting 1656331210
return static_cast<uint64_t>(tt);
}
std::string formatTimestamp(uint64_t epoch_seconds, std::string timestamp_format)
{
std::time_t tt = epoch_seconds;
std::tm tmb;
gmtime_s(&tmb, &tt);
std::stringstream ss;
ss << std::put_time(&tmb, timestamp_format.c_str());
if (ss.fail())
{
std::string err_msg = "unable to convert Timestamp to " + timestamp_format + " format";
throw std::invalid_argument(err_msg);
}
return ss.str();
}
int main()
{
uint64_t time1_uint = 1656331210;
std::string time1_str = "2022-06-27T12:00:10Z";
std::cout << " time1_str: " << time1_str << std::endl;
std::cout << " time1_uint as string: " << formatTimestamp(time1_uint, "%Y-%m-%dT%TZ" ) << std::endl;
std::cout << " time1_uint: " << time1_uint << std::endl;
std::cout << "time1_str from string: " << from_isoTimeString(time1_str) << std::endl;
}
英文:
Quick background: my application accesses multiple data sources that report timestamped data, each timestamp is reported as Unix epoch seconds, e.g. data reports 1656331210
. The user can input a requested time to report as an ISO date string, such as 2022-06-27T12:00:10Z
. These two values are considered equivalent. My problem is consistently converting back and forth.
My function formatTimestamp
shown below correctly converts the given timestamp value to an ISO string. However, my function to convert from a string to the same value produces a different value. I know there is an error in my logic and/or understanding.
(As a side note, I've scoured the docs for chrono
and Howard Hinnant's date.h libraries for understanding as well. I stumble greatly on converting from one type to another and can never seem to come up with a simple and consistent solution. I know there is one, but I'm not there yet.)
Please take a look at my sample code below and correct the error of my ways:
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
uint64_t from_isoTimeString(std::string iso_time_string)
{
//--- takes an UTC ISO formatted time/date string and converts it to a timestamp value
std::tm tmb;
std::stringstream ss(iso_time_string);
ss >> std::get_time(&tmb, "%Y-%m-%dT%TZ");
if (ss.fail())
{
std::string errmsg = "unable to convert Timestamp '" + iso_time_string + "' from ISO 8601 format";
throw std::invalid_argument(errmsg);
}
std::time_t tt;
tt = mktime(&tmb); // returns 1656345610, expecting 1656331210
tt = mktime(&tmb) - _timezone; // returns 1656327610, expecting 1656331210
return static_cast<uint64_t>(tt);
}
std::string formatTimestamp(uint64_t epoch_seconds, std::string timestamp_format)
{
std::time_t tt = epoch_seconds;
std::tm tmb;
gmtime_s(&tmb, &tt);
std::stringstream ss;
ss << std::put_time(&tmb, timestamp_format.c_str());
if (ss.fail())
{
std::string err_msg = "unable to convert Timestamp to " + timestamp_format + " format";
throw std::invalid_argument(err_msg);
}
return ss.str();
}
int main()
{
uint64_t time1_uint = 1656331210;
std::string time1_str = "2022-06-27T12:00:10Z";
std::cout << " time1_str: " << time1_str << std::endl;
std::cout << " time1_uint as string: " << formatTimestamp(time1_uint, "%Y-%m-%dT%TZ" ) << std::endl;
std::cout << " time1_uint: " << time1_uint << std::endl;
std::cout << "time1_str from string: " << from_isoTimeString(time1_str) << std::endl;
}
答案1
得分: 1
以下是代码部分的中文翻译:
C时间API的使用对于您的用例可能会非常令人困惑,因为它涉及到与您的本地时区之间的转换,这是完全不必要的复杂性。
值得一提的是,我已经重写了您的日期.h头文件下的转换函数:
uint64_t
from_isoTimeString(std::string iso_time_string)
{
//--- 接受一个UTC ISO格式的时间/日期字符串并将其转换为时间戳值
date::sys_seconds tmb;
std::stringstream ss(iso_time_string);
ss >> date::parse("%Y-%m-%dT%TZ", tmb);
if (ss.fail())
{
std::string errmsg = "无法从ISO 8601格式转换时间戳 '" + iso_time_string + "'";
throw std::invalid_argument(errmsg);
}
return static_cast<uint64_t>(tmb.time_since_epoch().count());
}
std::string
formatTimestamp(uint64_t epoch_seconds, std::string timestamp_format)
{
date::sys_seconds tt{std::chrono::seconds{epoch_seconds}};
std::stringstream ss;
ss << date::format(timestamp_format, tt);
if (ss.fail())
{
std::string err_msg = "无法将时间戳转换为 " + timestamp_format + " 格式";
throw std::invalid_argument(err_msg);
}
return ss.str();
}
我在每个函数中尽量保持了最少的更改。现在,您的本地时区不是计算的一部分。这段代码可以轻松移植到C++20(在可用时),只需将一些“date::”更改为“std::chrono::”或“std::”。
您的“main()”根本不需要更改,现在的输出如下:
time1_str: 2022-06-27T12:00:10Z
time1_uint as string: 2022-06-27T12:00:10Z
time1_uint: 1656331210
time1_str from string: 1656331210
希望这对您有所帮助。如果您有任何问题,请随时提出。
英文:
The use of the C time API can be very confusing for your use case because it involves conversions to and from your local time zone, which is a completely unnecessary complication.
Fwiw, I've rewritten your conversion functions in terms of my date.h header below:
uint64_t
from_isoTimeString(std::string iso_time_string)
{
//--- takes an UTC ISO formatted time/date string and converts it to a timestamp value
date::sys_seconds tmb;
std::stringstream ss(iso_time_string);
ss >> date::parse("%Y-%m-%dT%TZ", tmb);
if (ss.fail())
{
std::string errmsg = "unable to convert Timestamp '" + iso_time_string + "' from ISO 8601 format";
throw std::invalid_argument(errmsg);
}
return static_cast<uint64_t>(tmb.time_since_epoch().count());
}
std::string
formatTimestamp(uint64_t epoch_seconds, std::string timestamp_format)
{
date::sys_seconds tt{std::chrono::seconds{epoch_seconds}};
std::stringstream ss;
ss << date::format(timestamp_format, tt);
if (ss.fail())
{
std::string err_msg = "unable to convert Timestamp to " + timestamp_format + " format";
throw std::invalid_argument(err_msg);
}
return ss.str();
}
I've changed as little as possible within each function. Now your local time zone is not part of the computation. And this code will easily port to C++20 (when available) by changing a few date::
to std::chrono::
or std::
.
Your main()
needs no changes at all, and the output is now:
time1_str: 2022-06-27T12:00:10Z
time1_uint as string: 2022-06-27T12:00:10Z
time1_uint: 1656331210
time1_str from string: 1656331210
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论