Проблема преобразования даты / времени, если момент точно в конце зимы (не летнее время) - PullRequest
3 голосов
/ 04 марта 2010

В моем приложении мне нужно рассчитать смены, используя шаблон, описанный в файле. Недавно у одного из моих клиентов приложение зависло по следующей причине:

Если вы заполните 'struct tm' точным моментом в конце зимнего времени (не в летнее время), _mktime, похоже, вернет неправильный результат.

Код выглядит так:

struct tm tm_start;
tm_start.tm_mday  = startday;
tm_start.tm_mon   = startmonth-1;
tm_start.tm_year  = startyear-1900;
tm_start.tm_hour  = starthour;
tm_start.tm_min   = startmin;
tm_start.tm_sec   = startsec;
tm_start.tm_isdst = -1;             // Don't know if DST is active at this moment

_int64 contTime = _mktime64(&tm_start);

Предположим, что есть переход с зимнего на летнее время 5 апреля в 2:00. На практике это означает, что у нас есть следующие моменты времени:

5 April, 1:58
5 April, 1:59
5 April, 3:00

Поскольку в приложении я не знаю, когда начинается или заканчивается летнее время (действительно ли я хочу это знать?), Я передаю дату «5 апреля, 2:00» в _mktime64, используя код, показанный выше.

Я бы ожидал, что _mktime64 выдаст мне значение time_t, которое соответствует 5 апреля 3:00 (что в точности совпадает с моментом 5 апреля 2:00).

Однако это не то, что происходит. _mktime64 изменяет tm_start на 5 апреля, 1:00 и возвращает соответствующее значение time_t. Что означает, что я получаю совершенно другой момент. (фактически: каждый момент между 2:00 и 3:00 заставляет _mktime64 возвращать момент между 1:00 и 2:00)

Я думал, что это ошибка в Visual Studio 2005, но, по-видимому, Visual Studio 2010 (Release Candidate) имеет такое же поведение.

Проблема появляется как в XP, так и в Windows7 (не проверяла Vista).

Это известная ошибка? Или есть другие советы для решения этой проблемы?

Ответы [ 3 ]

3 голосов
/ 04 марта 2010

Это неизбежное последствие работы с местным временем вместо UTC. Конец летнего времени также выглядит довольно странно, временные метки при переключении двойственны, поскольку местное время совпадает два раза.

Это легко решить, работая вместо этого с UTC, это то же самое, что и операционная система. Проверьте вашу реализацию CRT, что-то вроде _gmtime64 () или встроенный GetFileTime ().

2 голосов
/ 04 марта 2010

Я думаю, он просто не знает, как правильно обрабатывать недопустимое время, которое вы проходите. И это, безусловно, недопустимо для вашего часового пояса - вы думаете, что это «1 минута после 1:59 зимой» подразумевая, что вы хотите, чтобы он возвратил «3:00» с DST снова в работе, что звучит разумно. Тем не менее, он может с таким же успехом относиться к нему как «за час до 3:00 летом», то есть, должно быть, это было из зимнего периода и, следовательно, возвращает «1:00». Таким образом, я не думаю, что это ошибка - скорее всего, это будет неопределенное поведение о том, как обрабатывать несуществующее время.

Я ожидаю, что самый безопасный способ приблизиться к этому - это использовать UTC везде, так как тогда нет никаких двусмысленностей. Очевидно, что это может не соответствовать карте вашего приложения, но таков темный мир, который тянет время вперед и назад!

1 голос
/ 04 марта 2010

Попытка преобразовать 5 апреля 2:30 в time_t аналогична попытке преобразовать 29 февраля 2011 года в time_t. Ни в том, ни в другом случае вы не ожидаете действительного результата, потому что ввод не является действительной датой. 5 апреля даже 2:00 не существует. 1: 59,59 сопровождается непосредственно 3: 00: 00

...