Dies ist so tragbar, wie ich es machen könnte. Ich wäre an einer besseren Lösung interessiert. Was ich getan habe, ist die Zeit von Epoche bis Beginn und Ende der Sommerzeit in der Zeitzone Amerika/New_York für ein bestimmtes Jahr zu berechnen und zu testen, ob die angegebene time_t
dazwischen liegt. Dies ist spezifisch für die Zeitzone Amerika/New_York, aber ich könnte mir vorstellen, dass es leicht mit einer gewissen Anstrengung für eine andere Zeitzone angepasst oder für alle/alle Zeitzonen angepasst werden könnte.
Wenn die GNU C Library verwenden, können timegm
anstelle von getenv
, verwendet werden mktime
, setenv
, aber nach GNU.org:
mktime
ist im Wesentlichen universell verfügbar. timegm
ist eher selten. Für die meisten tragbare Umwandlung von einer UTC kaputten Zeit auf eine einfache Zeit, stellen Sie den TZ
Umgebungsvariable UTC
, mktime
nennt, dann setzen TZ
zurück.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
/***********************************************\
* In America/New_York:
* DST begins: second Sunday in March 02:00 local, after which EDT == UTC-04:00
* DST ends: first Sunday in November 02:00 local, after which EST == UTC-05:00
\***********************************************/
//Return 1 if the year at UTC is greater than the year in America/New_York at
//the given time t. In other words, at time t, is it between 00:00:00 UTC
//(midnight) Jan 1 and 05:00:00 UTC Jan 1. Return 0 if the year at UTC is the
//same as America/New_York at time t.
int UTCyearIsGreater(time_t when) {
time_t begin, end;
struct tm* tm;
tm = gmtime(&when);
if (tm->tm_mon == 11 && tm->tm_mday == 31 &&
(tm->tm_hour >= 19 && tm->tm_hour < 5)) {
return 1;
}
return 0;
}
//Return number of seconds from epoch until DST begins/began in America/New_York, the second Sunday in March (ssim).
//for the given year.
time_t ssim(int year) {
time_t t, t2;
int sim = 0;
struct tm tm = {0};
tm.tm_year = year;
tm.tm_mon = 2;
tm.tm_mday = 1;
tm.tm_hour = 7;
char* env;
env = getenv("TZ");
setenv("TZ", "UTC", 1);
t = mktime(&tm);
tm = *gmtime(&t);
while (sim < 2) {
if (tm.tm_wday == 0) {
sim += 1;
if (sim == 2) { break; }
}
tm.tm_mday += 1;
tm.tm_wday = 0;
t = mktime(&tm);
tm = *gmtime(&t);
}
t = mktime(&tm);
if (env == NULL) {
unsetenv("TZ");
} else {
setenv("TZ", env, 1);
}
return t;
}
//Return number of seconds from epoch until DST ends/ended in America/New_York, the first Sunday in November (fsin).
//for the given year.
time_t fsin(int year) {
time_t t;
struct tm tm = {0};
tm.tm_year = year;
tm.tm_mon = 10;
tm.tm_mday = 1;
tm.tm_hour = 6;
char* env;
env = getenv("TZ");
setenv("TZ", "UTC", 1);
t = mktime(&tm);
tm = *gmtime(&t);
while (1) {
if (tm.tm_wday == 0) { break; }
tm.tm_mday += 1;
tm.tm_wday = 0;
t = mktime(&tm);
tm = *gmtime(&t);
}
t = mktime(&tm);
if (env == NULL) {
unsetenv("TZ");
} else {
setenv("TZ", env, 1);
}
return t;
}
//Return 1 if DST is in effect in America/New_York at time t, return 0 otherwise
int DSTinNYC(time_t t) {
time_t beginDST, endDST;
struct tm* tm_ptr;
tm_ptr = gmtime(&t);
if (UTCyearIsGreater(t)) {
tm_ptr->tm_year -= 1;
}
beginDST = ssim(tm_ptr->tm_year);
endDST = fsin(tm_ptr->tm_year);
return (t >= beginDST && t < endDST);
}
int main() {
//test it
if (DSTinNYC(1461179392)) {
printf("CORRECT 20 Apr 2016 15:09:52 EDT\n");
} else {
printf("FAILED 20 Apr 2016 15:09:52 EDT\n");
}
if (DSTinNYC(1455993975)) {
printf("FAILED 20 Feb 2016 13:46:15 EST\n");
} else {
printf("CORRECT 20 Feb 2016 13:46:15 EST\n");
}
if (DSTinNYC(1571179392)) {
printf("CORRECT 15 Oct 2019 18:43:12 EDT\n");
} else {
printf("FAILED 15 Oct 2019 18:43:12 EDT\n");
}
//results checked with http://www.epochconverter.com/
return 0;
}
"portable Weg" -> Nein. Leicht zu transportieren (innerhalb POSIX) -> vielleicht. Da Post nicht [POSIX] markiert ist, ist unklar, ob Sie eine POSIX-Antwort oder eine portable (Standard C) Antwort suchen. – chux
Kann ich fragen * warum * Sie wollen wissen, ob DST in Kraft ist? Planen Sie gerade etwas wie "Hey Benutzer, wussten Sie, DST ist gerade in Kraft?" oder ist das ein Teil in etwas Komplexer, das du versuchst? Normalerweise, wenn ich das frage, ist die Antwort die letztere, und die Lösung besteht darin, eine Bibliothek wie [CCTZ] (https://github.com/google/cctz) oder HHinnets [Datum] (http: // howardhinnant .github.io/date_v2.html) und [tz] (http://howardhinnant.github.io/tz.html) Bibliotheken. –
@chux Ich suche portabel, wenn möglich. Ab sofort läuft der Code in POSIX-Umgebungen, aber wer weiß, was die Zukunft bringt. – JB0x2D1