2016-08-22 25 views
1

もう一つ質問が、タイムゾーンをヨーロッパ/ベルリンすなわち、現在の時刻に設定されているCESTあるtm_isdstがフラグを無視します。システムコールはmktimeは、mktime関数とDST</p> <p>のLinux、Ubuntuのに関する

は今、私は次のコードを実行しよう:

#include <stdio.h> 
#include <time.h> 
int main() 
{ 

    struct tm tm = {0}; 
    int secs; 

    tm.tm_sec = 0; 
    tm.tm_min = 0; 
    tm.tm_hour = 12; 
    tm.tm_mon = 9 - 1; 
    tm.tm_mday = 30; 
    tm.tm_year = 2016 - 1900; 

    tm.tm_isdst = 0; 
    secs = mktime(&tm); 
    printf("%i\n", secs); 

    tm.tm_isdst = 1; 
    secs = mktime(&tm); 
    printf("%i\n", secs); 

    tm.tm_isdst = -1; 
    secs = mktime(&tm); 
    printf("%i\n", secs); 

    return 0; 
} 

をし、間違ったすべての3つのケースである

1475233200 
1475233200 
1475233200 

を得る(1時間オフセット):だから

>date -d @1475233200 
Fri Sep 30 13:00:00 CEST 2016 

私は少し困惑しています、私のタイムゾーンは何とか壊れていますか? tm_isdstフラグが完全に無視されるのはなぜですか?

編集:@名詞Animalは答えました:mktimeはtm_hourを変更します!私はそれが文書化されているのだろうか?

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

void reset(struct tm* tm){ 
    (*tm) = (const struct tm){0}; 

    tm->tm_sec = 0; 
    tm->tm_min = 0; 
    tm->tm_hour = 12; 
    tm->tm_mon = 9 - 1; 
    tm->tm_mday = 30; 
    tm->tm_year = 2016 - 1900; 
} 

int main() 
{ 

    struct tm tm; 
    int secs; 

    reset(&tm); 
    tm.tm_isdst = 0; 
    secs = mktime(&tm); 
    printf("%i\n", secs); 

    reset(&tm); 
    tm.tm_isdst = 1; 
    secs = mktime(&tm); 
    printf("%i\n", secs); 

    reset(&tm);  
    tm.tm_isdst = -1; 
    secs = mktime(&tm); 
    printf("%i\n", secs); 

    return 0; 
} 

が正常終了

1475233200 
1475229600 
1475229600 
+1

1)動作が奇妙に見えます。 'mktime()'として 'mktime(&tm);')を実行した後、**すべての**フィールドを再設定してください(または少なくとも印刷してください)2) 'tm'フィールドを調整することができます。 printf( "%lld \ n"、(long long)); '未定義の動作を避けるためにprintf("%i \ n "、(int)secs); – chux

+0

