2013-11-20 1 views
4

나는 날짜/시간에 대한 무거운 산술을 포함하여 시간 관리를 위해 mktime/localtime을 사용 해왔다.부정적인 초를 지닌 이상한 mktime 논리

mktime에 음수 값이 들어있는 struct tm을 제공 할 때 매우 이상한 것으로 나타났습니다.

아래 코드를 사용하십시오. 2013 년 11 월 3 일에 LA에 DST 변경 사항이있었습니다. 2013-11-04 자정으로 시간을 지정하고 24 시간을 빼면 2013-11-03 자정까지 동일한 값을 얻습니다. 그것은 UTC 방식으로 25 시간 차이가 있습니다. isdst = -1에서와 같이, 우리는 '벽시계'를보고 있다고 말할 수 있습니다. 내가 1440 분 (24 * 60)을 뺀 것과 같습니다. 그러나 86400 (24 * 60 * 60) 초를 빼면 2013-11-03 오전 1 시가됩니다. 그것은 UTC 방식으로 24 시간 차이가 있습니다. - 왜 초 분, 시간, 일보다 다르게 취급하는 것이 이해가되지 않습니다 나를 위해

2013-11-03 00:00:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000 
2013-12--27 00:00:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000 
2013-11-04 -24:00:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000 
2013-11-04 00:-1440:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000 
2013-11-04 00:00:-86400 (gmtoff=0, isdst=-1) -> 2013-11-03 01:00:00 (gmtoff=-25200, isdst=1) -> 1383465600 

: 여기에 아래 코드의 출력은입니까? 나는 사람과 C 표준을 보았지만 아무것도 찾을 수 없었다.

이 동작으로 인해 내 가정이 손상되고 여러 가지 문제가 발생합니다. 누군가 mktime/localtime에 대한 좋은 대안을 알고 있습니까 (ICU 및 tzcode를 테스트 한 결과 내가 필요로하는 것에 너무 느리다). 어떤 생각에 미리

감사합니다 :)

#include <time.h> 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
char* printtm(struct tm tm) 
{ 
    static char buf[100]; 
    sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d (gmtoff=%ld, isdst=%d)", 
    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 
    tm.tm_hour, tm.tm_min, tm.tm_sec, 
    tm.tm_gmtoff, tm.tm_isdst); 
    return buf; 
} 

void test(int y, int m, int d, int hh, int mm, int ss, int isdst) 
{ 
    struct tm tm; 
    memset(&tm, 0, sizeof(tm)); 
    tm.tm_year = y - 1900; 
    tm.tm_mon = m - 1; 
    tm.tm_mday = d; 
    tm.tm_hour = hh; 
    tm.tm_min = mm; 
    tm.tm_sec = ss; 
    tm.tm_isdst = isdst; 
    printf("%s -> ", printtm(tm)); 
    time_t t = mktime(&tm); 
    printf("%s -> %ld\n", printtm(tm), t); 
} 


int main() 
{ 
    setenv("TZ", ":America/Los_Angeles", 1); 
    tzset(); 

    test(2013,11,03, 0,0,0, -1); 
    test(2013,12,-27, 0,0,0, -1); 
    test(2013,11,04, -24,0,0, -1); 
    test(2013,11,04, 0,-1440,0, -1); 
    test(2013,11,04, 0,0,-86400, -1); 

    return 0; 
} 
+0

@hobbs : 예, 있습니다. C11 7.27.2.3은'mktime' 함수를 설명합니다 : "구조의 **'tm_wday' ** 및 **'tm_yday ** ** 구성 요소의 원래 값은 무시되고 다른 구성 요소의 원래 값은 무시됩니다 위에 표시된 범위로 제한됩니다. " (그리고 방금 회신했던 설명을 삭제했습니다.) –

+0

Thanks Keith. 우선, 나는 어떤 코멘트도 삭제하지 않았고 어떤 일이 일어 났는지 전혀 모른다. 어쨌든, 나는 wday/yday에 대해 알았지 만, 당신의 대답은 초가 왜 여기에 다르게 취급되는지 분명히하지 않습니다. –

+0

누군가 "hobbs"라는 사람이 의견을 게시 한 후 내 답장을 쓰면서 누군가 삭제했습니다. 나는 아직도 관련성이 있다고 보였으므로 회신을 제자리에 두었다. 당신 말이 맞습니다. 초가 다르게 대하는 이유를 분명히하지 않았기 때문에 대답이 아닌 논평을 게시했습니다. 나는 나중에 자세히 살펴볼지도 모른다. –

답변

3
struct tm의 범위를 벗어난 값으로 사용

mktimetm_isdst==-1이 문제와에서 지정합니다. 개인적으로, 나는 당신의 시스템이 여기에서 행동하는 방식이 이라고 잘못 생각한다. 그러나 그것이 어떻게 행동해야하는지에 대한 표준은 명확하지 않으므로 그러한 사용법은 기껏해야 이식성이 없다. struct tm에서 산술 연산을 수행하려면 명확한 결과가 나오도록 tm_isdst이 미리 0 또는 1로 설정되어 있는지 확인해야합니다.

주 하나 개 쉬운 방법이 단순히 서머 타임이 적용 여부를 결정하기 위해 연산을 적용하기 전에 원래 struct tm (tm_isdst==-1 포함)에 mktime를 호출하는 것입니다 것을 (즉, tm_isdst에 대한 최종 값을 채우기 위해)를 호출 산술 조정을 한 후에 다시.

+0

감사합니다. 당신이 맞습니다 isdst = 0/1 그것을 해결하고, 내가 생각하는 그것을 사용할 수 있습니다. 그러나 나는이 행동에 대해 매우 혼란 스러웠다. –

+2

나는 그 행동이 혼란스럽고 부 자연스러운 것이라고 완전히 동의한다. 그러나 표준은 범위를 벗어나는 값을 조정하고 일광 시간 상태를 결정하는 방법이 서로 상호 작용하는 방법에 대한 설명을 작성하지 않으며 사실상 모든 시간의 가치가 본질적으로 모호하기 때문에 모든 사람의 요구를 충족시킬 방법이 없습니다. BTW, 일광 절약 시간 전이는 일반적으로 분 단위로 지정되기 때문에 사용중인 시스템이 초를 무시한다는 것입니다. –

+0

아, 표준에 대한 가장 좋은 점은 sooo 일관성이 있다는 것입니다. mktime과 비슷한 점은 모호한 월 클럭 시간을 지정하는 것입니다 (1 시간의 겹치는 동안) - mktime은 통화 기록에 따라 가능한 두 값을 모두 반환 할 수 있습니다 . 장난! 모든 답장을 보내 주셔서 감사합니다! :) –