System time (Русский)

From ArchWiki
Состояние перевода: На этой странице представлен перевод статьи System time. Дата последней синхронизации: 4 февраля 2022. Вы можете помочь синхронизировать перевод, если в английской версии произошли изменения.

В операционной системе время (часы) определяется тремя понятиями: значением времени (будь то местное время, 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
Совет: Можно найти и выбрать нужный часовой пояс с помощью интерактивного помощника tzselect.

Смотрите timedatectl(1) и localtime(5) для более подробной информации.

Выбор на основе геолокации

Примечание: Некоторые среды рабочего стола поддерживают автоматический выбор часового пояса (например, смотрите GNOME (Русский)#Дата и время).

Чтобы автоматически выбрать часовой пояс на основе информации об 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, этого не происходит.

Примечание: Если время аппаратных часов устанавливается повторно менее чем через 24 часа после предыдущей установки, дрейф не пересчитывается, поскольку hwclock считает прошедший период времени слишком коротким для точного расчёта дрейфа.

Если аппаратные часы продолжают терять или набирать время с большим шагом, возможно, что был записан некорректный дрейф (но это применимо только в том случае, если запущен демон hwclock). Это может произойти, если вы неправильно установили время аппаратных часов или ваш стандарт времени не совпадает со стандартом времени в Windows или macOS. Значение дрейфа можно сбросить, сначала удалив файл /etc/adjtime, а затем установив правильное время аппаратных и системных часов. Затем следует проверить правильность используемого стандарта времени.

Примечание: Если вы хотите использовать значение дрейфа, хранящееся в /etc/adjtime, даже при использовании systemd (например, вы не можете или не хотите использовать NTP), вы должны регулярно вызывать hwclock --adjust, например, создав задание cron.

Программные часы очень точны, но, как и большинство часов, не идеально точны и могут дрейфовать. Хотя и редко, системные часы могут потерять точность, если ядро пропускает прерывания. Существуют некоторые инструменты для повышения точности программных часов; смотрите #Синхронизация времени.

Синхронизация времени

Network Time Protocol (NTP) — это протокол для синхронизации часов компьютерных систем в сетях передачи данных с коммутацией пакетов и переменной задержкой. Ниже приведены реализации NTP, доступные для Arch Linux:

  • Chrony — Клиент и сервер, дружественный к роумингу и разработанный специально для систем, которые не находятся в сети постоянно.
https://chrony.tuxfamily.org/ || chrony
  • ConnMan — Лёгкий сетевой менеджер с поддержкой NTP.
https://01.org/connman (waybackmachine) || connman
  • Network Time Protocol daemon — Эталонная реализация протокола, особенно рекомендуемая для использования на серверах времени. Она также может регулировать частоту прерываний и количество тиков в секунду для уменьшения дрейфа системных часов и будет вызывать повторную синхронизацию аппаратных часов каждые 11 минут.
https://www.ntp.org/ || ntp
  • ntpclient — Простой NTP-клиент с интерфейсом командной строки.
http://doolittle.icarus.com/ntpclient/ || ntpclientAUR
  • NTPsec — Форк NTPd, ориентированный на безопасность.
https://ntpsec.org/ || ntpsecAUR
  • OpenNTPD — Является частью проекта OpenBSD и реализует как клиент, так и сервер.
https://www.openntpd.org/ || openntpd
  • sntp — Клиент SNTP, который поставляется вместе с NTPd. Он заменяет ntpdate и рекомендуется в несерверных средах.
https://www.ntp.org/ || ntp
  • systemd-timesyncd — Простой демон SNTP, который реализует только клиентскую часть, фокусируясь только на запросе времени с одного удалённого сервера. Он должен быть более чем подходящим для большинства установок.
https://www.freedesktop.org/wiki/Software/systemd/ || systemd

Настройки для пользователя/сессии или временные настройки

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

Чтобы заставить приложение «видеть» дату/время, отличное от системного, можно воспользоваться утилитой 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 для записи текущего системного времени в аппаратные часы.

Смотрите также