これは私が作ることができるほどポータブルです。私はもっと良い解決策に興味があります。私がしたことは、特定の年のAmerica/New_YorkタイムゾーンでDSTの開始日と終了日までの時間を計算し、与えられたtime_t
がその間にあるかどうかをテストすることです。これはAmerica/New_Yorkのタイムゾーンに特有ですが、別のタイムゾーンに簡単に適合させることができます。
GNU Cライブラリを使用する場合、timegm
はGNU.orgに従ってgetenv
、mktime
、setenv
、しかしの代わりに使用することができる。
mktime
は、本質的に普遍的に利用可能です。 timegm
はかなりまれです。 簡単な時間にUTC壊れてダウンタイムから、ほとんどのポータブルの変換のために 、UTC
にTZ
環境変数を設定し、mktime
を呼び出し、その後、 はTZ
バックを設定します。
#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;
}
"ポータブルな方法" - >(POSIX以内)高ポータブル号 - >多分。 postがタグ付けされていないので[POSIX]、POSIXの回答やポータブルな(Standard C)ものを探しているかどうかは不明です。 – chux
DSTが有効かどうかを知りたい*理由*を聞かれますか?あなたはちょうど、 "ちょっとユーザーのようなものを表示することを計画していますか?DSTが現在有効であることを知っていますか?"あなたが試みているもっと複雑なものの中のこの部分ですか?通常、私がこれを尋ねるとき、答えは後者です。解決策は[CCTZ](https://github.com/google/cctz)やHHinnetの[date](http:// howardhinnant .github.io/date_v2.html)と[tz](http://howardhinnant.github.io/tz.html)のライブラリがあります。 –
@chux可能であれば、私は携帯用を探しています。現時点では、コードはPOSIX環境で実行されますが、将来の内容を知っています。 – JB0x2D1