Konvertiert Datum und Zeit, zahlen zu time_t UND geben Sie die Zeitzone
Habe ich die folgenden ganzen zahlen:
int y, mon, d, h, min, s;
Ihre Werte sind: 2012
, 06
, 27
, 12
, 47
, 53
bzw. Ich möchte zum darstellen des Datum-Zeit "2012/06/27 12:47:53 UTC -" wenn ich gewählt haben, 'UTC' irgendwo anders in meiner Anwendung, oder "2012/06/27 12:47:53 AEST" wenn ich gewählt haben, 'US /Eastern' irgendwo anders in meiner Anwendung.
Will ich wandeln diese in eine time_t
, und hier ist der code, ich bin aktuell mit zu tun:
struct tm timeinfo;
timeinfo.tm_year = year - 1900;
timeinfo.tm_mon = mon - 1;
timeinfo.tm_mday = day;
timeinfo.tm_hour = hour;
timeinfo.tm_min = min;
timeinfo.tm_sec = sec;
//timeinfo.tm_isdst = 0; //TODO should this be set?
//TODO find POSIX or C standard way to do covert tm to time_t without in UTC instead of local time
#ifdef UNIX
return timegm(&timeinfo);
#else
return mktime(&timeinfo); //FIXME Still incorrect
#endif
So, ich bin mit einem tm struct
und mktime
werden, das ist aber nicht gut, denn es wird immer vorausgesetzt, meine lokale Zeitzone.
Was ist der richtige Weg, dies zu tun?
Also unten ist die Lösung, die ich kommen mit so weit.
Es im Grunde genommen drei Dinge:
- Wenn UNIX, verwenden Sie einfach
timegm
- Wenn nicht UNIX
- Entweder, rechnen die Differenz zwischen UTC-Zeit und lokaler Zeit als ein offset
- Reservierung: Mathe kann falsch sein,
- Oder die "TZ" - Umgebungsvariable auf UTC zeitweise
- Reservierung: wird die Reise, wenn/wenn dieser code muss Multithread
- Entweder, rechnen die Differenz zwischen UTC-Zeit und lokaler Zeit als ein offset
namespace tmUtil
{
int const tm_yearCorrection = -1900;
int const tm_monthCorrection = -1;
int const tm_isdst_dontKnow = -1;
#if !defined(DEBUG_DATETIME_TIMEGM_ENVVARTZ) && !(defined(UNIX) && !defined(DEBUG_DATETIME_TIMEGM))
static bool isLeap(int year)
{
return
(year % 4) ? false
: (year % 100) ? true
: (year % 400) ? false
: true;
}
static int daysIn(int year)
{
return isLeap(year) ? 366 : 365;
}
#endif
}
time_t utc(int year, int mon, int day, int hour, int min, int sec)
{
struct tm time = {0};
time.tm_year = year + tmUtil::tm_yearCorrection;
time.tm_mon = mon + tmUtil::tm_monthCorrection;
time.tm_mday = day;
time.tm_hour = hour;
time.tm_min = min;
time.tm_sec = sec;
time.tm_isdst = tmUtil::tm_isdst_dontKnow;
#if defined(UNIX) && !defined(DEBUG_DATETIME_TIMEGM) //TODO remove && 00
time_t result;
result = timegm(&time);
return result;
#else
#if !defined(DEBUG_DATETIME_TIMEGM_ENVVARTZ)
//TODO check that math is correct
time_t fromEpochUtc = mktime(&time);
struct tm localData;
struct tm utcData;
struct tm* loc = localtime_r (&fromEpochUtc, &localData);
struct tm* utc = gmtime_r (&fromEpochUtc, &utcData);
int utcYear = utc->tm_year - tmUtil::tm_yearCorrection;
int gmtOff =
(loc-> tm_sec - utc-> tm_sec)
+ (loc-> tm_min - utc-> tm_min) * 60
+ (loc->tm_hour - utc->tm_hour) * 60 * 60
+ (loc->tm_yday - utc->tm_yday) * 60 * 60 * 24
+ (loc->tm_year - utc->tm_year) * 60 * 60 * 24 * tmUtil::daysIn(utcYear);
#ifdef UNIX
if (loc->tm_gmtoff != gmtOff)
{
StringBuilder err("loc->tm_gmtoff=", StringBuilder((int)(loc->tm_gmtoff)), " but gmtOff=", StringBuilder(gmtOff));
THROWEXCEPTION(err);
}
#endif
int resultInt = fromEpochUtc + gmtOff;
time_t result;
result = (time_t)resultInt;
return result;
#else
//TODO Find a way to do this without manipulating environment variables
time_t result;
char *tz;
tz = getenv("TZ");
setenv("TZ", "", 1);
tzset();
result = mktime(&time);
if (tz)
setenv("TZ", tz, 1);
else
unsetenv("TZ");
tzset();
return result;
#endif
#endif
}
N. B. StringBuilder
ist eine interne Klasse, es spielt keine Rolle, für die Zwecke dieser Frage.
Mehr info:
Ich weiß, dass dies kann leicht getan werden mit boost, et al. Aber das ist KEINE option. Ich muss es getan werden rechnerisch oder mit Hilfe eines c-oder c++ - standard-Funktion, oder Kombinationen davon.
timegm
angezeigt wird, um dieses problem zu lösen, aber es scheint nicht Teil der C /POSIX-standard. Dieser code ist derzeit zusammengestellt, die auf mehreren Plattformen (Linux, OSX, WIndows, iOS, Android (NDK)), so muss ich einen Weg finden, damit es funktioniert auf allen diesen Plattformen, auch wenn die Lösung umfasst #ifdef $PLATFORM
Art Dinge.
- Haben Sie andere Bibliotheken? Sie haben eine Liste von Zeitzonen & Ihre offsets?
- Nein, ich will nicht zu verwenden Bibliotheken, wie Sie entstehen viel Entwicklungsaufwand bei der cross-Compilierung. Auch, Nein, ich habe nicht eine Liste von Zeitzonen und deren offsets. Werfen Sie einen Blick auf mein update oben, ich habe es in einer Weise zu berechnen, Zeitzone offsets - sieht es richtige für Sie?
- <HÄSSLICHER HACK> könnte Man es in einen string konvertieren mit
strftime()
ersetzen Sie die Zeitzone in den string und konvertieren Sie es dann zurück mitmktime(strptime())
</HÄSSLICHER HACK>, aber ich würde einfach davon überzeugen, die Kräfte, die sein, dass der boost ist in der Tat eine option. - Könntest du posten, dass da eine Antwort?
- Sicher, aber ich bin tatsächlich ein bisschen beschämt, dass ich sogar gepostet als Kommentar 🙂
- auch wenn, wie Sie sagen, es ist hässlich (nicht zu erwähnen, nicht sehr effizient), es bedeutet, dass ich [1] nicht zu tun, keine Mathematik (und haben zu sorgen über deren Richtigkeit), oder [2] Bearbeiten alle Umgebungsvariablen (und sorgen multi-threading-Probleme), also die Vermeidung der Fallstricke der beiden Methoden, die ich kommen mit so weit. So können Sie beantworten würde intakt!
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es macht mich wollen, um zu werfen in meinem Mund ein bisschen, aber man könnte es in einen string konvertieren mit
strftime()
ersetzen Sie die Zeitzone in den string und konvertieren Sie es dann zurück mitstrptime()
und in einetime_t
mitmktime()
. Im detail:Allerdings würde ich empfehlen, Sie zu überzeugen, die Kräfte, die für die Erhöhung ist eine option, nachdem alle. Boost hat große Unterstützung für benutzerdefinierte Zeitzonen. Gibt es andere Bibliotheken, die dies tun, aus sowie.
Wenn alle Sie wollen, ist zu konvertieren
struct tm
- Uhr in UTC zu einemtime_t
dann kannst du es so machen:Diese im Grunde konvertiert die UTC-Zeit zu
time_t
als ob der gegebenen Zeit vor Ort ist, dann gilt eine Zeitzone Korrektur um das Ergebnis, um es wieder zu UTC.Getestet auf gcc/cygwin und Visual Studio 2010.
Ich hoffe, das hilft!
Update: Wie man sehr gut darauf hingewiesen, meine Lösung oben zurückkehren können time_t-Wert, der eine Stunde aus, wenn das Tageslicht Zeitersparnis Zustand der abgefragten Datum ist anders als die, die für die aktuelle Zeit.
Die Lösung für dieses problem ist, um eine zusätzliche Funktion, die Ihnen sagen kann, ob ein bestimmtes Datum fällt in die Sommerzeit-region oder nicht, und nutzen, und die aktuellen DST-flag, um die Zeit anzupassen zurückgegeben
mktime
. Dies ist eigentlich einfach zu tun. Wenn Sie anrufenmktime()
Sie müssen nur legen Sie dietm_dst
Mitglied auf -1 und dann das system wird sein bestes tun, um herauszufinden, die Sommerzeit in der gegebenen Zeit für Sie. Vorausgesetzt, wir Vertrauen, dass das system auf dieser, dann können Sie diese Informationen verwenden, um eine Korrektur:timezone
imtime.h
repräsentiert die Differenz in der Zeit von UTC auf den gegenwärtigen Augenblick, und nicht am Punkt der Zeit, die Sie berechnen. Dies bedeutet, dass die Zeit berechnet werden, wird von einer Stunde deaktiviert, wenn Sie sind Rechenzeiten, die auf der gegenüberliegenden Tageslicht Einsparungen Zeit, dass Sie derzeit in (6 Monate pro Jahr). Haben Sie dies berücksichtigt wird; oder korrigieren Sie mich, wenn ich mich nicht Irre?Wenn Sie auf Linux oder anderen UNIx-oder UNIX-like system ist, dann haben Sie vielleicht eine
timegm
Funktion, die tut, was Sie wollen. Die verlinkten manual-Seite haben, eine portable Implementierung, so dass Sie machen es selbst. Unter Windows kenne ich keine solche Funktion.Nachdem ich mein Kopf gegen diese für Tage zu versuchen einen
timegm(1)
- Funktion, die funktioniert auf Android (was nicht Schiff mit ein), habe ich schließlich entdeckt, diese einfache und elegante Lösung, die wunderbar funktioniert:Ich sehe nicht ein, warum wäre dies nicht eine geeignete, Plattform-übergreifende Lösung.
Ich hoffe, das hilft!
tm_gmtoff
ist nicht tragbar.Scheint es eine einfachere Lösung:
Eigentlich habe ich nicht getestet aber wenn es wirklich funktioniert, denn ich habe noch ein bisschen bei der Portierung zu tun, aber es kompiliert.
Hier ist meine Lösung:
Sollte diese Arbeit sowohl für unix-und windows -