2012-12-10 7 views
14

ich die Standard mktime Funktion bin mit einem struct tm in einer Epoche Zeitwert drehen. Die tm Felder sind lokal bevölkert, und ich brauche die Epoche Zeit als GMT zu bekommen. tm hat ein gmtoff Feld, damit Sie die lokale GMT nur für diesen Zweck in Sekunden Offset einzustellen.die Zeitzone Get Offset GMT in C

Aber ich kann nicht herausfinden, wie bekommen diese Informationen. Sicherlich muss es irgendwo eine Standardfunktion geben, die den Offset zurückgibt? Wie macht localtime es?

+1

"' tm' eine 'gmtoff' Feld hat" -> das ist eine Nicht-Standard-C-Bibliothek Erweiterung. – chux

Antwort

5

Ich denke, ich soll, bevor er fragt ein bisschen mehr auf der Suche getan haben. Es stellt sich heraus, es gibt eine wenig bekannte timegm Funktion, die das Gegenteil von gmtime tut. Es wird auf GNU und BSD unterstützt, was für meine Zwecke gut genug ist. Eine portablere Lösung besteht darin, den Wert der Umgebungsvariablen TZ vorübergehend auf "UTC" zu setzen und dann mktime zu verwenden und dann TZ zurückzusetzen.

Aber timegm funktioniert für mich.

+3

Link sagt "Diese Funktionen sind nicht standardmäßige GNU-Erweiterungen, die auch auf den BSDs vorhanden sind. Vermeiden Sie ihre Verwendung." – satur9nine

0

Ich glaube, die folgenden Aussagen wahr in Linux ist mindestens: Zeitzone Infos von/usr/share kommt/zoneinfo /. Lokalzeit liest/etc/localtime, die eine Kopie der entsprechenden Datei von zoneinfo sein sollte. Sie können sehen, was drin ist, indem Sie zdump -v für die Zeitzonendatei ausführen (zdump kann in sbin sein, aber Sie benötigen keine erhöhten Berechtigungen, um Zeitzonendateien damit zu lesen). Hier ist ein Ausschnitt von einem:

 
/usr/share/zoneinfo/EST5EDT Sun Nov 6 05:59:59 2033 UTC = Sun Nov 6 01:59:59 2033 EDT isdst=1 gmtoff=-14400 
/usr/share/zoneinfo/EST5EDT Sun Nov 6 06:00:00 2033 UTC = Sun Nov 6 01:00:00 2033 EST isdst=0 gmtoff=-18000 
/usr/share/zoneinfo/EST5EDT Sun Mar 12 06:59:59 2034 UTC = Sun Mar 12 01:59:59 2034 EST isdst=0 gmtoff=-18000 
/usr/share/zoneinfo/EST5EDT Sun Mar 12 07:00:00 2034 UTC = Sun Mar 12 03:00:00 2034 EDT isdst=1 gmtoff=-14400 
/usr/share/zoneinfo/EST5EDT Sun Nov 5 05:59:59 2034 UTC = Sun Nov 5 01:59:59 2034 EDT

Ich denke, Sie könnten dies selbst analysieren, wenn Sie wollen. Ich bin nicht sicher, ob es eine stdlib Funktion ist, die nur die gmtoff gibt (es gut sein kann, aber ich weiß nicht, ...)

edit: Mann tzfile beschreibt das Format der Datei zoneinfo. Sie sollten in der Lage sein, einfach in eine Struktur des entsprechenden Typs zu mappen. Es scheint so zu sein, was zdump basierend auf einem strace tut.

19

tun gerade folgenden:

#define _GNU_SOURCE /* for tm_gmtoff and tm_zone */ 

#include <stdio.h> 
#include <time.h> 

/* Checking errors returned by system calls was omitted for the sake of readability. */ 
int main(void) 
{ 
    time_t t = time(NULL); 
    struct tm lt = {0}; 

    localtime_r(&t, &lt); 

    printf("Offset to GMT is %lds.\n", lt.tm_gmtoff); 
    printf("The time zone is '%s'.\n", lt.tm_zone); 

    return 0; 
} 

Hinweis: Die Sekunden seit Epoche zurück von time() gemessen werden, als ob in Greenwich.

+0

Ich mag diese einfache Lösung, aber ich habe ein Problem mit Ihrem Code gefunden. Ich denke, 'struct tm = {0};' sollte 'struct tm result = {0};' sein und dann können Sie 'result' anstelle von' tm' im Rest des Codes verwenden. +1 von mir, wenn du das ändern könntest. – Serrano

+3

Auch ich würde gerne den Code für Windows sehen. Jede Hilfe wird geschätzt! –

+2

'tm_gmtoff, tm_zone' sind Nicht-C-Std-Erweiterungen. – chux

4

Wie Localtime es tun?

Nach localtime Manpage

Die Localtime() Funktion wirkt, als ob es tzset (3) genannt und stellt die externen Variablen tzname mit Informationen über die aktuelle Zeitzone, Zeitzone mit dem Unterschied zwischen Coordinated Universal Zeit (UTC) und lokale Standardzeit in Sekunden

So könnte man entweder localtime() anrufen und Sie werden den Unterschied in timezone oder rufen tzset() haben:

extern long timezone; 
.... 
tzset(); 
printf("%ld\n", timezone); 

Hinweis: Wenn Sie mit localtime_r() Notiz wählen gehen, dass es nicht diese Variablen setzen erforderlich ist, die Sie benötigen rufen tzset() erste timezone setzen:

nach POSIX.1-2004, localtime() erforderlich ist, als ob tzset() zu verhalten genannt wurde, während localtime_r() hav nicht e diese Anforderung.Für tragbaren Code tzset() soll vor localtime_r() aufgerufen werden

2

Die universelle Version des Erhaltens der lokalen Zeitversatzfunktion ist hier.
Ich habe Teile des Codes von the answer in statckoverflow ausgeliehen.

int time_offset() 
{ 
    time_t gmt, rawtime = time(NULL); 
    struct tm *ptm; 

#if !defined(WIN32) 
    struct tm gbuf; 
    ptm = gmtime_r(&rawtime, &gbuf); 
#else 
    ptm = gmtime(&rawtime); 
#endif 
    // Request that mktime() looksup dst in timezone database 
    ptm->tm_isdst = -1; 
    gmt = mktime(ptm); 

    return (int)difftime(rawtime, gmt); 
}