对将日期字符串从 UTC 转换为本地时间的常用 C++ 解决方案感到困惑

问题描述 投票:0回答:1

在这个答案中,有:

int main()
{
   std::string strUTCTime = "2017-03-17T13:20:00Z";
   std::wstring wstrUTCTime = std::wstring(strUTCTime.begin(),strUTCTime.end());
   time_t utctime = getEpochTime(wstrUTCTime.c_str());
   struct tm tm;
   /*Convert UTC TIME To Local TIme*/
   localtime_s(&tm, &utctime);
   char CharLocalTimeofUTCTime[30];
   strftime(CharLocalTimeofUTCTime, 30, "%Y-%m-%dT%H:%M:%SZ", &tm);
   string strLocalTimeofUTCTime(CharLocalTimeofUTCTime);
   std::cout << "\n\nLocal To UTC Time Conversion:::" << strLocalTimeofUTCTime;
}

std::time_t getEpochTime(const std::wstring& dateTime) 
{

     /* Standard UTC Format*/
     static const std::wstring dateTimeFormat{ L"%Y-%m-%dT%H:%M:%SZ" };

     std::wistringstream ss{ dateTime };
     std::tm dt;
     ss >> std::get_time(&dt, dateTimeFormat.c_str()); // (1)

     /* Convert the tm structure to time_t value and return Epoch. */
     return _mkgmtime(&dt);
}

我从解决方案一开始就心存疑虑,我在另一个问题中提出这个问题,因为该解决方案代表了多个类似的解决方案:首先依赖于

get_time
,然后依赖于
mktime

我对情况的理解是(看线

(1)
):

  • 任何
    stringstream
    上的默认区域设置都是与机器对应的区域设置(例如,当地时间)。
  • get_time
    考虑流中所灌输的语言环境来解析其“输入”;换句话说:它认为解析的字符串是一个时间点,根据“本地日历”以给定的格式表示;但事实并非如此,它是 UTC 日期(来自“UTC”时区)!

解析 UTC 日期时间并认为它是本地日期时间,这不存在任何语义问题吗?我真的不明白这个“逻辑不匹配”是如何解决的。这对我来说毫无意义。

注意: 对于那些向我推荐此解决方案替代方案的人(尽管这不是我的问题),我无法使用 C++20。我最多可以使用 C++17,以及任何 POSIX 和/或 Linux 特定的函数(gcc 8.5、Linux 内核 3.x)。

c++ datetime c++17
1个回答
0
投票
问题中的

getEpochTime
对于时区而言可以正确工作。 UTC 和当地时间之间没有实际差异。

更多细节:

  • 问题中的

    dateTimeFormat
    "%Y-%m-%dT%H:%M:%SZ"
    是较长的ISO 8601格式,如
    date + "T" + time + time_zone
    ,其中时区字符串
    "Z"
    表示UTC == GMT。

  • ss >> std::get_time(..., dateTimeFormat)
    仅接受更长的ISO 8601格式(如
    "Z"
    中指定)的UTC字符串(以
    dateTimeFormat
    结尾,如
    dateTimeFormat
    中指定)。它的输出结构体
    std::tz
    不包含任何指示时区的字段。

  • ss >> std::get_time(..., dateTimeFormat)
    调用在解析月份和工作日名称时尊重当前区域设置(例如,如果区域设置是英语,则
    "%b"
    "%h"
    "%B"
    转换说明符在输入字符串中接受
    October
    ,并且它们接受
    Oktober
    相反,如果当地人是德国人)。但是,指定的
    dateTimeFormat
    不使用任何特定于区域设置的转换说明符,因此该特定调用与区域设置无关。

  • ss >> std::get_time(..., dateTimeFormat)
    调用会忽略时区。

  • ss >> std::get_time(&dt, dateTimeFormat)
    调用之后,
    dt
    结构体(
    std::tm
    )将填充 6 个字段(年、月、日、时、分、秒)。 (也许其他字段也会被填充。)

  • _mkgmtime(&dt);
    调用将
    std::dt
    的6个字段转换为time_t类型的有符号整数(假设时区UTC == GMT)。
    
    

© www.soinside.com 2019 - 2024. All rights reserved.