2009-11-19 25 views
5

Ho una stringa contenente una data/ora locale e ho bisogno di convertirlo in un valore time_t (in UTC) - Ho cercato questo:Conversione stringa contenente localtime in UTC in C

char* date = "2009/09/01/00"; 
struct tm cal = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL}; 
strptime(date, "%Y/%m/%d/%H", &cal); 
time_t t = mktime(&cal); 

ma il valore time_t che ottengo è il valore che mi aspetterei se la stringa venisse analizzata come ora UTC non locale. Forse ho frainteso cosa dovrebbe fare la durata massima, ma nel mio fuso orario (Regno Unito) il 1 ° settembre usiamo BST (cioè UTC + 1 ora), quindi mi aspetto che il valore alla fine sia di 1 ora prima di UTC .

C'è un modo per interpretare la stringa come ora locale, tenendo automaticamente conto dell'offset UTC che sarebbe stato in vigore in quella data? Nota che ho bisogno del valore time_t non di una struct tm, nell'esempio sopra voglio che il valore time_t corrisponda a 2009-09-01 01:00:00 GMT

risposta

0

Penso di aver incrinato ora, grazie a Andomar - questo codice fa quello che ho bisogno e sembra funzionare a prescindere dello stato DST corrente (ho cambiato l'orologio sul mio PC per controllare questo):

#include <time.h> 
#include <assert.h> 

time_t parseLocalDate(char* date){ 
    struct tm cal = {0, 0, 0, 0, 0, 0, 0, 0, -1, 0, NULL}; 
    strptime(date, "%Y/%m/%d/%H", &cal); 
    return mktime(&cal); 
} 

int main(int argc, char *argv[]){ 
// DST is effect, Local Time = GMT+1 
    assert(1251759600 == parseLocalDate("2009/09/01/00")); // Mon, 31 Aug 2009 23:00:00 GMT 
    assert(1254351600 == parseLocalDate("2009/10/01/00")); // Wed, 30 Sep 2009 23:00:00 GMT 
// DST not in effect, Local Time = GMT 
    assert(1257033600 == parseLocalDate("2009/11/01/00")); // Sun, 01 Nov 2009 00:00:00 GMT 
} 
5

Puoi usare mktime per interpretare una struct tm nel fuso orario locale. Quando lo fai, fai attenzione a impostare il flag tm_isdst. È 0 per l'estate, 1 per l'inverno, e -1 per avere mktime capirlo. Ecco qualche esempio di codice:

void main() 
{ 
    char* date = "2009/09/01/00"; 
    struct tm cal = {}; 
    // Read string into struct tm 
    strptime(date, "%Y/%m/%d/%H", &cal); 
    // Tell mktime to figure out the daylight saving time 
    cal.tm_isdst = -1; 
    printf("%20s: %s", "Before mktime", asctime(&cal)); 
    // Convert struct tm to time_t 
    time_t t = mktime(&cal); 
    // Convert time_t to localtime 
    struct tm localcal = *localtime(&t); 
    printf("%20s: %s", "Local time", asctime(&localcal)); 
    printf("%20s: %i\n", "Local DST", localcal.tm_isdst); 
    // Convert time_t to GMT 
    struct tm gmcal = *gmtime(&t); 
    printf("%20s: %s", "GM time", asctime(&gmcal)); 
    printf("%20s: %i\n", "GM DST", gmcal.tm_isdst); 
} 

Questo stampa (io vivo a GMT + 1, ed è inverno ora):

Before mktime: Tue Sep 1 00:00:00 2009 
     Local time: Tue Sep 1 00:00:00 2009 
     Local DST: 1 
     GM time: Mon Aug 31 22:00:00 2009 
      GM DST: 0 

Sembra mktime converte una data nel mese di settembre sulla base delle legale attuali tempo. È novembre ora, quindi è in realtà un'ora di pausa. Non ho trovato un modo per correggerlo.

+0

grazie, ma il suo valore time_t che mi interessa - se faccio un mktime() sul 'localcal' struct nel tuo codice mi dà lo stesso risultato di mktime() su ' cal'. Ho bisogno di un modo per produrre un valore time_t equivalente a '2009-09-01 01:00 GMT' – codebox

+1

La convenzione C è di memorizzare time_t come il numero di secondi dal 1970-01-01 in UTC. È cambiato in locale solo per l'interpretazione o la visualizzazione. Se desideri introdurre rob_t come variante locale, puoi calcolare il numero di secondi tra gmtime() e localtime() e aggiungerlo al tuo time_t. :) – Andomar

+0

ok, ma voglio interpretare la stringa come ora locale, non produrre un equivalente locale di una stringa di tempo UTC. Nel nostro esempio, supponendo che viviamo in GMT + 1, la stringa "2009/09/01/00" è la nostra ora locale, quindi è equivalente a "2009/09/01/01" in GMT, quindi il codice dovrebbe restituire il valore time_t corrispondente a "2009/09/01/01". Ha senso? – codebox

0

Ecco la mia versione, utilizzando tm_gmtoff. Si spera, la biblioteca si prende cura di ora legale ...

#define _BSD_SOURCE 
#define _XOPEN_SOURCE 
#include <stdio.h> 
#include <time.h> 

int gmtoffset(void) { 
    struct tm *dummy; 
    time_t t = 0; 
    dummy = localtime(&t); 
    return dummy->tm_gmtoff; /* _BSD_SOURCE */ 
} 

int main(void) { 
    int off; 
    const char *date = "2009/09/01/00"; 
    struct tm cal = {0}; 
    time_t t; 

    off = gmtoffset(); 

    strptime(date, "%Y/%m/%d/%H", &cal); /* _XOPEN_SOURCE */ 
    t = mktime(&cal); 
    printf("t  --> %s", ctime(&t)); /* ctime includes a final '\n' */ 
    t -= off; 
    printf("t-off --> %s", ctime(&t)); 
    return 0; 
} 
 
$ /usr/bin/gcc ptime.c 
 
$ ./a.out 
t  --> Tue Sep 1 01:00:00 2009 
t-off --> Tue Sep 1 00:00:00 2009 
+0

La 'struct tm' che si passa a' mktime' ha 'tm_isdst' impostato su 0, quindi l'ora viene letta senza ora legale. Quindi lo passi a 'ctime', che corregge l'ora legale aggiungendo 1 ora. Quindi sottrarre l'offset, che è anche confusionamente di 1 ora, per ottenere un tempo casuale. Questa roba mi fa girare la testa ma mi piacerebbe arrivare fino in fondo :) – Andomar

+0

Questo DST è divertente.Ho appena realizzato che l'ora legale non è in vigore al momento, ma era il 1 ° settembre! Hmmm ... Immagino che non ci sia modo per la biblioteca di "sapere" quando l'ora legale inizia e finisce in un posto specifico. Penso che tu debba gestire l'ora legale a mano (http://timeanddate.com/time/dst2009.html) – pmg

Problemi correlati