Comment faire pour convertir de l'heure UTC en heure locale en C?
C'est une question simple, mais la solution semble être loin d'être simple. Je voudrais savoir comment faire pour convertir de l'heure UTC en heure locale. Je suis à la recherche d'une solution dans C, de série et de plus ou moins garanti pour fonctionner sur n'importe quel ordinateur à n'importe quel endroit.
J'ai lu les liens suivants attentivement, mais je ne peux pas y trouver une solution:
La conversion de chaîne de caractères contenant localtime en UTC, dans C
La conversion Entre l'heure Locale et l'heure GMT/UTC en C/C++
J'ai essayé un certain nombre de variations, telles que (datetime est une chaîne avec la date et l'heure UTC):
strptime(datetime, "%A %B %d %Y %H %M %S", tp);
strftime(printtime, strlen(datetime), "%A %B %d %Y %H %M %S", tp);
Ou
strptime(datetime, "%A %B %d %Y %H %M %S", tp);
lt=mktime(tp);
printtime=ctime(<);
Peu importe ce que j'essaie printtime finit par être le même que l'UTC.
Modifier 11-29-2013: basé sur le très utile de répondre par "R" ci-dessous j'ai enfin réussi à créer un exemple de travail. Je l'ai trouvé de travail correct dans les deux fuseaux horaires je l'ai testé, HEC et PST:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
long long diff_tm(struct tm *a, struct tm *b)
{
return a->tm_sec - b->tm_sec
+60LL*(a->tm_min - b->tm_min)
+3600LL*(a->tm_hour - b->tm_hour)
+86400LL*(a->tm_yday - b->tm_yday)
+(a->tm_year-70)*31536000LL
-(a->tm_year-69)/4*86400LL
+(a->tm_year-1)/100*86400LL
-(a->tm_year+299)/400*86400LL
-(b->tm_year-70)*31536000LL
+(b->tm_year-69)/4*86400LL
-(b->tm_year-1)/100*86400LL
+(b->tm_year+299)/400*86400LL;
}
int main()
{
time_t utc, local;
char buf[100];
const char datetime[]="2013 11 30 23 30 26 UTC"; /* hard coded date and time in UTC */
struct tm *tp=malloc(sizeof(struct tm));
if(tp==NULL)
exit(-1);
struct tm *localt=malloc(sizeof(struct tm));
if(localt==NULL)
exit(-1);
memset(tp, 0, sizeof(struct tm));
memset(localt, 0, sizeof(struct tm));
printf("UTC date and time to be converted in local time: %s\n", datetime);
/* put values of datetime into time structure *tp */
strptime(datetime, "%Y %m %d %H %M %S %z", tp);
/* get seconds since EPOCH for this time */
utc=mktime(tp);
printf("UTC date and time in seconds since EPOCH: %d\n", utc);
/* lets convert this UTC date and time to local date and time */
struct tm e0={ .tm_year = 70, .tm_mday = 1 }, e1, new;
/* get time_t EPOCH value for e0 (Jan. 1, 1970) */
time_t pseudo=mktime(&e0);
/* get gmtime for this value */
e1=*gmtime(&pseudo);
/* calculate local time in seconds since EPOCH */
e0.tm_sec += utc - diff_tm(&e1, &e0);
/* assign to local, this can all can be coded shorter but I attempted to increase clarity */
local=e0.tm_sec;
printf("local date and time in seconds since EPOCH: %d\n", local);
/* convert seconds since EPOCH for local time into localt time structure */
localt=localtime(&local);
/* get nicely formatted human readable time */
strftime(buf, sizeof buf, "%Y-%m-%d %H:%M:%S %Z", localt);
printf("local date and time: %s\n", buf);
}
Il devrait compiler sans problème sur la plupart des systèmes. J'ai codé en dur date et de l'heure en UTC qui seront ensuite convertis à la date et l'heure locale.
strptime
) ou tout simplement C?Désolé manqué que, oui, vous pouvez supposer POSIX.
OriginalL'auteur aseq | 2012-01-31
Vous devez vous connecter pour publier un commentaire.
Si vous pouvez supposer POSIX (et donc la spécification POSIX de
time_t
en secondes depuis l'époque), je voudrais tout d'abord utiliser la POSIX formule pour convertir de secondes depuis l'epoch:Ensuite, utilisez
localtime((time_t []){0})
pour obtenir unstruct tm
représentant de l'époque dans l'heure locale. Ajouter les secondes depuis l'époque de latm_sec
champ de cettestruct tm
, puis d'appelermktime
à accepter.Edit: en Fait la seule POSIX dépendance est d'avoir connu une époque qui
(time_t)0
correspond à. Peut-être vous pouvez trouver un moyen de contourner cela, si vous avez vraiment besoin de... par exemple à l'aide d'appels à la foisgmtime
etlocaltime
àtime_t
0..Edit 2: Une esquisse de la façon de le faire:
S'il vous plaît ne pas l'esprit de la laide de code de sortie. Ce programme prend un argument sous la forme de "secondes par rapport à la norme POSIX époque" et les sorties de l'résultant heure en heure locale. Vous pouvez convertir n'importe quelle heure UTC de secondes depuis l'epoch à l'aide de la formule que j'ai cité ci-dessus. Notez que ce code ne dépend en aucune façon POSIX, mais il suppose le décalage retourné par
diff_tm
combiné avec le nombre de secondes depuis l'epoch valeur ne déborde pasint
. Un correctif pour ce qui serait d'utiliser unlong long
offset et une boucle qui ne cesse d'ajouter de incréments pas plus grand queINT_MAX/2
(ou plus petit queINT_MIN/2)
et de l'appel demktime
d'effectuer une renormalisation jusqu'à ce que le décalage atteint 0.Il n'a pas besoin d'être le même. La seule raison pour laquelle vous avez besoin de la calculer est d'obtenir l'ajustement de l'offset en quelques secondes à partir de la "epoch" dans localtime de sorte que vous pouvez faire de la dénormalisée
struct tm
dans localtime format puis la passer àmktime
pour la normalisation.Voir mon montage....
Merci pour cette réponse. Je vais l'essayer et de vous laisser savoir comment il s'est avéré.
BTW, il est vraiment malade que C fait, vous aller à de telles longueurs de travailler avec normalisé temps dans un façon saine. Juste un UTC équivalent de la
mktime
fonction permettrait d'éviter que l'ensemble de la question. Au moins l'approche ci-dessus peut être utilisé pour faire une telle fonction...OriginalL'auteur R..
Ahm ... j'ai peut-être juste un débutant en C, mais j'ai eu ce travail exemple:
Qui produit la sortie suivante:
Vous avez maintenant la différence entre l'heure UTC et l'heure locale en quelques secondes. Cela devrait être suffisant pour le convertir.
Une note à votre code, l'aseq: vous êtes à l'aide de malloc sans besoin ici (vous pouvez memset valeurs sur la pile, et le malloc peut être coûteux alors que l'allocation de pile est souvent beaucoup plus rapide), et vous n'avez pas libre. C'est très, très mauvaise pratique.
Autre chose:
Serait mieux fait, si vous voulez passer sizeof(*tp) (ou, si vous mettez de la tp sur la pile, sizeof(tp)) à memset. Qui assure que même si le type de votre objet de modifications, il sera toujours entièrement memset.
Aujourd'hui, je n'aurais même pas l'écrire de cette façon. La raison pour cela est parce que mktime n'est pas réentrant (il touche le global variable TZ, si je ne me trompe pas), et peut exploser à tout moment. Ce qui est un énorme échec, à mon avis ... mais encore une fois, les gens qui normalisé de l'API avais d'autres choses à se soucier. Cependant, il n'est pas sain d'esprit façon de le faire. R.. déjà montré une bonne façon de calculer la date par vous-même. Il est malheureux que vous avez à transporter le long de cette fonction pour une tâche aussi terre à terre, mais d'un autre côté, ça prend une éternité pour publier des normes plus récentes.
À partir de la les pages de manuel de mktime(): une valeur positive signifie que l'heure d'été est en vigueur; zéro signifie que l'heure d'été n'est pas en effet; et une valeur négative signifie que mktime () (utiliser le fuseau horaire de l'information et des bases de données système) pour tenter de déterminer si l'heure d'été est en vigueur à l'heure spécifiée. Cependant, plus tard, il dit tm_isdst est défini (indépendamment de sa valeur initiale) à une valeur positive ou à 0, respectivement, pour indiquer si l'heure d'été est ou n'est pas, en effet, à l'heure spécifiée, mais le comportement semble être de faire confiance à la valeur de
tm_isdst
sur entréeOriginalL'auteur Dachschaden
Pour résumer: la conversion d'un ventilées date (struct tm) UTC à un (local) calendar time (time_t) est réalisé avec timegm() - à l'opposé de mktime() - MAIS timegm() n'est pas une fonction standard (la façon dont la logique est que).
Le C standard, nous laisse avec seulement de temps(), gmtime(), mktime() et difftime().
Une solution de contournement trouvé dans d'autres docs conseille à émuler timegm() en définissant d'abord la variable d'environnement TZ pour une chaîne nulle, alors l'appel de mktime() résultant en une heure UTC calendrier de temps, puis réinitialiser la LIMITE de sa valeur initiale, mais encore une fois, ce n'est pas la norme.
Fondamentalement, ce que je comprends, la différence entre l'heure locale et l'heure UTC est juste un décalage de sorte que si nous pouvons évaluer que l'offset, nous pouvons ajuster le résultat de mktime(), voici donc ma proposition:
Un test rapide:
Aussi, il est important de se rappeler que mktime est pas réentrant (et contrairement à localtime & gmtime, il n'est pas évident à partir de la signature de la fonction), car il modifie le mondial fuseau horaire variable. Donc ce code , semblent fonctionner, mais n'importe quel autre thread qui fait un mktime peuvent briser complètement à votre sortie.
OriginalL'auteur 0xFC
OriginalL'auteur Denes Borsos
J'ai trouvé que la solution de l'OP a donné ne fonctionne pas dans les cas où l'heure s'applique. Par exemple, dans mon cas, à l'heure actuelle, l'heure d'été n'était pas en effet, mais si j'ai mis la date initiale qui devraient se convertir à l'heure locale avec de l'heure d'été, alors il ne serait pas de travail, c'est à dire la date d'aujourd'hui est 3/1/2018 et de l'heure d'été n'est pas en effet, mais si j'ai mis la date de la conversion, disons, 8/1/2018 0:00:00 lorsque l'heure d'été est en effet, alors la solution serait de convertir à l'heure locale, mais de ne pas prendre en compte de l'heure d'été. J'ai trouvé que l'initialisation d'
e0
à la date et l'heure de la première chaîne de date/heure et de ses étatstm_isdst
à-1
résolu le problème. Ensuite, j'ai créé le programme suivant avec des fonctions complémentaires que vous pouvez inclure dans votre code. Le format de la date et de l'heure est la même que MySQL utilise, car j'en avais besoin pour de telles fins.OriginalL'auteur Nikola Novak
Je pense que c'est plus simple que cela; le temps.h définit trois variables:
qui sont chargés d'après le TZ env variable lorsque vous appelez
si vous avez une heure utc dans
convertir un time_t à l'aide de mktime
puis de le convertir en heure locale
fuseau horaire est le nombre de secondes de l'heure utc pour le fuseau horaire actuel et la lumière du jour est de 1 pour indiquer l'heure d'été est en jeu et zéro pour ne pas.
Une petite précaution: Lorsque j'ai codé ce pour un microcontrôleur et de cross-compilé, il est temps.h défini les variables initiales, des traits de soulignement.
Voir la page de man pour le moment.h
OriginalL'auteur Jim Brannan
J'ai suivi la réponse par @Dachschaden et j'ai fait un exemple qui montre également lisible par l'homme, de sortie et je supprime l'option de l'heure d'été pour la différence en secondes entre l'heure UTC et l'heure locale. Ici, il est:
Sortie sur ma machine est:
Noter que l'heure d'été est sur dans ce cas (il y a 1 heure de décalage horaire décalage entre l'heure UTC et l'heure LOCALE).
OriginalL'auteur ChisholmKyle
goûter, sortie de test:
utcEpochTime: 1487652688, localEpochTime: 1487699488, diff: 46800
la diff est de 13 heures, ce qui est bien, comme mon fuseau horaire est UTC+8.
OriginalL'auteur Ted Feng
Un moyen simple et efficace: Ajouter (ou soustraire) le nombre de secondes entre votre fuseau horaire et l'heure UTC (en tenant compte de l'heure d'été).
Comme un exemple qui a très bien fonctionné il y a une minute, sur décembre 30, en 2017, avec les états-UNIS Heure normale des rocheuses (pas de DST), qui est de 7 heures derrière UTC:
Profiter.
OriginalL'auteur user3341673
Il semblerait que vous n'avez jamais réellement lu la question. pour ne pas mentionner votre code s'appuie sur un chemin particulier et la structure de répertoire pour le travail. essayez plus difficile de travailler dans les questions paramètres la prochaine fois.
OriginalL'auteur zhaixiaohu