*そうかもしれませんが、実際には奇妙ではありません。実際、['mktime()'](http://man7.org/linux/man-pages/man3/mktime.3.html)は、その引数、特に 'tm.tm_hour'と' tm。この場合、tm_isdst'フィールドに入力します。 –

+0

@Nominal Animal 'odd 'とは、最初の2つのケースで、' tm'が主な範囲にあるので、 'mktime()'は 'tm'を変更するとは予想されません。 _hh_最初のケースではないかもしれません。うーん、夏時間の0のdstは1に変わるかもしれない。 – chux

答えて

1

私はこの混乱をどのように感じるか分かります。 time_t結果が(正規化)*srcに基づいて算出される

time_t mktime_actual(struct tm *dst, const struct tm *src); 

署名を有するとmktime()考えると、正規化されたフィールドと夏時間がその時点で適用されるかどうか、*dstに保存されています。

C言語の開発者は、歴史的には、srcdstの両方を組み合わせた1つのポインタのみを使用することを選択しました。しかし、上記のロジックはまだ立っています。

`man mktimeマニュアルページ、特にこの部分参照:

にはmktime()関数は、壊れたダウン時間構造を変換し、 は、時間表現をカレンダーに、ローカルタイムで表されます。 関数は、tm_wdayおよび のtm_ydayフィールドで呼び出し元から提供された値を無視します。 tm_isdstフィールドで指定された値は、 の夏時間(DST)がtm構造体に指定されている時間に有効であるかどうかを、mtime() に通知します。正の値はDSTが であることを意味します。 0はDSTが有効でないことを意味します。負の値 は、指定時刻に でDSTが有効かどうかをmktime()が(タイムゾーン情報とシステム データベースを使用して)調べる必要があることを意味します。

mktime()関数は、tm構造体のフィールドを というように変更します。tm_wdayとtm_ydayは、他のフィールドの の内容から決定された値に設定されます。構造体メンバが有効な間隔の範囲外にある場合は、正規化されます(たとえば、40 月が11月9日に変更されます)。 tm_isdstは、に関係なく正の値に設定され、0に設定すると、指定した時刻にDSTが有効かどうかを示す に設定されます。 mktime()を呼び出すと、外部変数tznameに が設定され、現在のタイムゾーンに関する情報が設定されます。

指定破壊ダウン時間はカレンダー 時間(エポック秒)で、はmktime()戻り値(のtime_t)として表すことができない-1と が破壊ダウン時間構造体のメンバーを変更しない場合。言い換えれば

、あなたのテストプログラムは、ビットを変更した場合、

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

static const char *dst(const int flag) 
{ 
    if (flag > 0) 
     return "(>0: is DST)"; 
    else 
    if (flag < 0) 
     return "(<0: Unknown if DST)"; 
    else 
     return "(=0: not DST)"; 
} 

static struct tm newtm(const int year, const int month, const int day, 
         const int hour, const int min, const int sec, 
         const int isdst) 
{ 
    struct tm t = { .tm_year = year - 1900, 
        .tm_mon = month - 1, 
        .tm_mday = day, 
        .tm_hour = hour, 
        .tm_min = min, 
        .tm_sec = sec, 
        .tm_isdst = isdst }; 
    return t; 
} 

int main(void) 
{ 
    struct tm tm = {0}; 
    time_t secs; 

    tm = newtm(2016,9,30, 12,0,0, -1); 
    secs = mktime(&tm); 
    printf("-1: %04d-%02d-%02d %02d:%02d:%02d %s %lld\n", 
      tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, 
      tm.tm_hour, tm.tm_min, tm.tm_sec, dst(tm.tm_isdst), (long long)secs); 

    tm = newtm(2016,9,30, 12,0,0, 0); 
    secs = mktime(&tm); 
    printf(" 0: %04d-%02d-%02d %02d:%02d:%02d %s %lld\n", 
      tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, 
      tm.tm_hour, tm.tm_min, tm.tm_sec, dst(tm.tm_isdst), (long long)secs); 

    tm = newtm(2016,9,30, 12,0,0, 1); 
    secs = mktime(&tm); 
    printf("+1: %04d-%02d-%02d %02d:%02d:%02d %s %lld\n", 
      tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, 
      tm.tm_hour, tm.tm_min, tm.tm_sec, dst(tm.tm_isdst), (long long)secs); 

    return EXIT_SUCCESS; 
} 

に言って、それはつまり、出力

-1: 2016-09-30 12:00:00 (>0: is DST) 1475226000 
0: 2016-09-30 13:00:00 (>0: is DST) 1475229600 
+1: 2016-09-30 12:00:00 (>0: is DST) 1475226000 

を生成し実行している、それは(説明とまったく同じように動作します上の引用符で)。この動作は、C89、C99、およびPOSIX.1で文書化されています(C11とも考えていますが、チェックしていません)。

1

を与え、構造のtm_wdaytm_yday成分の値が適切に設定され、そして他の成分は、指定されたカレンダーを表すように設定されています 時間、... C11dr7.27.2.32

mktime(&tm)を呼び出すと、元の値tmは範囲に制限されません。そのため最初のmktime(&tm)コールの

は、確かにtm.tm_isdsttm.tm_hourは1と11に調整したので、OPのタイムスタンプに影響を及ぼさなかったコードtm.tm_isdst = 1;tm.tm_isdst = -1;次。

調査するすべてのフィールドを設定する方がよい。

struct tm tm0 = {0}; 
struct tm tm; 
int secs; 

tm0.tm_sec = 0; 
tm0.tm_min = 0; 
tm0.tm_hour = 12; 
tm0.tm_mon = 9 - 1; 
tm0.tm_mday = 30; 
tm0.tm_year = 2016 - 1900; 

tm = tm0; 
tm.tm_isdst = 0; 
secs = mktime(&tm); 
printf("%i\n", (int) secs); 

tm = tm0; 
tm.tm_isdst = 1; 
secs = mktime(&tm); 
printf("%i\n", (int) secs); 

tm = tm0; 
tm.tm_isdst = -1; 
secs = mktime(&tm); 
printf("%i\n", (int) secs); 
関連する問題