System time (Русский)
В операционной системе время (часы) определяется тремя понятиями: значением времени (будь то местное время, UTC или что-то другое), часовым поясом и информацией о переходе на летнее время (DST), если это применимо. Эта статья рассказывает, что это такое и как их читать и менять. В системах присутствуют двое часов: аппаратные часы и системные часы, которые также подробно описаны в этой статье.
Стандартное поведение большинства операционных систем таково:
- При загрузке для системных часов устанавливается значение из аппаратных часов.
- Поддерживается точное время системных часов; смотрите #Синхронизация времени.
- При выключении для аппаратных часов устанавливается значение из системных часов.
Аппаратные часы
Аппаратные часы (они же часы реального времени (RTC) или часы CMOS) хранят следующие значения: год, месяц, день, час, минута и секунда. Только в прошивках UEFI 2016 года или новее есть возможность хранить часовой пояс, а также информацию о переходе на летнее время.
Просмотр времени из аппаратных часов
# hwclock --show
Изменение времени аппаратных часов по системным часам
Следующая команда устанавливает время в аппаратных часах, беря значение из системных часов. Кроме того, она обновляет файл /etc/adjtime
или создаёт его, если он отсутствует. Смотрите раздел "The Adjtime File" в hwclock(8) для более подробной информации, а также раздел #Погрешность часов.
# hwclock --systohc
Системные часы
Системные часы (они же программные часы) отслеживают время, часовой пояс и информацию о переходе на летнее время, если применимо. В ядре Linux они представлены как количество секунд, прошедших с полуночи 1 января 1970 года по UTC. Начальное значение системных часов вычисляется из аппаратных часов в зависимости от содержимого файла /etc/adjtime
. После завершения загрузки системные часы работают независимо от аппаратных часов. Ядро Linux отслеживает системные часы путём подсчета прерываний таймера.
Просмотр времени
Для проверки текущего времени системных часов (представленных как в местном времени, так и в UTC), а также RTC (аппаратных часов):
$ timedatectl
Изменение времени системых часов
Установка местного времени для системых часов:
# timedatectl set-time "гггг-ММ-дд чч:мм:сс"
Например:
# timedatectl set-time "2014-05-26 11:13:54"
Установит 26 мая 2014 года, 11 часов 13 минут 54 секунды.
Стандарт времени
Есть два основных стандарта времени: местное (локальное) время (localtime) и Всемирное координированное время (Coordinated Universal Time, UTC). Местное время зависит от текущего часового пояса, а время UTC — это глобальное время, которое одинаково для всех и не зависит от часовых поясов. UTC иногда называют гринвичским временем (GMT), хотя это немного разные вещи.
Стандарт, который будет использоваться в аппаратных часах, выбирается операционной системой. По умолчанию Windows использует местное время, macOS использует UTC, а другие UNIX и UNIX-подобные системы используют разные стандарты. ОС, использующая стандарт UTC, обычно рассматривает аппаратные часы как UTC и вносит в них поправку для установки времени ОС при загрузке в соответствии с часовым поясом.
Если на машине установлено несколько операционных систем, все они будут получать текущее время от одних и тех же аппаратных часов: рекомендуется настроить их на использование UTC, чтобы избежать конфликтов. В противном случае, если аппаратные часы установлены на местное время, сразу несколько операционных систем могут попытаться скорректировать его, например, после перехода на летнее/зимнее время, что приведёт к избыточной коррекции; проблемы могут также возникнуть при перемещении между различными часовыми поясами и использовании одной из операционных систем для сброса системных/аппаратных часов.
Значение аппаратных часов можно прочитать и изменить с помощью команды timedatectl
.
Вы можете узнать текущий стандарт, который Arch использует для работы с аппаратными часами, с помощью следующей команды:
$ timedatectl | grep local
RTC in local TZ: no
Переход на использование местного времени для аппаратных часов:
# timedatectl set-local-rtc 1
Переход на использование UTC для аппаратных часов:
# timedatectl set-local-rtc 0
Эти команды автоматически обновят аппаратные часы и файл /etc/adjtime
, дополнительные действия не требуются.
Во время запуска ядра, в момент загрузки драйвера RTC, значение системных часов может быть установлено по аппаратным часам. Произойдет ли это, зависит от аппаратной платформы, версии ядра и опций сборки ядра. Если это происходит, то в этот момент последовательности загрузки время аппаратных часов принимается за UTC и значение /sys/class/rtc/rtcN/hctosys
(N=0,1,2,..) будет установлено в 1.
Позже systemd снова обновляет системное время по аппаратным часам, опираясь на значения в /etc/adjtime
. Следовательно, использование аппаратных часов с местным временем может привести к неожиданному поведению во время загрузки, например, системные часы могут перескочить назад по времени, что всегда является плохой идеей (это ещё не всё). Чтобы избежать этого, systemd будет синхронизироваться назад, только если аппаратные часы установлены в UTC, и не будет информировать ядро о локальном часовом поясе. Как следствие, временные метки на файловой системе FAT, которые изменены через Linux, будут в UTC.
- Использование
timedatectl
требует активной шины D-Bus. Поэтому использование этой команды под chroot (например, во время установки) может оказаться невозможным. В таких случаях можно вернуться к команде hwclock или использовать systemd-nspawn вместо chroot. - Если файл
/etc/adjtime
отсутствует, systemd по умолчанию считает, что аппаратные часы используют UTC.
UTC в Microsoft Windows
При двойной загрузке с Windows рекомендуется настроить Windows на использование UTC, а не настраивать Linux на использование местного времени. (По умолчанию Windows использует местное время [1].)
Это делается простым изменением в реестре: откройте regedit
и добавьте DWORD
ключ со значением 1
здесь:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\RealTimeIsUniversal
Это можно сделать одной командой в командной строке, запущенной от имени администратора:
reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /d 1 /t REG_DWORD /f
Также можно создать *.reg
файл и импортировать его в реестр двойным щелчком мыши:
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation] "RealTimeIsUniversal"=dword:00000001
Если Windows попросит обновить часы в связи с изменениями DST, позвольте ей это сделать. Часы останутся в UTC, как и ожидалось, скорректируется только отображаемое время.
После этого #Аппаратные часы и #Системные часы может понадобиться обновить.
Если у вас проблемы со смещением времени, попробуйте переустановить tzdata и заново установить часовой пояс:
# timedatectl set-timezone Europe/Moscow
Исторические примечания
В очень старых версиях Windows это всё не работает из-за их багов. Более конкретно,
- В 64-битных версиях Windows 7 и старых сборках Windows 10 существовала ошибка, из-за которой требовалось значение
QWORD
со значением1
вместоDWORD
. Эта ошибка была исправлена в новых сборках, и теперь работает толькоDWORD
. - До Vista SP2 существовала ошибка, которая сбрасывала часы на местное время после возвращения из ждущего или спящего режима.
- В XP и более старых версиях есть ошибка, связанная с переходом на летнее время. Подробнее: [2]
- Для еще более старых версий Windows лучше прочитать https://www.cl.cam.ac.uk/~mgk25/mswish/ut-rtc.html — тогда эта функциональность даже не была задокументирована и официально не поддерживалась.
Для этих операционных систем рекомендуется использовать местное время.
UTC в Ubuntu
Если Ubuntu на любом диске обнаруживает Windows в процессе установки, то для аппаратных часов она автоматически начинает использовать местное время. Очевидно, это сделано специально, чтобы позволить новым пользователям Linux опробовать Ubuntu на своих компьютерах с Windows без редактирования реестра.
Изменить это поведение можно так же, как описано выше.
Часовой пояс
Узнать текущий часовой пояс, установленный в системе:
$ timedatectl status
Просмотр списка доступных часовых поясов:
$ timedatectl list-timezones
Изменение часового пояса:
# timedatectl set-timezone Регион/Город
Например:
# timedatectl set-timezone Europe/Moscow
Эта команда создаст символическую ссылку /etc/localtime
, которая ведёт на соответствующий файл с информацией о зоне в /usr/share/zoneinfo/
. Если вам нужно создать её вручную (например, внутри chroot, где timedatectl
не работает), имейте в виду, что это должна быть именно символическая ссылка:
# ln -sf /usr/share/zoneinfo/Регион/Город /etc/localtime
Смотрите timedatectl(1) и localtime(5) для более подробной информации.
Выбор на основе геолокации
Чтобы автоматически выбрать часовой пояс на основе информации об IP-адресе, можно использовать какой-нибудь API геолокации для получения часового пояса (нпример curl https://ipapi.co/timezone
) и передать его вывод в команду timedatectl set-timezone
. Примеры бесплатных или частично бесплатных GeoIP API:
Обновление часового пояса после подключения к сети через NetworkManager
Создайте скрипт NetworkManager dispatcher:
/etc/NetworkManager/dispatcher.d/09-timezone
#!/bin/sh case "$2" in up) timedatectl set-timezone "$(curl --fail https://ipapi.co/timezone)" ;; esac
Также можно использовать tzupdateAUR для автоматического выбора часового пояса по IP-адресу. Сравнение наиболее популярных API IP-геолокации поможет выбрать подходящий вариант.
Погрешность часов
Нет ничего идеального. В том числе и часов. Время на любых часах хоть немного но отличается от реального. Одними из наиболее точных считаются атомные часы. Кварцевые часы, используемые в компьютерах, также не являются абсолютно точными, зато имеют относительно постоянную погрешность.
При установке аппаратных часов с помощью hwclock
рассчитывается новое значение дрейфа в секундах в день. Значение дрейфа вычисляется с помощью разницы между новым установленным значением и значением аппаратных часов непосредственно перед установкой, с учётом значения предыдущего значения дрейфа и времени последней установки аппаратных часов. Новое значение дрейфа и время, когда часы были установлены, записываются в файл /etc/adjtime
, перезаписывая предыдущие значения. Таким образом, аппаратные часы могут быть скорректированы с учётом дрейфа при выполнении команды hwclock --adjust
; это также происходит при выключении, но только если демон hwclock
включен, поэтому в Arch-системах, использующих systemd, этого не происходит.
hwclock
считает прошедший период времени слишком коротким для точного расчёта дрейфа.Если аппаратные часы продолжают терять или набирать время с большим шагом, возможно, что был записан некорректный дрейф (но это применимо только в том случае, если запущен демон hwclock). Это может произойти, если вы неправильно установили время аппаратных часов или ваш стандарт времени не совпадает со стандартом времени в Windows или macOS. Значение дрейфа можно сбросить, сначала удалив файл /etc/adjtime
, а затем установив правильное время аппаратных и системных часов. Затем следует проверить правильность используемого стандарта времени.
/etc/adjtime
, даже при использовании systemd (например, вы не можете или не хотите использовать NTP), вы должны регулярно вызывать hwclock --adjust
, например, создав задание cron.Программные часы очень точны, но, как и большинство часов, не идеально точны и могут дрейфовать. Хотя и редко, системные часы могут потерять точность, если ядро пропускает прерывания. Существуют некоторые инструменты для повышения точности программных часов; смотрите #Синхронизация времени.
Синхронизация времени
Network Time Protocol (NTP) — это протокол для синхронизации часов компьютерных систем в сетях передачи данных с коммутацией пакетов и переменной задержкой. Ниже приведены реализации NTP, доступные для Arch Linux:
- Chrony — Клиент и сервер, дружественный к роумингу и разработанный специально для систем, которые не находятся в сети постоянно.
- ConnMan — Лёгкий сетевой менеджер с поддержкой NTP.
- Network Time Protocol daemon — Эталонная реализация протокола, особенно рекомендуемая для использования на серверах времени. Она также может регулировать частоту прерываний и количество тиков в секунду для уменьшения дрейфа системных часов и будет вызывать повторную синхронизацию аппаратных часов каждые 11 минут.
- ntpclient — Простой NTP-клиент с интерфейсом командной строки.
- NTPsec — Форк NTPd, ориентированный на безопасность.
- https://ntpsec.org/ || ntpsecAUR
- OpenNTPD — Является частью проекта OpenBSD и реализует как клиент, так и сервер.
- sntp — Клиент SNTP, который поставляется вместе с NTPd. Он заменяет ntpdate и рекомендуется в несерверных средах.
- systemd-timesyncd — Простой демон SNTP, который реализует только клиентскую часть, фокусируясь только на запросе времени с одного удалённого сервера. Он должен быть более чем подходящим для большинства установок.
Настройки для пользователя/сессии или временные настройки
В некоторых случаях может быть полезно изменить настройки времени, не затрагивая глобальные системные значения. Например, для тестирования приложений, полагающихся на время во время разработки, или для настройки системного часового пояса при удалённом входе на сервер из другой зоны.
Чтобы заставить приложение «видеть» дату/время, отличное от системного, можно воспользоваться утилитой faketime(1) (из пакета libfaketime).
Если вы хотите, чтобы приложение «видело» часовой пояс, отличный от системного, установите переменную окружения TZ
, например:
$ date && export TZ=":/usr/share/zoneinfo/Pacific/Fiji" && date
Вт 01 ноя 2016 16:34:51 MSK Ср 02 ноя 2016 01:34:51 +12
Это отличается от простой установки времени, поскольку, например, позволяет протестировать поведение программы с положительными или отрицательными значениями смещения UTC, или влияние изменений летнего/зимнего времени при разработке на системах с часовым поясом, в котором нет переходов на летнее/зимнее время.
Другим вариантом использования является установка разных часовых поясов для разных пользователей одной системы: это можно сделать, установив переменную TZ
в конфигурационном файле оболочки; смотрите Переменные окружения#Установка переменных.
Советы и рекомендации
fake-hwclock
alarm-fake-hwclock разработан специально для систем без нормально работающих аппаратных часов. Он включает в себя службу systemd, которая при выключении сохраняет текущее время, а при следующем запуске восстанавливает сохранённое время, таким образом избегая странных ошибок путешествия во времени.
Установите пакет fake-hwclock-gitAUR, запустите и включите службу fake-hwclock.service
.
Решение проблем
Часы показывают значение, которое не является ни UTC, ни местным временем
Это может быть вызвано рядом причин. Например, если ваши аппаратные часы используют местное время, но timedatectl
настроен на то, чтобы считать, что они используют UTC, в результате смещение вашего часового пояса относительно UTC будет применено дважды, что приведёт к неправильным значениям местного времени и UTC.
Чтобы заставить ваши часы показывать правильное время, а также записать правильный UTC в ваши аппаратные часы, выполните следующие шаги:
- Настройте ntpd (включать его как службу не обязательно).
- Установите правильный часовой пояс.
- Запустите
ntpd -qg
для ручной синхронизации ваших часов с сетью, игнорируя большие отклонения между локальным UTC и сетевым UTC. - Запустите
hwclock --systohc
для записи текущего системного времени в аппаратные часы.