【问题标题】:Convert string from __DATE__ into a time_t将字符串从 __DATE__ 转换为 time_t
【发布时间】:2010-12-18 09:52:59
【问题描述】:

我正在尝试将__DATE__ 宏生成的字符串转换为time_t。我不需要成熟的日期/时间解析器,只处理__DATE__ 宏格式的东西会很棒。

预处理器方法很漂亮,但函数也可以工作。如果相关,我正在使用 MSVC。

【问题讨论】:

    标签: c++ date visual-c++ c-preprocessor


    【解决方案1】:

    编辑:更正后的函数应如下所示:

    time_t cvt_TIME(char const *time) { 
        char s_month[5];
        int month, day, year;
        struct tm t = {0};
        static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
    
        sscanf(time, "%s %d %d", s_month, &day, &year);
    
        month = (strstr(month_names, s_month)-month_names)/3;
    
        t.tm_mon = month;
        t.tm_mday = day;
        t.tm_year = year - 1900;
        t.tm_isdst = -1;
    
        return mktime(&t);
    }
    

    【讨论】:

    • 一件大事 - __DATE__ '返回'的月份是名称形式('Jan'、'Feb' 等)。另一个小建议:您应该设置t.tm_dst = -1,以便mktime() 将尝试使用适当的夏令时。
    • @Michael - 看起来 t.tm_dst 不是 Visual c++ 的一部分。
    • 对不起-应该是t.tm_isdst = -1
    • 上面的函数不能正常工作——strstr() 的参数顺序不对,应该是strstr(month_names, s_month)。参考cplusplus.com/reference/clibrary/cstring/strstr
    • @HowardHinnant:嗯,还有一些其他类似 UTC 的东西可以代替使用(例如,TAI 和 GPS 都独立于时区,但都不包括像 UTC 那样的闰秒)。但是是的——如果now() < __DATE__ 可能特别有害——许多人通常认为不可能出现这种情况。不过,甚至不需要使用便携式计算机:如果您在计算机上编译,而我在不同时区将其下载到我的计算机上,则会出现相同的基本情况。
    【解决方案2】:

    Jerry 的函数看起来很棒。这是我的尝试。我也加入了 __TIME__。

    #include <iostream>
    #include <sstream>
    
    using namespace std;
    
    time_t time_when_compiled()
    {
        string datestr = __DATE__;
        string timestr = __TIME__;
    
        istringstream iss_date( datestr );
        string str_month;
        int day;
        int year;
        iss_date >> str_month >> day >> year;
    
        int month;
        if     ( str_month == "Jan" ) month = 1;
        else if( str_month == "Feb" ) month = 2;
        else if( str_month == "Mar" ) month = 3;
        else if( str_month == "Apr" ) month = 4;
        else if( str_month == "May" ) month = 5;
        else if( str_month == "Jun" ) month = 6;
        else if( str_month == "Jul" ) month = 7;
        else if( str_month == "Aug" ) month = 8;
        else if( str_month == "Sep" ) month = 9;
        else if( str_month == "Oct" ) month = 10;
        else if( str_month == "Nov" ) month = 11;
        else if( str_month == "Dec" ) month = 12;
        else exit(-1);
    
        for( string::size_type pos = timestr.find( ':' ); pos != string::npos; pos = timestr.find( ':', pos ) )
            timestr[ pos ] = ' ';
        istringstream iss_time( timestr );
        int hour, min, sec;
        iss_time >> hour >> min >> sec;
    
        tm t = {0};
        t.tm_mon = month-1;
        t.tm_mday = day;
        t.tm_year = year - 1900;
        t.tm_hour = hour - 1;
        t.tm_min = min;
        t.tm_sec = sec;
        return mktime(&t);
    }
    
    int main( int, char** )
    {
        cout << "Time_t when compiled: " << time_when_compiled() << endl;
        cout << "Time_t now: " << time(0) << endl;
    
        return 0;
    }
    

    【讨论】:

    【解决方案3】:

    回复here

    DATE 的格式规范为here

    【讨论】:

      【解决方案4】:

      我不知道是否有其他 Arduino 黑客会偶然发现这个问题,但我发现 @JerryCoffin 的回答对我的项目解决这个问题很有帮助。这是一个可以粘贴到 Arduino 中的完整示例。它使用Time lib referenced here

      #include "Arduino.h"
      #include <Time.h>
      #include <stdio.h>
      
      time_t cvt_date(char const *date) { 
          char s_month[5];
          int month, day, year;
          tmElements_t tmel;
          static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
      
          sscanf(date, "%s %d %d", s_month, &day, &year);
      
          month = (strstr(month_names, s_month)-month_names)/3+1;
      
          tmel.Hour = tmel.Minute = tmel.Second = 0; // This was working perfectly until 3am then broke until I added this.
          tmel.Month = month;
          tmel.Day = day;
       // year can be given as full four digit year or two digts (2010 or 10 for 2010);
       //it is converted to years since 1970
        if( year > 99)
            tmel.Year = year - 1970;
        else
            tmel.Year = year + 30;
      
          return makeTime(tmel);
      }
      
      void printdate(char const *date)
      {
        Serial.println((String)"cvt_date('" + date + "')");
        time_t t = cvt_date(date);
      
        Serial.println((String) month(t) + "-" + day(t) + "-" + year(t));
        setTime(t);
        Serial.println((String) month()  + "/" + day()  + "/" + year() + "\n");
      }
      
      void setup()
      {
        Serial.begin(9600); while (!Serial);
        printdate(__DATE__);       // works with the compiler macro
        printdate("Jan  1    00"); // works with 2 digit years
        printdate("Feb  28   01");
        printdate("Mar  7 5");     // works with 1 digit years
        printdate("Apr  10 1970"); // works from 1970
        printdate("May  13 1980");
        printdate("Jun  16 1990");
        printdate("Jul  19 1997");
        printdate("Aug  22 2000");
        printdate("Sep  25 2010");
        printdate("Oct  31 2014");
        printdate("Nov  30 2020");
        printdate("Dec  31 2105"); // through 2105
        printdate("Dec  31 2106"); // fails at and after 2106
      }
      
      void loop(){
      }
      

      这是串行终端结果...

      cvt_date('Oct  5 2014')
      10-5-2014
      10/5/2014
      
      cvt_date('Jan  1    00')
      1-1-2000
      1/1/2000
      
      cvt_date('Feb  28   01')
      2-28-2001
      2/28/2001
      
      cvt_date('Mar  7 5')
      3-7-2005
      3/7/2005
      
      cvt_date('Apr  10 1970')
      4-10-1970
      4/10/1970
      
      cvt_date('May  13 1980')
      5-13-1980
      5/13/1980
      
      cvt_date('Jun  16 1990')
      6-16-1990
      6/16/1990
      
      cvt_date('Jul  19 1997')
      7-19-1997
      7/19/1997
      
      cvt_date('Aug  22 2000')
      8-22-2000
      8/22/2000
      
      cvt_date('Sep  25 2010')
      9-25-2010
      9/25/2010
      
      cvt_date('Oct  31 2014')
      10-31-2014
      10/31/2014
      
      cvt_date('Nov  30 2020')
      11-30-2020
      11/30/2020
      
      cvt_date('Dec  31 2105')
      12-31-2105
      12/31/2105
      
      cvt_date('Dec  31 2106')
      11-23-1970
      11/23/1970
      

      如果您只想使用__DATE__ 而不需要time_ttmElements_t 对象,则代码可以简单得多。

      void logname(char const *date, char *buff) { 
          int month, day, year;
          static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
          sscanf(date, "%s %d %d", buff, &day, &year);
          month = (strstr(month_names, buff)-month_names)/3+1;
          sprintf(buff, "%d%02d%02d.txt", year, month, day);
      }
      
      void setup()
      {
        Serial.begin(9600); while (!Serial);
        Serial.print("log file name: ");
        char filename[16];
        logname(__DATE__, filename);
        Serial.println(filename);
      }
      
      void loop(){
      }
      

      这是串行终端结果...

      log file name: 20141009.txt
      

      【讨论】:

      • 我正要评论不是所有的英雄都穿斗篷,但我发现你这样做!
      【解决方案5】:

      Bruno 的回答对我的 Arduino 项目非常有用。这是一个包含 __DATE__ 和 __TIME__ 的版本

      #include <Time.h>
      #include <stdio.h>
      
      time_t cvt_date(char const *date, char const *time)
      {
          char s_month[5];
          int year;
          tmElements_t t;
          static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
      
          sscanf(date, "%s %hhd %d", s_month, &t.Day, &year);
          sscanf(time, "%2hhd %*c %2hhd %*c %2hhd", &t.Hour, &t.Minute, &t.Second);
      
          // Find where is s_month in month_names. Deduce month value.
          t.Month = (strstr(month_names, s_month) - month_names) / 3 + 1;
      
          // year can be given as '2010' or '10'. It is converted to years since 1970
          if (year > 99) t.Year = year - 1970;
          else t.Year = year + 30;
      
          return makeTime(t);
      }
      
      void setup()
      {
          Serial.begin(115200); 
          while (!Serial);
      
          // Show raw system strings
          Serial.println(String("__DATE__ = ") + __DATE__);
          Serial.println(String("__TIME__ = ") + __TIME__);
      
          // set system time = compile time
          setTime(cvt_date(__DATE__, __TIME__));
      
          // Show actual time
          Serial.println(String("System date = ") + month() + "/" + day() + "/" + year() + " " + hour() + ":" + minute() + ":" + second() + "\n");
      }
      
      void loop() {}
      

      【讨论】:

        【解决方案6】:

        根据gcc.gnu.org 给出的描述,构建日期可以在编译时使用以下宏获得。

        #define BUILDTM_YEAR (\
            __DATE__[7] == '?' ? 1900 \
            : (((__DATE__[7] - '0') * 1000 ) \
            + (__DATE__[8] - '0') * 100 \
            + (__DATE__[9] - '0') * 10 \
            + __DATE__[10] - '0'))
        
        #define BUILDTM_MONTH (\
            __DATE__ [2] == '?' ? 1 \
            : __DATE__ [2] == 'n' ? (__DATE__ [1] == 'a' ? 1 : 6) \
            : __DATE__ [2] == 'b' ? 2 \
            : __DATE__ [2] == 'r' ? (__DATE__ [0] == 'M' ? 3 : 4) \
            : __DATE__ [2] == 'y' ? 5 \
            : __DATE__ [2] == 'l' ? 7 \
            : __DATE__ [2] == 'g' ? 8 \
            : __DATE__ [2] == 'p' ? 9 \
            : __DATE__ [2] == 't' ? 10 \
            : __DATE__ [2] == 'v' ? 11 \
            : 12)
        
        #define BUILDTM_DAY (\
            __DATE__[4] == '?' ? 1 \
            : ((__DATE__[4] == ' ' ? 0 : \
            ((__DATE__[4] - '0') * 10)) + __DATE__[5] - '0'))
        

        【讨论】:

          【解决方案7】:

          以下是我如何修改您的示例以与 mbed 一起使用 C++ 中的 Arm32 微控制器。

          // Convert compile time to system time 
          time_t cvt_date(char const *date, char const *time)
          {
              char s_month[5];
              int year;
              struct tm t;
              static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
              sscanf(date, "%s %d %d", s_month, &t.tm_mday, &year);
              sscanf(time, "%2d %*c %2d %*c %2d", &t.tm_hour, &t.tm_min, &t.tm_sec);
              // Find where is s_month in month_names. Deduce month value.
              t.tm_mon = (strstr(month_names, s_month) - month_names) / 3 + 1;    
              t.tm_year = year - 1900;    
              return mktime(&t);
          }
          

          完整代码请参见:https://developer.mbed.org/users/joeata2wh/code/compile_time_to_system_time/。另请参阅https://developer.mbed.org/users/joeata2wh/code/xj-Init-clock-to-compile-time-if-not-alr/,了解我如何使用它根据编译时间初始化时钟芯片。

          【讨论】:

            猜你喜欢
            • 2016-12-11
            • 1970-01-01
            • 2021-12-26
            • 2016-09-15
            • 2018-07-25
            • 2015-12-22
            • 2013-01-16
            • 2011-10-30
            • 2011-07-19
            相关资源
            最近更新 更多