2009-11-19 5 views
5

J'ai une chaîne contenant une date/heure locale et je dois le convertir en une valeur time_t (UTC) - J'ai essayé ceci:Conversion chaîne contenant localtime en UTC en 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); 

mais la valeur time_t que je récupère est la valeur à laquelle je m'attendrais si la chaîne était analysée en UTC et non en heure locale. Peut-être que j'ai mal compris ce que strptime est censé faire, mais dans mon fuseau horaire (UK) le 1er septembre nous utilisons BST (ie UTC + 1 heure) donc je m'attendrais à ce que la valeur que je reçois soit 1 heure d'avance sur UTC .

Existe-t-il un moyen d'interpréter la chaîne comme locale, en tenant automatiquement compte du décalage UTC qui aurait été en vigueur à cette date? Notez que j'ai besoin de la valeur time_t pas une struct tm, dans l'exemple ci-dessus je veux que la valeur time_t correspond à 2009-09-01 01:00:00 GMT

Répondre

0

Je pense que je l'ai craqué maintenant, grâce à Andomar - ce code fait ce que je dois et semble fonctionner indépendamment de l'état actuel DST (j'ai changé l'horloge sur mon PC pour vérifier):

#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

Vous pouvez utiliser mktime pour interpréter une structure dans le fuseau horaire local. Lorsque vous faites ainsi, veillez à placer le drapeau tm_isdst. C'est 0 pour l'été, 1 pour l'hiver, et -1 pour avoir mktime le découvrir. Voici quelques exemples de code:

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

Cette impression (je vis en GMT + 1, et il est l'hiver maintenant):

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 

Il ressemble mktime convertit une date en Septembre sur la base des économies de jour en cours temps. C'est novembre maintenant, donc c'est en fait une heure de congé. Je n'ai pas trouvé un moyen de corriger cela.

+0

grâce, mais sa valeur time_t que je suis intéressé par - si je fais un mktime() sur le « localcal » struct dans votre code il me donne le même résultat que faire mktime() sur ' cal '. J'ai besoin d'un moyen de produire une valeur time_t équivalente à '2009-09-01 01:00 GMT' – codebox

+1

La convention C est de stocker time_t en tant que nombre de secondes depuis 1970-01-01 en UTC. Il a été changé en heure locale uniquement pour l'interprétation ou l'affichage. Si vous souhaitez présenter rob_t comme variante locale, vous pouvez calculer le nombre de secondes entre gmtime() et localtime() et l'ajouter à votre time_t. :) – Andomar

+0

ok, mais je veux interpréter la chaîne comme heure locale, ne pas produire un équivalent en temps local d'une chaîne de temps UTC. Dans notre exemple, en supposant que nous vivons en GMT + 1, la chaîne "2009/09/01/00" est notre heure locale, et donc elle est équivalente à "2009/09/01/01" en GMT, et donc le le code doit renvoyer la valeur time_t correspondant à "2009/09/01/01". Cela a-t-il du sens? – codebox

0

Voici ma version, en utilisant tm_gmtoff. Si tout va bien, la bibliothèque prend en charge le temps de l'heure d'été ...

#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

Le 'struct tm' que vous passez à' mktime' a 'tm_isdst' réglé à 0, donc l'heure est lue sans DST. Ensuite, vous le passez à 'ctime', ce qui corrige l'heure d'été en ajoutant 1 heure. Ensuite, vous soustrayez le décalage, ce qui est également une heure de confusion, pour obtenir un temps aléatoire. Ce truc me fait tourner la tête mais j'aimerais aller au fond des choses :) – Andomar

+0

Cette DST est une affaire marrante.Je viens de réaliser que DST n'est pas en vigueur actuellement, mais c'était le 1er septembre! Hmmm ... Je suppose qu'il n'y a aucun moyen pour la bibliothèque de "savoir" quand DST commence et se termine à un endroit spécifique. Je pense que vous devez gérer DST à la main (http://timeanddate.com/time/dst2009.html) – pmg

Questions connexes