В последние годы есть такая традиция у руководства страны - баловаться со временем: отмена перехода на зимнее время в 2011 году, переход на зимнее время в 2014 году. Оборудование, программное обеспечение и системные администраторы каждый раз сходят с ума с этими переводами. Время необходимо иметь актуальное, поэтому следует своевременно обновлять базу часовых поясов zoneinfo.
Сперва необходимо проверить актуальность текущей базы часовых поясов на сервере.
# zdump -v /etc/localtime | grep 2014
/etc/localtime Sat Oct 25 21:59:59 2014 UTC = Sun Oct 26 01:59:59 2014 MSK isdst=0 gmtoff=14400 /etc/localtime Sat Oct 25 22:00:00 2014 UTC = Sun Oct 26 01:00:00 2014 MSK isdst=0 gmtoff=10800
Две строки в выводе команды выше свидетельствуют, что зоны актуальны на текущий момент (2014 год), а если команда вернула пустой вывод или другой, необходимо обновить часовые пояса на сервере. Ниже указаны два способа - ручной и автоматический.
Если обновление часовых поясов требуется произвести на небольшом парке машин, то это можно сделать и в ручную.
Скачиваем новый zoneinfo и распаковываем его:
# mkdir /tmp/zoneinfo # cd /tmp/zoneinfo # fetch ftp://ftp.iana.org/tz/tzdata-latest.tar.gz # tar -xzvf tzdata-latest.tar.gz
Скачать tzdata можно также из Базы Знаний «Онлайн Север» (версия от октября 2014), на случай недоступности файла временных зон на FTP IANA.
# fetch http://wiki.onsever.ru/_media/freebsd/tzdata-2014.10.tar.gz
Компилим зоны часовых поясов для Европы.
# zic europe
Создаём бэкап старой зоны и используем обновленную зону Europe/Moscow для локального времени.
# cp /etc/localtime /etc/localtime.old # cp /usr/share/zoneinfo/Europe/Moscow /etc/localtime
Обновляем время через ntp-сервер.
# /usr/sbin/ntpdate pool.ntp.org # date
Вт. нояб. 18 13:57:44 MSK 2014
Проверяем актуальность обновлённого localtime.
# zdump -v /etc/localtime | grep 2014
/etc/localtime Sat Oct 25 21:59:59 2014 UTC = Sun Oct 26 01:59:59 2014 MSK isdst=0 gmtoff=14400 /etc/localtime Sat Oct 25 22:00:00 2014 UTC = Sun Oct 26 01:00:00 2014 MSK isdst=0 gmtoff=10800
То, что нужно. Удаляем временные файлы.
# rm -r /tmp/zoneinfo
Далее - скрипт автоматического обновления часовых поясов на сервере. Проверен на полсотне машин с ОС FreeBSD и оптимизирован для FreeBSD 4, FreeBSD 5, FreeBSD 6, FreeBSD 7, FreeBSD 8, FreeBSD 9, FreeBSD 10, именно поэтому довольно дерзкий код, с множеством cut'ов и другого хлама, т.к. например, whereis в FreeBSD 4.0 не поддерживает ключ -q, а du не поддерживает -А и другое. Скрипт написан на Shell, что позволяет запускать его практически на любой Unix-системе.
Запуск осуществляется с консоли сервера следующей командой.
# fetch http://wiki.onsever.ru/_media/freebsd/update_zoneinfo.sh && chmod 500 ./update_zoneinfo.sh && ./update_zoneinfo.sh
Скрипт загружается на сервер, получает право на выполнение, после чего он, собственно, запускается. Далее - проверяет актуальность базы данных часовых поясов, загружает обновлённый tzdata, устанавливает его, сверяет время с NTP-сервером, снова проверяет установленный файл часового пояса и после этого удаляет временные файлы, в том числе и себя. Выполнение скрипта информативно и оформлено:
Ниже - исходный код скрипта update_zoneinfo.sh.
#!/bin/sh ########################### # Online Sever (c) 2014 # ########################### printf "\033[94mPreparing... \033[39m" ##### Console commands ##### WIS="/usr/bin/whereis -b" ZDUMP=`${WIS} zdump | cut -d " " -f2` CD=`${WIS} cd | cut -d " " -f2` FETCH=`${WIS} fetch | cut -d " " -f2` TAR=`${WIS} tar | cut -d " " -f2` ZIC=`${WIS} zic | cut -d " " -f2` CP=`${WIS} cp | cut -d " " -f2` NTPDATE=`${WIS} ntpdate | cut -d " " -f2` RM=`${WIS} rm | cut -d " " -f2` GREP=`${WIS} grep | cut -d " " -f2` MKTEMP=`${WIS} mktemp | cut -d " " -f2` MV=`${WIS} mv | cut -d " " -f2` MD5=`${WIS} md5 | cut -d " " -f2` DU=`${WIS} du | cut -d " " -f2` AWK=`${WIS} awk | cut -d " " -f2` ##### Some variables ##### tmpdir=`${MKTEMP} -d -t tmp` hash_true="f8cc37fb0efd041e6becf2f213571515" # For 2014 tzdata_url="ftp://ftp.iana.org/tz/tzdata-latest.tar.gz" tzdata_name=`basename $tzdata_url` tzdata_path=${tmpdir}/$tzdata_name ntp_pool="pool.ntp.org" echo -e "\033[92mOk!$1\033[39m" ##### Checking zoneinfo ############################### printf "\033[94mChecking zoneinfo... \033[39m" hash_zdump=`${ZDUMP} -v /etc/localtime | ${GREP} 2014 | md5` if [ "${hash_zdump}" != "${hash_true}" ]; then echo -e "\033[91mNeed to be updated!\033[39m" else echo -e "\033[92mUpdate is not required!\033[39m" printf "\033[94mCurrent local time... " curdate=`date \+DATE:\ \%Y-\%m-\%d\ TIME:\ \%H:\%M:\%S` echo -e "\033[92m${curdate}\033[39m" printf "\033[94mDeleting temporary files... \033[39m" ${RM} -rf ${tmpdir} > /dev/null 2>&1 if ! [ -d "${tmpdir}" ]; then echo -e "\033[92mOk!\033[39m"; else echo -e "\033[93mError!\033[39m"; fi; printf "\033[94mDeleting itself $0... \033[39m" ${RM} $0 > /dev/null 2>&1 if ! [ -f "$0" ]; then echo -e "\033[92mOk!\033[39m"; else echo -e "\033[93mError!\033[39m"; fi; exit 0; fi ##### Fetching latest tzdata ##### printf "\033[94mFetching latest tzdata... \033[39m" ${FETCH} -q ${tzdata_url} > /dev/null 2>&1 if [ $? -ne 0 ]; then echo -e "\033[91mTzdata is not available!\033[39m"; exit 1; fi; ${MV} ${tzdata_name} ${tzdata_path} if [ -f ${tzdata_path} ]; then tzdata_size=`${DU} ${tzdata_path} | ${AWK} '{print $1}'` if [ "${tzdata_size}" -lt 200 ]; then echo -e "\033[91mYou must check downloaded tzdata!\033[39m" exit 1; else echo -e "\033[92mOk!\033[39m" fi fi ##### Extracting tzdata... ##### printf "\033[94mExtracting tzdata... \033[39m" ${TAR} -C ${tmpdir} -xzvf ${tzdata_path} > /dev/null 2>&1 if [ $? -ne 0 ]; then echo -e "\033[91mTzdata archive broken!\033[39m"; exit 1; fi; ${RM} -rf ${tzdata_path} echo -e "\033[92mOk!\033[39m" ##### Applying new tzdata ##### printf "\033[94mApplying new tzdata... \033[39m" ${ZIC} ${tmpdir}/europe ${CP} /etc/localtime /etc/localtime.prev ${CP} /usr/share/zoneinfo/Europe/Moscow /etc/localtime echo -e "\033[92mOk!\033[39m" ##### Checking zoneinfo ############################### printf "\033[94mChecking zoneinfo... \033[39m" hash_zdump=`${ZDUMP} -v /etc/localtime | ${GREP} 2014 | md5` if [ "${hash_zdump}" != "${hash_true}" ]; then echo -e "\033[91mTime zones have not been updated!\033[39m" else echo -e "\033[92mTime zones have been updated!\033[39m" fi ##### Synchronizing local time with ntp pool ##### printf "\033[94mSynchronizing local time... \033[39m" ${NTPDATE} ${ntp_pool} > /dev/null 2>&1 if [ $? -eq 0 ]; then echo -e "\033[92mOk!\033[39m" printf "\033[94mCurrent local time... " curdate=`date \+DATE:\ \%Y-\%m-\%d\ TIME:\ \%H:\%M:\%S` echo -e "\033[92m${curdate}\033[39m" else echo -e "\033[93mError!\033[39m" printf "\033[94mCurrent local time... " curdate=`date \+DATE:\ \%Y-\%m-\%d\ TIME:\ \%H:\%M:\%S` echo -e "\033[92m${curdate}\033[39m" fi ##### Deleting temporary files ##### printf "\033[94mDeleting temporary files... \033[39m" ${RM} -rf ${tmpdir} > /dev/null 2>&1 if ! [ -d "${tmpdir}" ]; then echo -e "\033[92mOk!\033[39m"; else echo -e "\033[93mError!\033[39m"; fi; ##### Deleting temporary files ##### printf "\033[94mDeleting itself $0... \033[39m" ${RM} $0 > /dev/null 2>&1 if ! [ -f "$0" ]; then echo -e "\033[92mOk!\033[39m"; else echo -e "\033[93mError!\033[39m"; fi;
Довольно часто встречается ситуация, когда приложения вместо системных зон часовых поясов используют свои собственные. Например, php и mysql. В таких случаях можно наблюдать картину, когда время в приложении отстаёт или опережает системное, что можно исправить, обновив временные зоны уже для конкретного приложения.