将__DATE__中的字符串转换为time_t

时间:2009-11-19 17:17:51

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

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

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

7 个答案:

答案 0 :(得分:16)

编辑:更正的功能应如下所示:

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);
}

答案 1 :(得分:7)

杰瑞的功能看起来很棒。这是我的尝试..我也投入了__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;
}

答案 2 :(得分:3)

我不知道是否有其他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

答案 3 :(得分:2)

根据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'))

答案 4 :(得分:1)

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() {}

答案 5 :(得分:0)

回答here

DATE 格式的规格为here

答案 6 :(得分:0)

以下是我如何修改您的样本,以便在C ++中使用mbed for 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/以获取如何使用它根据编译时间初始化时钟芯片的示例。