为什么我的时间转换不一致?

huangapple go评论91阅读模式
英文:

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 &gt;&gt; date::parse(&quot;%Y-%m-%dT%TZ&quot;, tmb);
if (ss.fail())
{
std::string errmsg = &quot;unable to convert Timestamp &#39;&quot; + iso_time_string + &quot;&#39; from ISO 8601 format&quot;;
throw std::invalid_argument(errmsg);
}
return static_cast&lt;uint64_t&gt;(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 &lt;&lt; date::format(timestamp_format, tt);
if (ss.fail())
{
std::string err_msg = &quot;unable to convert Timestamp to &quot; + timestamp_format + &quot; format&quot;;
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

huangapple
  • 本文由 发表于 2023年3月10日 00:11:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75687230.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定