Comment obtenir time_t à GMT sous Windows en C

J’écris un code qui fonctionnera sur plusieurs systèmes intercommunicants. J’utilisais time () pour obtenir time_t, mais cela posait des problèmes de décalage de fuseau horaire entre les systèmes. Je souhaitais donc obtenir time_t à l’heure GMT. J’ai parcouru les fonctions time.h, mais je ne vois pas comment je peux être sûr d’obtenir l’heure correctement. C’est ce que j’ai trouvé jusqu’à présent:

time_t t = time(); struct tm *gtm = gmtime(&t); time_t gt = mktime(gtm); 

Maintenant, cela semble obtenir la bonne réponse sur ma machine, mais je veux savoir si cela fonctionnera de manière universelle avant de la sortir, même si les horloges des autres machines sont réglées sur l’heure locale ou sur l’heure GMT ou dans des fuseaux horaires différents . La raison pour laquelle je suis concerné est à cause de mktime. Dans la description, il est indiqué qu’il interprète la structure tm comme “une heure de calendrier exprimée en heure locale”. Cela me semble que l’heure GMT ne sera pas renvoyée, bien que cela semble être sur ma machine. En outre, lorsque j’imprime gt, il a 4 heures d’avance sur t, ce qui semble bien. Mais si je lance ce qui suit:

 time_t t = time(); struct tm *gtm = gmtime(&t); struct tm *ltm = localtime(&t); printf("%d, %d\n", gtm->tm_hour, ltm->tm_hour); 

les heures sont les mêmes et sont l’heure locale, ce qui n’est pas ce à quoi je m’attendais.

Pour mémoire, dans une autre réponse, j’ai vu la référence à timegm (), qui semble parfaite, mais elle n’existe pas sur mon système.

En bref, comment puis-je obtenir time_t en GMT sur n’importe quelle machine Windows en C?

Edit: suppression de la balise msvcrt qui a été ajoutée, car je n’utilise pas msvcrt.

time_t est toujours en UTC, par définition. Alors le temps () fait ce que vous voulez. Les fuseaux horaires n’entrent en jeu que lorsque vous effectuez la conversion entre time_t et représentation décomposée.

Si vous avez l’heure UTC sous la forme d’une heure fractionnée, vous devez temporairement basculer le fuseau horaire sur UTC, utilisez mktime () pour convertir en time_t et rétablir le fuseau horaire, comme suit:

 time_t convert_utc_tm_to_time_t (struct tm *tm) { char *tz; time_t result; /* temporarily set timezone to UTC for conversion */ tz = getenv("TZ"); if (tz) { tz = strdup (tz); if (!tz) { // out of memory return -1; } } setenv("TZ", "", 1); tzset(); result = mktime (tm); /* restore timezone */ if (tz) { setenv("TZ", tz, 1); free (tz); } else { unsetenv("TZ"); } tzset(); return result; } 

Utilisez gmtime() comme vous le souhaitez pour votre chiffre horaire GMT. localtime indiquera l’heure dans le fuseau horaire local et uniquement par GMT lorsque le fuseau horaire local est également GMT.

Windows possède son propre code et ses propres structures de données permettant de gérer les fuseaux horaires. Pour obtenir GMT à l’aide du code c spécifique à Windows, vous pouvez utiliser GetSystemTime() . Vous trouverez plus d’informations à ce sujet à l’adresse suivante: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724390(v=vs.85).aspx

Veuillez noter que Windows utilise sa propre structure de date / heure, mais elle est également détaillée avec GetSystemTime() et ses pages associées. En bref, GetSystemTime() récupère la date et l’heure système actuelles, exprimées en temps universel coordonné (UTC) (également appelé GMT). Il utilise la structure Windows SYSTEMTIME qui est une structure avec de nombreux éléments de temps.

En regardant la première partie de votre code:

 time_t t = time(); struct tm *gtm = gmtime(&t); time_t gt = mktime(gtm); 

Vous définissez gt sur une valeur fictive. Lorsque vous appelez mktime , vous devez transmettre une struct tm* en heure locale. time_t est défini comme le nombre de secondes écastings depuis le 1er janvier 1970, 00:00 UTC. Sauf si vous vous trouvez actuellement dans le fuseau horaire +0000, la valeur de retour de votre appel à mktime représentera un temps de quelques heures passées ou futures.

Quant à la deuxième partie:

 time_t t = time(); struct tm *gtm = gmtime(&t); struct tm *ltm = localtime(&t); printf("%d, %d\n", gtm->tm_hour, ltm->tm_hour); 

Je pense que gmtime et localtime retournent le même tampon en mémoire, ce qui pourrait expliquer pourquoi vous obtenez les mêmes deux heures dans votre sortie. Le deuxième appel remplace la sortie du premier. Essayez ceci à la place:

 struct tm gtm, ltm; struct tm *tm_buf; time_t t = time(); tm_buf = gmtime(&t); memcpy(&gtm, tm_buf, sizeof(struct tm)); tm_buf = localtime(&t); memcpy(&ltm, tm_buf, sizeof(struct tm)); printf("%d, %d\n", gtm.tm_hour, ltm.tm_hour); 

Notez que pour une conversion aussi sortingviale, vous pouvez utiliser votre propre fonction. Il y a une copie ici du mkgmtime()

https://github.com/m2osw/snapcpp/blob/master/snapwebsites/libsnapwebsites/src/snapwebsites/mkgmtime.c

Cela vous permet de convertir une struct tm en une valeur time_t ignorant les informations de fuseau horaire. Sans les commentaires, cela représente probablement moins de 100 lignes de code, il est donc très facile de l’append à votre projet.