2016-04-19 16 views
1

time_tで指定されたタイムゾーンで夏時間が有効かどうかをどのように判断できますか?私はreadだ "POSIXシステムでは、ユーザーがTZ環境変数でタイムゾーンを指定することができます。現在のTZ値(設定されている場合)を保存し、TZに変更したい場合は、localtime()に電話し、tm_isdstにチェックを入れ、元の値に戻してください。私はちょうどどのようにポータブルであるか分からない。time_t指定のタイムゾーンでDSTが有効かどうかを確認します。

C言語でtime_tと指定されたタイムゾーンのDSTを判別するポータブルな方法はありますか?

+0

"ポータブルな方法" - >(POSIX以内)高ポータブル号 - >多分。 postがタグ付けされていないので[POSIX]、POSIXの回答やポータブルな(Standard C)ものを探しているかどうかは不明です。 – chux

+0

DSTが有効かどうかを知りたい*理由*を聞かれますか?あなたはちょうど、 "ちょっとユーザーのようなものを表示することを計画していますか?DSTが現在有効であることを知っていますか?"あなたが試みているもっと複雑なものの中のこの部分ですか?通常、私がこれを尋ねるとき、答えは後者です。解決策は[CCTZ](https://github.com/google/cctz)やHHinnetの[date](http:// howardhinnant .github.io/date_v2.html)と[tz](http://howardhinnant.github.io/tz.html)のライブラリがあります。 –

+0

@chux可能であれば、私は携帯用を探しています。現時点では、コードはPOSIX環境で実行されますが、将来の内容を知っています。 – JB0x2D1

答えて

1

これは私が作ることができるほどポータブルです。私はもっ​​と良い解決策に興味があります。私がしたことは、特定の年のAmerica/New_YorkタイムゾーンでDSTの開始日と終了日までの時間を計算し、与えられたtime_tがその間にあるかどうかをテストすることです。これはAmerica/New_Yorkのタイムゾーンに特有ですが、別のタイムゾーンに簡単に適合させることができます。

GNU Cライブラリを使用する場合、timegmGNU.orgに従ってgetenvmktimesetenvしかしの代わりに使用することができる。

mktimeは、本質的に普遍的に利用可能です。 timegmはかなりまれです。 簡単な時間にUTC壊れてダウンタイムから、ほとんどのポータブルの変換のために 、UTCTZ環境変数を設定し、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; 
} 
+0

これは、ニューヨークのDSTトランジションの*現在の*セットにも制限されています。米国は2007年にルールを変更したが、他の国々は常に変化している。これがPOSIXの 'TZ'変数が十分ではない理由です。それらは2つの遷移のみをサポートすることができ、年々の変化を処理することはできません。これを正しく行うには、[TZデータベース](https://en.wikipedia.org/wiki/Tz_database)が不可欠です。 –

+0

BTW - あなたのコードは本質的に 'EST5EDT、M3.2.0/2、M11.1.0/2'のPOSIX TZ varの効果を再現します –

+0

本当ですが、実行可能なCライブラリがなければ何ができますか? – JB0x2D1

関連する問題