Dziwna logika mktime z ujemnymi sekundami
Używam mktime / localtime do zarządzania czasem, włączając w to ciężką arytmetykę dat / godzin.
Zauważyłem coś bardzo dziwnego, gdy udostępniłem mktime struct tm, który zawiera wartości ujemne.
Weź poniższy kod. W Los Angeles 3 listopada 2013 r. Nastąpiła zmiana czasu letniego. Jeśli określę czas tm jako 2013-11-04 o północy i odejmiemy 24 godziny, otrzymam tę samą wartość co północy 2013-11-03. Jest to różnica 25-godzinna w stosunku do czasu UTC, co jest w porządku, ponieważ w przypadku isdst = -1 można powiedzieć, że patrzymy na „czas zegara ściennego”. To samo, jeśli odejmuję 1440 minut (24 * 60). Ale jeśli odejmę 86400 (24 * 60 * 60) sekund, otrzymam 2013-11-03 1am. To jest 24 godziny różnicy UTC. Oto wyjście z poniższego kodu:
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
Dla mnie to nie ma sensu - dlaczego sekundy są traktowane inaczej niż minuty, godziny i dni? Patrzyłem na człowieka i standard C, ale nic nie mogłem znaleźć.
To zachowanie łamie niektóre z moich założeń i komplikuje sprawy. Czy ktoś zna dobrą alternatywę dla mktime / localtime (testowałem boost, ICU i tzcode, zbyt wolno na to, czego potrzebuję).
Z góry dziękuję za wszelkie myśli :)
#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;
}