2009-11-19 17 views
10

Estoy tratando de convertir la cadena producida de la macro __DATE__ en un time_t. No necesito un analizador sintáctico de fecha/hora, algo que solo maneje el formato de la macro __DATE__ sería genial.Convertir cadena de __DATE__ a un time_t

Un método de preprocesador sería ingenioso, pero una función funcionaría igual de bien. Si es relevante, estoy usando MSVC.

Respuesta

14

Editar: la función corregida debería ser algo como esto:

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

Una cosa importante: el mes 'devuelto' por '__DATE__' está en forma de nombre ('Jan', 'Feb', etc.). Otra sugerencia menor: debe establecer 't.tm_dst = -1' para que' mktime() 'intente utilizar el horario de verano apropiado. –

+0

@Michael - parece que t.tm_dst no es parte de C++ visual. – tfinniga

+0

Lo siento - debería haber sido 't.tm_isdst = -1' –

6

función de Jerry se ve muy bien. Aquí está mi intento. Lancé el __TIME__ también.

#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; 
} 
+1

¿No debería ser 't.tm_hour = hora - 1;'? https://msdn.microsoft.com/en-us/library/windows/hardware/ff567981(v=vs.85).aspx – gmas80

+0

Buena catch @ gmas80, voy a editar para corregirlo. – tfinniga

2

No sé si algún otro hacker de Arduino tropezará con esta pregunta, pero encontré la respuesta de @ JerryCoffin bastante útil para resolver este problema para mi proyecto. Aquí hay un ejemplo completo que puedes pegar en Arduino. Utiliza el 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(){ 
} 

Éstos son los resultados de terminal serie ...

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 

Si lo que desea es utilizar el __DATE__ y usted no necesita un objeto o time_ttmElements_t, el código puede ser mucho más simple .

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

Éstos son los resultados de terminal serie ...

log file name: 20141009.txt 
1

respuesta de Bruno era muy útil para mi proyecto Arduino. Aquí hay una versión con tanto __DATE__ y __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() {} 
1

basándose en la descripción dada en gcc.gnu.org la fecha de creación puede ser obtener en el tiempo de compilación usando macros siguientes.

#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')) 
1

Así es como modifiqué su muestra para usar con mbed para microcontroladores Arm32 en C++.

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

Ver: https://developer.mbed.org/users/joeata2wh/code/compile_time_to_system_time/ de código completo. También vea https://developer.mbed.org/users/joeata2wh/code/xj-Init-clock-to-compile-time-if-not-alr/ para ver un ejemplo de cómo lo uso para inicializar un chip de reloj basado en el tiempo de compilación.