Столкнулся с такой проблемой. После отмены перехода на зимнее время функция _mktime64() стала не правильно расчитывать __time64_t для дат зимнего времени прошлых лет. Она считает так, как будто бы раньше тоже не было перехода зимнее/летнее. Для примера возьмём дату "26 Jan 2011 03:00:00" (строка "Зима начала 2011 года" в таблице на странице http://habrahabr.ru/blogs/sysadm/130363/). Результат должен быть 1296000000. Такой результат даёт функция MySQL UNIX_TIMESTAMP('2011-01-26 03:00:00'). А _mktime64() возвращает 1295996400 (на 1 час меньше).
Если заглянуть внутрь _mktime64()
/*
* Adjust for timezone. No need to check for overflow since
* localtime() will check its arg value
*/
__tzset();
_ERRCHECK(_get_dstbias(&dstbias));
_ERRCHECK(_get_timezone(&timezone));
tmptm1 += timezone;
/*
* Convert this second count back into a time block structure.
* If localtime returns NULL, return an error.
*/if ( _localtime64_s(&tbtemp, &tmptm1) != 0 )
goto err_mktime;
/*
* Now must compensate for DST. The ANSI rules are to use the
* passed-in tm_isdst flag if it is non-negative. Otherwise,
* compute if DST applies. Recall that tbtemp has the time without
* DST compensation, but has set tm_isdst correctly.
*/if ( (tb->tm_isdst > 0) || ((tb->tm_isdst < 0) &&
(tbtemp.tm_isdst > 0)) ) {
tmptm1 += dstbias;
if ( _localtime64_s(&tbtemp, &tmptm1) != 0 )
goto err_mktime;
}
то видим, что функциями _get_dstbias(&dstbias) и _get_timezone(&timezone) запрашиваются сдвижки DST и часового пояса действующие на сегодняшний момент. Т.е. dstbias=0 т.к. нет переходов зимнего/летнего времени и timezone=14400 (UTC+4). А ведь на момент "26 Jan 2011 03:00:00" часовой пояс был UTC+3.
Мне просто необходимо что бы _mktime64() в клиентской программе и UNIX_TIMESTAMP(), FROM_UNIXTIME() на MySQL сервере давали одинаковый результат.
Похоже придётся хранить все даты перевода часов с 1970 по 2011 и самому корректировать результат. Хотя оставляю надежду на какой-нибудь дельный совет.
> Столкнулся с такой проблемой. После отмены перехода на зимнее время функция > _mktime64() стала не правильно расчитывать __time64_t для дат зимнего времени > прошлых лет. Она считает так, как будто бы раньше тоже не было перехода > зимнее/летнее. Для примера возьмём дату "26 Jan 2011 03:00:00" (строка "Зима > начала 2011 года" в таблице на странице
Чё сюда-то пишешь? Ты это в Госдуму пиши, тем идиотам которые это придумали.
Здравствуйте, MasterZiv, Вы писали:
>> начала 2011 года" в таблице на странице MZ>Чё сюда-то пишешь? Ты это в Госдуму пиши, тем идиотам которые это придумали.
А какая разница, раз речь про 1970 год и далее — значит эта функция всегда неправильно работала.
в СССР в 1981 году менялось ("декретное время", в 1991, Калиниград поменял часовой пояс, регионы разные в любое другое время).
Будет интересно посмотреть на правильную функцию/утилиту, учитывающую всё.
Здравствуйте, igyrus, Вы писали:
I>После отмены перехода на зимнее время функция _mktime64() стала неправильно расчитывать __time64_t для дат зимнего времени прошлых лет. Она считает так, как будто бы раньше тоже не было перехода зимнее/летнее.
Windows никогда не славилась корректной работой с часовыми поясами.
I>Похоже придётся хранить все даты перевода часов с 1970 по 2011 и самому корректировать результат. Хотя оставляю надежду на какой-нибудь дельный совет.
Все даты перевода хранятся в tz database и поддерживаются в актуальном состоянии, с недавнего времени под эгидой IANA: http://www.iana.org/time-zones. Нормальные libc задействуют эту БД, а в Windows, наверное, можно таскать ее с собой и брать данные из нее, минуя системные вызовы.
Здравствуйте, Denis Mingulov, Вы писали: DM>А какая разница, раз речь про 1970 год и далее — значит эта функция всегда неправильно работала. DM>в СССР в 1981 году менялось ("декретное время", в 1991, Калиниград поменял часовой пояс, регионы разные в любое другое время). DM>Будет интересно посмотреть на правильную функцию/утилиту, учитывающую всё.
Да нет. Раньше она правильно работала. Для московского часового пояса что с 1970 по 1981, что с 1981 по осень 2011 был часовой пояс UTC+3.
Т.е. tmptm1 += timezone; , где timezone=10800 и летом начиная с 1981г стало прибавляться dstbias=3600. А с осени 2011 пояс стал UTC+4, т.е timezone=14400. А функции _mktime64() пофиг какую дату её просят посчитать. Она теперь всегда 14400 прибавляет.
Здравствуйте, igyrus, Вы писали:
I>Да нет. Раньше она правильно работала.
Ничего не понял.
Раз у вас эта функция могла работать правильно с учетом того, что летнее время то вводили, то отменяли, то вообще меняли часовые пояса — вам лучше разобраться с тем, что именно и почему у вас сейчас не работает.
Либо всё-таки вариант, что раньше она тоже неправильно работала.
Здравствуйте, igyrus, Вы писали:
I>Да, спасибо. Подтвердили моё мнение, что для Windows делать надо самому. А даты перехода я, пожалуй, возьму из таблицы `mysql`.`time_zone_transition`.
еще libical умеет это делать