【问题标题】:How do I construct an ISO 8601 datetime in C++?如何在 C++ 中构造 ISO 8601 日期时间?
【发布时间】:2012-03-20 15:23:24
【问题描述】:

我正在使用 Azure REST API,他们正在使用它来创建表存储的请求正文:

DateTime.UtcNow.ToString("o")

产生:

2012-03-02T04:07:34.0218628Z

它被称为“往返”,显然它是一个 ISO 标准(参见 http://en.wikipedia.org/wiki/ISO_8601),但在阅读了 wiki 文章后我不知道如何复制它。

有谁知道Boost 是否支持这个,或者可能是Qt

【问题讨论】:

    标签: c++ qt azure


    【解决方案1】:

    使用 C++20,时间点格式(到字符串)在 (chrono) 标准库中可用。 https://en.cppreference.com/w/cpp/chrono/system_clock/formatter

    #include <chrono>
    #include <format>
    #include <iostream>
    
    int main()
    {
       const auto now = std::chrono::system_clock::now();
       std::cout << std::format("{:%FT%TZ}", now) << '\n';
    }
    

    输出

    2021-11-02T15:12:46.0173346Z
    

    它适用于最新 C++ 语言版本 (/std:c++latest) 的 Visual Studio 2019。

    【讨论】:

      【解决方案2】:

      我应该指出我是一个 C++ 新手。

      我需要具有 UTC ISO 8601 格式的日期和时间(包括毫秒)的字符串。我无法使用 boost。

      这与其说是一个解决方案,不如说是一个 hack,但它对我来说已经足够好了。

      std::string getTime()
      {
          timeval curTime;
          gettimeofday(&curTime, NULL);
      
          int milli = curTime.tv_usec / 1000;
          char buf[sizeof "2011-10-08T07:07:09.000Z"];
          char *p = buf + strftime(buf, sizeof buf, "%FT%T", gmtime(&curTime.tv_sec));
          sprintf(p, ".%dZ", milli);
      
          return buf;
      }
      

      输出如下:2016-04-13T06:53:15.485Z

      【讨论】:

        【解决方案3】:

        您可以获取本地时间或UTC时间:

        #include <ctime>
        #include <iostream>
        
        int main(){
            std::time_t time = std::time(0); // Get current time
        
            // Construct local time
            char loc[sizeof("2021-03-01T10:44:10Z")];
            strftime(loc, sizeof(loc), "%FT%TZ", localtime(&time));
        
            // Construct UTC time 
            char utc[sizeof("2021-03-01T10:44:10Z")];
            strftime(utc, sizeof(utc), "%FT%TZ", gmtime(&time));
        
            // Print local and UTC time
            std::cout << "Local time: " << loc << std::endl;
            std::cout << "UTC time: " << utc << std::endl;
            return 0;
        }
        

        【讨论】:

          【解决方案4】:

          您可以使用这个函数,它使用std::put_timestd::ostringstream 来生成结果std::string

          #include <iostream>
          #include <chrono>
          #include <iomanip>
          #include <sstream>
          /**
           * Generate a UTC ISO8601-formatted timestamp
           * and return as std::string
           */
          std::string currentISO8601TimeUTC() {
            auto now = std::chrono::system_clock::now();
            auto itt = std::chrono::system_clock::to_time_t(now);
            std::ostringstream ss;
            ss << std::put_time(gmtime(&itt), "%FT%TZ");
            return ss.str();
          }
          // Usage example
          int main() {
              std::cout << currentISO8601TimeUTC() << std::endl;
          }
          

          参考:https://techoverflow.net/2018/03/30/iso8601-utc-time-as-stdstring-using-c11-chrono/

          【讨论】:

            【解决方案5】:

            在 Visual C++、GNU C++、Emscripten 中测试

            #include <ctime>
            #include <chrono>
            #include <iostream> 
            #include <locale>  
            
            #if defined (_WIN32) 
            #define WINDOWSLIB 1
            #elif defined (__APPLE__)//iOS, Mac OS
            #define MACOSLIB 1
            #elif defined (__LINUX__) || defined(__gnu_linux__) || defined(__linux__) || defined(__linux) || defined(linux)//_Ubuntu - Fedora - Centos - RedHat
            #define LINUXLIB 1
            #elif defined (__EMSCRIPTEN__)
            #define EMSCRIPTENLIB 1
            #endif
            
            #define WriteLine(data)std::cout<< data <<std::endl;
            typedef std::string String;
            
            String CurrentISO8601DateTime(bool toUTC=true)
            {
                using namespace std::chrono;
                system_clock::time_point now = system_clock::now();
                time_t timet = system_clock::to_time_t(now);
                std::tm tm{};
                String localeStr = setlocale(LC_ALL, nullptr);
                setlocale(LC_ALL, u8"");
                String format = String(u8"%FT%T.").append(std::to_string(duration_cast<milliseconds>(now.time_since_epoch()).count() % static_cast<long long>(1000)));
                if (toUTC)
                {
            #ifdef WINDOWSLIB
                    gmtime_s(&tm, &timet);
            #elif LINUXLIB
                    gmtime_r(&timet, &tm);
            #elif EMSCRIPTENLIB
                    gmtime_r(&timet, &tm);
            #endif
                    format = format.append(u8"Z");
                }
                else
                {
            #ifdef WINDOWSLIB
                    localtime_s(&tm, &timet);
            #elif LINUXLIB
                    localtime_r(&timet, &tm);
            #elif EMSCRIPTENLIB
                    localtime_r(&timet, &tm);
            #endif
                    format.append(u8"%z");
                }
                String result = String(255, 0);
                const size_t length = std::strftime(&result[0], result.size(), format.c_str(), &tm);
                result.resize(length);
                setlocale(LC_ALL, localeStr.c_str());
                return result;
            }
            
            #define ConsoleWriteLn(data) std::cout<< data <<std::endl;
            
            int main()
            {
                ConsoleWriteLn(u8"UTC  : " + CurrentISO8601DateTime());
                ConsoleWriteLn(u8"LOCAL: " + CurrentISO8601DateTime(false));
            }
            


            结果

            UTC : 2020-04-12T17:00:18.632Z
            本地:2020-04-12T12:00:18.633-0500

            使用Json.NET可以正常反序列化

            【讨论】:

              【解决方案6】:

              为此,Boost 有一个 library

              posix_time 具有 from_iso_string()to_iso_string() 函数。

              【讨论】:

                【解决方案7】:

                使用date 库 (C++11):

                template <class Precision>
                string getISOCurrentTimestamp()
                {
                    auto now = chrono::system_clock::now();
                    return date::format("%FT%TZ", date::floor<Precision>(now));
                }
                

                示例用法:

                cout << getISOCurrentTimestamp<chrono::seconds>();
                cout << getISOCurrentTimestamp<chrono::milliseconds>();
                cout << getISOCurrentTimestamp<chrono::microseconds>();
                

                输出:

                2017-04-28T15:07:37Z
                2017-04-28T15:07:37.035Z
                2017-04-28T15:07:37.035332Z
                

                【讨论】:

                  【解决方案8】:

                  好的,所以我修改了一些我发现的解决方案:

                  static QString getTimeZoneOffset()
                  {
                      QDateTime dt1 = QDateTime::currentDateTime();
                      QDateTime dt2 = dt1.toUTC();
                      dt1.setTimeSpec(Qt::UTC);
                  
                  int offset = dt2.secsTo(dt1) / 3600;
                  if (offset >= 0)
                      return QString("%1").arg(offset).rightJustified(2, '0',true).prepend("+");
                  return QString("%1").arg(offset).rightJustified(2, '0',true);
                  }
                  

                  然后轻松格式化日期(yyyy-MM-dd'T'HH:mm:ss.SSSZ):

                  static QString toISO8601ExtendedFormat(QDateTime date)
                  {
                      QString dateAsString = date.toString(Qt::ISODate);
                      QString timeOffset =  Define::getTimeZoneOffset();
                      qDebug() << "dateAsString :" << dateAsString;
                      qDebug() << "timeOffset :" << timeOffset;
                      timeOffset = QString(".000%1%2").arg(timeOffset).arg("00");
                      qDebug() << "timeOffset replaced :" << timeOffset;
                      if(dateAsString.contains("Z",Qt::CaseInsensitive))
                          dateAsString = dateAsString.replace("Z",timeOffset);
                      else
                          dateAsString = dateAsString.append(timeOffset);
                          qDebug() << "dateAsString :" << dateAsString;
                      return dateAsString;
                  }
                  

                  例如 GMT +2 看起来像这样: 2013-10-14T00:00:00.000+0200

                  【讨论】:

                    【解决方案9】:

                    是这样的吗:

                    using namespace boost::posix_time;
                    ptime t = microsec_clock::universal_time();
                    qDebug() << QString::fromStdString(to_iso_extended_string(t) + "0Z"); // need 7 digits
                    

                    【讨论】:

                      【解决方案10】:

                      在 Qt 中,应该是:

                      QDateTime dt = QDateTime::currentDateTime();
                      dt.setTimeSpec(Qt::UTC);  // or Qt::OffsetFromUTC for offset from UTC
                      qDebug() << QDateTime::currentDateTime().toString(Qt::ISODate);
                      

                      【讨论】:

                      • 最后的数字是问题,不是字符串的格式
                      • 您是指秒的小数部分(即 .0218628)?它们是可选的...
                      • 怎么样?在文档中看不到任何内容
                      • en.wikipedia.org/wiki/ISO_8601#Times :“也可以添加小数...”
                      • 是的,我完全意识到这一点。我只是想知道如何使用 Qt 方法来做到这一点。
                      【解决方案11】:

                      如果精确到秒的时间足够精确,可以使用strftime

                      #include <ctime>
                      #include <iostream>
                      
                      int main() {
                          time_t now;
                          time(&now);
                          char buf[sizeof "2011-10-08T07:07:09Z"];
                          strftime(buf, sizeof buf, "%FT%TZ", gmtime(&now));
                          // this will work too, if your compiler doesn't support %F or %T:
                          //strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
                          std::cout << buf << "\n";
                      }
                      

                      如果需要更高的精度,可以使用 Boost:

                      #include <iostream>
                      #include <boost/date_time/posix_time/posix_time.hpp>
                      
                      int main() {
                          using namespace boost::posix_time;
                          ptime t = microsec_clock::universal_time();
                          std::cout << to_iso_extended_string(t) << "Z\n";
                      }
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2010-10-23
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-07-16
                        • 1970-01-01
                        • 2022-01-18
                        相关资源
                        最近更新 更多