Определить, если дата в летнее время в MySql
Я унаследовал устаревшее приложение, в котором все даты и время хранятся в местном часовом поясе (Великобритания). Я не в состоянии изменить, как они хранятся.
Однако необходимо, чтобы в приложении отображались все даты по Гринвичу. Поэтому, когда я получаю список событий из базы данных, мне нужно, чтобы он отображал их все в этом формате времени, наблюдая, работает ли переход на летнее время для каждой конкретной даты события. Используя следующую логику, я могу определить, активно ли летнее время в запросе:
IF(CAST(TIMEDIFF(NOW(), UTC_TIMESTAMP()) AS SIGNED) >0,
DATE_FORMAT(CONVERT_TZ(ADDTIME(`event_date`, IFNULL(`event_time`, '00:00')), '+01:00', '+00:00'), '%H:%i'), `event_time`) AS event_time
Это, однако, очевидно, проверяет только дату запуска. Поэтому любые события в будущем, которые пересекают границы перехода на летнее время, не работают.
Есть ли способ, которым я могу определить, находится ли данная дата в DST в самом запросе mysql?
Любая помощь, высоко ценится.
3 ответа
Ты в Великобритании. Итак, ваш TZ должен быть CET или CEST (летнее время Центральной Европы). Вы можете получить информацию таким образом:
mysql> SELECT @@system_time_zone;
+--------------------+
| @@system_time_zone |
+--------------------+
| CEST |
+--------------------+
Я использую это во многих моих хранимых процедурах. Примечание: мне нужны обе формы информации TZ, независимо от того, нужно ли мне вычислять смещения с применением DST или без него.
CASE @@system_time_zone
WHEN 'CET' THEN SET l_tz = 'Europe/Paris'; SET l_tzOff = '+1:00';
WHEN 'CEST' THEN SET l_tz = 'Europe/Paris'; SET l_tzOff = '+1:00';
WHEN 'SGT' THEN SET l_tz = 'Asia/Singapore'; SET l_tzOff = '+8:00';
ELSE SET l_tz = 'Europe/Paris'; SET l_tzOff = '+1:00';
END CASE;
Вы можете получить вдохновение от этого.
Часовые пояса не сохраняются в значениях DATETIME. Интересно, что они для TIMESTAMPs.
Учитывая сохраненную дату, вы можете посмертно выяснить, был ли DST "включен" в то время на основе местных правил. Поскольку вы не можете изменить даты, я думаю, вы не можете добавить столбец для хранения часового пояса...
Создайте хранимую процедуру, которая содержит правила и преобразует данную дату в GMT.
Обратите внимание, что только люди, которые живут вокруг Гринвича, хотят, чтобы их время отображалось в GMT.:)
Удачи.
В качестве альтернативы, вот несколько функций, позволяющих определить, действуют ли правила перехода на летнее время в Северной Америке.
По состоянию на 2007* правило, в Северной Америке было что Daylight Savings (DST):
- начинается в 2 часа ночи (по местному времени) во 2-е воскресенье марта
- заканчивается в 2 часа ночи (по местному времени) 1- го воскресенья ноября
*(С 1987 по 2006 год это было первое воскресенье апреля - последнее воскресенье октября.)
Функции MySQL:
DELIMITER // CREATE FUNCTION DSTstart(dt DATETIME) RETURNS DATETIME DETERMINISTIC BEGIN
RETURN cast(concat(year(now()),'-3-',(14-WEEKDAY(concat(year(now()),'-3-1'))),' 2:00') as datetime);
END// DELIMITER ;
DELIMITER // CREATE FUNCTION DSTstop(dt DATETIME) RETURNS DATETIME DETERMINISTIC BEGIN
RETURN cast(concat(year(now()),'-11-',(7-WEEKDAY(concat(year(now()),'-11-1'))),' 2:00') as datetime);
END// DELIMITER ;
DELIMITER // CREATE FUNCTION isDST(dt DATETIME) RETURNS BIT DETERMINISTIC BEGIN
RETURN (dt>=cast(concat(year(now()),'-3-',(14-WEEKDAY(concat(year(now()),'-3-1'))),' 2:00') as datetime))
AND (dt<cast(concat(year(now()),'-11-',(7-WEEKDAY(concat(year(now()),'-11-1'))),' 2:00') as datetime));
END// DELIMITER ;
Просто для справки я включу версии функций VBA и Spreadsheet (т.е. Excel) Worksheet Formula:
Функции Excel/Access/ и т. Д. VBA:
Function DSTstart(dt As Date) As Date
DSTstart = CDate(Year(dt) & "-3-" & (15 - Weekday(CDate(Year(dt) & "-3-1"), 2)) & " 2:00")
End Function
Function DSTstop(dt As Date) As Date
DSTstop = CDate(Year(dt) & "-11-" & (8 - Weekday(CDate(Year(dt) & "-11-1"), 2)) & " 2:00")
End Function
Function isDST(dt As Date) As Boolean
isDST = (dt >= CDate(Year(dt) & "-3-" & (15 - Weekday(CDate(Year(dt) & "-3-1"), 2)) & " 2:00") _
And dt < CDate(Year(dt) & "-11-" & (8 - Weekday(CDate(Year(dt) & "-11-1"), 2)) & " 2:00"))
End Function
Функции листа Excel:
Начало летнего времени: (возвращает дату / время начала летнего времени в году даты в[A1]
)
=DATE(YEAR(A1),3,15-WEEKDAY(DATE(YEAR(A1),3,1),2))+TIMEVALUE("2:00")
Конец летнего времени: (возвращает дату / время начала летнего времени в году даты в[A1]
)
=DATE(YEAR(A1),11,8-WEEKDAY(DATE(YEAR(A1),11,1),2))+TIMEVALUE("2:00")
Летнее время?: (возвращаетTRUE
если действует летнее время на дату в [A1]
)
=AND(A1>=DATE(YEAR(A1),3,15-WEEKDAY(DATE(YEAR(A1),3,1),2))+TIMEVALUE("2:00"),A1<DATE(YEAR(A1),11,8-WEEKDAY(DATE(YEAR(A1),11,1),2))+TIMEVALUE("2:00"))
Нашел ужасно сложный путь, @DT вводит дату и время
Set @DT=20150329020304; # -> 0
Set @DT=20150329030304; # -> 1(-0.0511)
Set @DT=20150329040304; # -> 1(-1)
Select 0!=(UNIX_TIMESTAMP(@DT)- UNIX_TIMESTAMP(Concat(Year(@DT),'0101',Time_Format(@DT,'%H%i%s')))-DateDiff(@DT,Concat(Year(@DT),'0101',Time_Format(@DT,'%H%i%s')))*86400)/3600 as DlsIsOn