2010-03-09 11 views
6

Die Info-Seiten für das GNU date Befehl enthalten dieses Beispiel:Wie programmiere ich eine Zeit von einer Zeitzone in eine andere in C programmatisch um?

Zum Beispiel mit dem GNU date Befehl können Sie die Frage „beantworten Wie spät ist es in New York, als eine Paris Uhr 6 : 30 Uhr am Oktober 31, 2004? " durch ein Datum mit mit `TZ = "Europa/Paris" ab 'wie in die folgende Shell-Transkript gezeigt:

$ export TZ="America/New_York" 
$ date --date='TZ="Europe/Paris" 2004-10-31 06:30' 
Sun Oct 31 01:30:00 EDT 2004 

In diesem Beispiel ist der '--date' Operand beginnt mit seiner eigenen' TZ ' Einstellung, so dass der Rest dieses Operanden nach ' Europa/Paris 'Regeln verarbeitet wird, die Zeichenfolge 2004-10-31 06:30 behandeln, als ob es in Paris wäre. Da die Ausgabe des Befehls date gemäß den gesamten Zeitzonenregeln verarbeitet wird, verwendet sie New York Zeit. (Paris war in der Regel 6 Stunden vor New York im Jahr 2004, aber das Beispiel bezieht sich auf eine kurze Halloween Zeit, als die Lücke 5 Stunden waren.)

Ich versuche, im Wesentlichen die gleiche Sache programmatisch zu erreichen in C ohne das Programm date millionenfach aufzurufen. Im Grunde suche ich nach einer Möglichkeit, ein beliebiges Datum und eine beliebige Zeit in einer Zeitzone zu nehmen und sie in das entsprechende Datum und die Zeit in einer anderen Zeitzone umzuwandeln, entweder direkt oder über die Konvertierung in und aus UTC. Die Formate der Ein- und Ausgabezeit sind mir egal, solange ich sie mit Standardfunktionen manipulieren kann (strftime/strptime/mktime/etc).

Das date Programm scheint dies zu erreichen mit komplexen Routinen innerhalb der coreutils Paket, ich bin auf der Suche nach einer Möglichkeit, dies in C mit entweder Standard-POSIX/Linux-Routinen oder einer externen Bibliothek. Ich schaute auf zoneinfo ziemlich viel, das vielversprechend schien, aber ich kann keine Bibliotheken finden, um irgendetwas nützliches damit zu tun.

Antwort

2

Für Zeit:

  • Holen Sie sich das GMT-Zeit mit gmtime
  • Add/subtrahieren die Stunden von time_t.tm_hour
  • Verwenden mktime

Die Datumsberechnung wird renormieren ähnlich sein aber ein bisschen komplizierter.

+1

Es gibt eine Reihe von subtilen Problemen mit manuellen Berechnungen, die ich vermeiden möchte, wie z. B. DST zu behandeln. Diese Informationen sind in der zoneinfo-Datenbank enthalten, jedoch nicht in einer Weise, die sich für mich bisher als nützlich erwiesen hat. –

+1

Zum Beispiel, diese Arbeit besonders schlecht in Venezuela - das ist offiziell UTC-4: 30 – Quintus

3

Ich habe eine Lösung gefunden, die unter Linux mit glibc zu funktionieren scheint, ich weiß nicht, wie portabel dieses Verhalten ist, Kommentare zur Portabilität oder eine bessere Vorgehensweise wären willkommen.

convert_time.c (kein Fehler aus Gründen der Klarheit überprüft):

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

int main (int argc, char *argv[]) 
{ 
    struct tm mytm = {0}; 
    time_t mytime; 
    char buf[100]; 

    mytm.tm_isdst = -1; 
    putenv(argv[1]); 
    tzset(); 
    strptime(argv[2], "%Y-%m-%d %H:%M", &mytm); 
    mytime = mktime(&mytm); 

    putenv(argv[3]); 
    tzset(); 
    localtime_r(&mytime, &mytm); 
    strftime(buf, 100, "%a, %d %b %Y %H:%M:%S %z(%Z)", &mytm); 
    puts(buf); 

    return 0; 
} 

Das erste Argument ist die Quelle Zeitzone (eigentlich „TZ = Zeitzone“ passieren putenv) Das zweite Argument ist die Zeit, in dem vorgegebenen Format, das letzte Argument ist die Zielzeitzone. Ich benutze zoneinfo-Zeitzonennamen, die glibc unterstützt, indem sie die zoneinfo-Datenbank benutzt.

Die Ergebnisse mehrerer DST Prüfecke Fälle entsprechen den Ergebnissen aus dem Ersatz date Befehl sowie this Website, die die zoneinfo-Datenbank verwendet:

$ ./convert_time "TZ=America/New_York" "2005-05-31 06:30" "TZ=America/Indiana/Indianapolis" 
Tue, 31 May 2005 05:30:00 -0500(EST) 

$ ./convert_time "TZ=America/New_York" "2006-05-31 06:30" "TZ=America/Indiana/Indianapolis" 
Wed, 31 May 2006 06:30:00 -0400(EDT) 

$ ./convert_time "TZ=Europe/Paris" "2004-10-30 06:30" "TZ=America/New_York" 
Sat, 30 Oct 2004 00:30:00 -0400(EDT) 

$ ./convert_time "TZ=Europe/Paris" "2004-10-31 06:30" "TZ=America/New_York" 
Sun, 31 Oct 2004 01:30:00 -0400(EDT) 

$ ./convert_time "TZ=Europe/Paris" "2004-11-01 06:30" "TZ=America/New_York" 
Mon, 01 Nov 2004 00:30:00 -0500(EST) 
+1

Yuck, aber was können Sie tun? Genau das sagt die Manpage: http://www.kernel.org/doc/man-pages/online/pages/man3/timegm.3.html. Es ist einfach schrecklich Thread nicht sicher. – smparkes

0

Ich war eigentlich für die gleiche Antwort suchen Sie getan haben, und das ist die Lösung, die ich mir ausgedacht habe. Das folgende Beispielprogramm verwendet die lokale Systemzeit und konvertiert sie in eine beliebige Zeitzone.

// compile: gcc snippet.c 
// usage: ./a.out Europe/Berlin Pacific/Nauru Asia/Hong_Kong Asia/Kabul 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <time.h> 
#include <errno.h> 

int main(int argc, char *argv[]) 
{ 
     char buf[80]; 
     time_t tt = time(NULL); 
     struct tm tm; 
     int i; 

     if (!localtime_r(&tt, &tm)) { 
       printf("Could not convert time_t to tm struct. %s\n", strerror(errno)); 
       return 1; 
     } 

     printf("time_t: %ld\n", tt); 
     printf("timezone: %ld, %s/%s, daylight:%d\n", timezone, tzname[0], tzname[1], daylight); 
     strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %z %Z", &tm); 
     printf("time: %s\n", buf); 

     for (i = 1; i < argc; ++i) { 
       printf("\ninput: %s\n", argv[i]); 

       snprintf(buf, sizeof(buf), "TZ=%s", argv[i]); 
       putenv(buf); 
       tzset(); 
       printf("\ttimezone: %ld, %s/%s, daylight:%d\n", timezone, tzname[0], tzname[1], daylight); 

       if (!localtime_r(&tt, &tm)) { 
         printf("Could not convert time_t to tm struct. %s\n", strerror(errno)); 
         return 1; 
       } 

       strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %z %Z", &tm); 
       printf("\ttime: %s\n", buf); 
     } 

     return 0; 
} 
Verwandte Themen