web-dev-qa-db-ja.com

mktimeおよびtm_isdst

いろいろな見方があったので、ここで聞いてみようと思いました。

man mktimeを読みました:

 (A positive or zero value for tm_isdst causes mktime() to presume initially
 that summer time (for example, Daylight Saving Time) is or is not in
 effect for the specified time, respectively.  A negative value for
 tm_isdst causes the mktime() function to attempt to divine whether summer
 time is in effect for the specified time. 

私の質問は、tm_isdst-1として保持して、システムにdstかどうかを判断させ、コードがdstに依存しないようにするべきではないかということです。

私は何かが足りないのですか?

16
hari

その本来の理由は、一部のタイムゾーンに夏時間がないことだと思います。 mktimeは非同期セーフではなく、再入可能でもないため、実装では、夏時間[0または1]でインデックス付けされたPOSIX extern char tzname [2]に夏時間の現在の値を格納できます。これは、tzname [0] = "[std TZname]"およびtzname = "[daylight TZ name、例:EDT]"を意味します。

詳細については、tzset()のマニュアルページを参照してください。 mktime()に準拠する標準は、とにかくtzset()を呼び出すかのように動作する必要があります。この種の場合、tm_isdst、IMOの使用が不要になります。

結論:特定の実装とタイムゾーンによって、tm_isdstに-1、0、または1を使用するかどうかが決まります。すべての実装に対して、デフォルトで正しい方法は1つではありません。

4
jim mcnamara

可能であれば、tm_isdstを-1に設定しないでください。システムは、日付と時刻だけからDSTステータスを常に判断できるとは限りません。 DSTが終了する前後の1時間はあいまいです。たとえば、2012年11月4日午前1時30分にmktime()を渡した場合、mktime()から正しい_time_t_値を取得するには十分な情報ではありません。通常、mktime()があいまいな場合に標準時間を想定するのを見てきましたが、すべてのプラットフォームでその動作を保証するドキュメントを見たことがありません。 2012年11月4日午前1時30分(_tm_isdst == 1_)は、1:00:00から1:59:59の時間が繰り返されるため、1時間前になります。

_#include <stdio.h>
#include <time.h>

int main()
{
    time_t daylight, standard;
    struct tm timestr;
    double diff;

    timestr.tm_year = 2012 - 1900;
    timestr.tm_mon = 11 - 1;
    timestr.tm_mday = 4;
    timestr.tm_hour = 1;
    timestr.tm_min = 30;
    timestr.tm_sec = 0;

    /* first with standard time */
    timestr.tm_isdst = 0;
    standard = mktime(&timestr);

    /* now with daylight time */
    timestr.tm_isdst = 1;
    daylight = mktime(&timestr);

    diff = difftime(standard, daylight);

    printf("Difference is %f hour(s)", diff/60.0/60.0);

    return 0;
}
_

これにより、次のものが生成されます。

_Difference is 1.000000 hour(s)
_

どちらも2012年11月4日午前1時30分ですが、どちらも1時間離れた2つの異なるtime_t値です。

mktime()には基本的に2つの出力があります。

  • time_t
  • 修復された時間構造

時間構造体は入力と出力の両方です。 mktime()によって変更され、すべての構造体メンバーが公称範囲に戻ります。たとえば、tm_hourメンバー_+= 500_をインクリメントする場合、それは時間を500時間インクリメントすることを意味します。 _tm_hour_メンバーは値00から23に変更され、_tm_day_、_tm_mday_などはすべてそれに応じて調整されます。 _tm_isdst_も入力と出力の両方です。その値は次のとおりです。

  • 1 (DST in effect, i.e. daylight time)
  • 0 (DST not in effect, i.e. standard time)
  • -1(不明なDSTステータス)

したがって、mktime()はtm_isdstに対して1または0のいずれかを出力し、-1は出力しません。

-1は可能ですinputですが、私はそれを「不明」を意味すると思います。一般に、mktime()は常に自動的に決定できるとは限らないため、「自動的に決定する」という意味とは考えないでください。

明示的なDSTステータス(0または1)は、ソフトウェアの外部から取得する必要があります。たとえば、ファイルまたはデータベースに保存するか、ユーザーにプロンプ​​トを表示します。

10
Rich Jahn

扱っている時間のタイプに関する情報がない限り、_-1_フィールドには実際に_tm_isdst_を使用する必要があると思います。

たとえば、カリフォルニアにはまだPSTとPDTがあります。日付を解析していて、そのタイムゾーン情報が存在する場合は、それに応じて_tm_isdst_を設定する必要があります。 Jim McNamaraが述べたように、これらの名前はtzset()を呼び出した後、_tzname[]_配列で使用できます。

たとえば、次のC++コードは_PST/PDT_を記述します。

_int main(int argc, char * argv [])
{
    tzset();
    std::cerr << tzname[0] << "/" << tzname[1] << "\n";

    return 0;
}
_

_tzname[]_配列のオフセットは、_tm_isdst_の値に対応します。 (PST-太平洋標準時、_tm_isdst = 0_、およびPDT、太平洋夏時間、_tm_isdst = 1_。)

入力にタイムゾーン情報がない場合は、_-1_を使用するのが最善の選択です。問題が発生しますのみ日付が変更が発生する日時に対応する場合。 Rich Jahnが説明するように、2012年11月4日、彼は標準時間と夏時間の間で時間の変更があり、その頃、gmtime()が選択を行う必要があり、それはあなたが望むものと同じです。期待します。そうは言っても、それは1年に合計2時間、深夜にしか起こりません。したがって、日付が非常に重要な重要なタイプのソフトウェアで作業しているのでない限り、それはおそらくそれほど重要ではありません。

したがって、要約として:

  • 変換する日付にタイムゾーンが関連付けられている場合は、その情報を使用して_tm_isdst_の値を決定します(とはいえ、すべてのタイムゾーンをサポートする必要がある場合に、それをどのように処理するかはよくわかりません。 ... _tzname[]_配列は、ユーザーの現在のタイムゾーンのみを提供します。)
  • それ以外の場合は、_-1_を使用してください
0
Alexis Wilke