# Windows: установка системного времени

В какой-то момент я обнаружил, что на одной из моих домашних машин с Windows 10 установлено некорректное время, часы отставали. Я проверил службу Windows Time, она была запущена, но, судя по всему, не работала. Затем я проверил вторую машину (ноутбук) и там ситуация оказалась аналогичной, то есть время не устанавливалось.

Сначала я попробовал решить проблему с помощью Gemini, тот довольно быстро сдался и предложил устанавливать время с помощью скрипта, время предполагалось получать через HTTP с одной из общедоступных служб. Тогда я обратился к ChatGPT, тот оказался гораздо более умным и мы провели исследования в результате которых он пришел к выводу, что не работает что-то именно в самой службе Windows. Мы проверяли обе машины, отпали блокировки портов и протокола UDP, был проверен мой роутер, все было в рабочем состоянии. После того как я потратил на решение проблемы целый день, я решил остановиться и таки да, подключил скрипт в планировщик для установки времени при запуске компьютера.

### Фиксирую ряд моментов об этой службе.

В Windows за синхронизацию времени отвечает служба **Windows Time (`W32Time`)**. В упрощённом виде она работает так:

```text
Аппаратные часы компьютера
          │
          ▼
      W32Time
          │
          │ NTP/UDP 123
          ▼
   NTP-сервер
   time.windows.com
   pool.ntp.org
   и т.д.
          │
          ▼
     NTP-ответ
          │
          ▼
   расчёт смещения
          │
          ▼
  корректировка часов
```

Но внутри есть несколько важных механизмов.

#### 1. При загрузке Windows

Компьютер получает первоначальное время из **RTC/CMOS** — аппаратных часов материнской платы.

Именно поэтому при:

```powershell
w32tm /query /source
```

можно увидеть:

```text
Local CMOS Clock
```

Это **не означает, что CMOS является настроенным NTP-сервером**. Это означает: *последнего пригодного внешнего источника времени нет, поэтому система использует локальные часы*.

---

#### 2. W32Time выбирает источник

Настройка:

```powershell
w32tm /query /configuration
```

показывает, например:

```text
Type: NTP
NtpServer: time.windows.com,0x8
```

То есть W32Time должна обращаться к:

```text
time.windows.com
```

по протоколу **NTP**.

Можно указать несколько серверов:

```text
time.windows.com,0x8 pool.ntp.org,0x8 time.nist.gov,0x8
```

---

#### 3. Используется UDP/123

Классический NTP использует:

```text
UDP source port: 123
UDP destination port: 123
```

То есть W32Time создаёт NTP-сокет и отправляет примерно:

```text
PC 192.168.0.103:123
        │
        │ UDP
        ▼
NTP 213.239.234.28:123
```

Сервер отвечает:

```text
NTP 213.239.234.28:123
        │
        ▼
PC 192.168.0.103:123
```

Обычный NTP-клиент может работать иначе:

```text
192.168.0.103:59882 → 185.125.190.57:123
185.125.190.57:123 → 192.168.0.103:59882
```

А W32Time использует **локальный порт 123**.

---

#### 4. W32Time не просто спрашивает «который час?»

NTP-пакет содержит временные метки.

Упрощённо:

```text
T1 = время отправки запроса клиентом
T2 = время получения запроса сервером
T3 = время отправки ответа сервером
T4 = время получения ответа клиентом
```

По этим четырём значениям можно оценить:

**задержку сети:**

```text
delay ≈ (T4 - T1) - (T3 - T2)
```

и **смещение часов клиента:**

```text
offset ≈ ((T2 - T1) + (T3 - T4)) / 2
```

Поэтому NTP значительно сложнее простого:

> «отправил запрос → получил время сервера → поставил его себе».

---

#### 5. W32Time собирает несколько измерений

Windows не обязательно корректирует часы после одного ответа.

Она собирает **NTP samples**:

```text
sample 1
sample 2
sample 3
...
```

Затем отбрасывает плохие/аномальные измерения и пытается получить надёжную оценку смещения.

#### 6. Затем Windows корректирует часы

Если расхождение небольшое, Windows может **плавно изменить скорость хода часов**, чтобы постепенно привести их к правильному времени.

Если расхождение достаточно большое, возможна **ступенчатая коррекция (step)**.

Поэтому W32Time — это не просто:

```text
получил время → SetSystemTime()
```

а полноценный механизм регулирования системных часов.

---

#### 7. Существует период опроса

В конфигурации можно увидеть:

```text
MinPollInterval: 10
MaxPollInterval: 15
```

Это степени двойки:

```text
2^10 = 1024 секунд
2^15 = 32768 секунд
```

То есть интервал может динамически изменяться примерно от:

```text
17 минут
```

до:

```text
9 часов
```

Кроме того, может быть:

```text
SpecialPollInterval: 16384
```

Это примерно:

```text
4 часа 33 минуты
```

Конкретное поведение зависит от режима и флагов peer'а.

---

#### Что происходит при `w32tm /resync`

Когда мы выполняем:

```powershell
w32tm /resync
```

это **не просто команда "скажи серверу время"**.

Она заставляет службу попытаться выполнить новую синхронизацию.

Упрощённо:

```text
w32tm /resync
       │
       ▼
    W32Time
       │
       ▼
выбрать peer
       │
       ▼
отправить NTP-запрос
       │
       ▼
получить ответ
       │
       ▼
создать NTP sample
       │
       ▼
проверить sample
       │
       ▼
рассчитать offset
       │
       ▼
скорректировать системные часы
```

#### Почему `stripchart` здесь очень важен

Команда:

```powershell
w32tm /stripchart /computer:213.239.234.28 /dataonly /samples:3
```

тоже использует NTP, но это **не тот же самый механизм синхронизации, что W32Time service**.

Например:

```text
19:58:08, +09.6895857s
19:58:10, +09.6929900s
19:58:12, +09.6926500s
```

Это доказывает:

```text
DNS              ✓
маршрутизация    ✓
UDP/123          ✓
NTP-сервер       ✓
ответ сервера    ✓
```

Но это **не доказывает**, что W32Time сможет использовать этот ответ для собственной синхронизации.

#### И ещё одна важная деталь

W32Time создаёт сокеты:

```text
[::]:123
0.0.0.0:123
```

То есть сама служба слушает **порт UDP 123 на компьютере**.

А `stripchart` может использовать другой сетевой путь/сокет.

Поэтому принципиальная разница сейчас выглядит так:

```text
                 W32Time
                    │
             source port 123
                    │
                    ▼
              router/NAT
                    │
                    ▼
             NTP server
                    │
                    ▼
              ??? :123
                    │
                    ▼
                 W32Time
```

против:

```text
              stripchart
                    │
             ephemeral port
                    │
                    ▼
              router/NAT
                    │
                    ▼
             NTP server
                    │
                    ▼
          ephemeral port
                    │
                    ▼
              stripchart
```

### Установка времени скриптом.

Создайте папку для скриптов, например C:\\Scripts и в ней файл SyncTime.ps1 со следующим содержимым:

```bash
try {
    $res = Invoke-WebRequest -Uri "https://ya.ru" -Method Head -TimeoutSec 5 -UseBasicParsing
    $serverTime = [datetime]$res.Headers.Date
    Set-Date $serverTime
} catch {
    $res = Invoke-WebRequest -Uri "https://www.google.com" -Method Head -TimeoutSec 5 -UseBasicParsing
    $serverTime = [datetime]$res.Headers.Date
    Set-Date $serverTime
}

```

Сначала будет попытка получить время от Яндекса, если не получится, то от Google.

- Нажмите **`Win + R`**, введите `taskschd.msc` и нажмите `Enter` (Планировщик заданий).
- Справа нажмите **«Создать задачу...»** (Create Task).
- **На вкладке «Общие»**:
    
    
    - Имя: `HTTP Time Sync`
    - Обязательно выберите галочку: **«Выполнить с наивысшими правами»** (Run with highest privileges) — это нужно, чтобы у скрипта были права на изменение системного времени.
    - В поле «Настроить для» выберите **Windows 10** (или Windows 11).
- **На вкладке «Триггеры»**:
    
    
    - Нажмите **«Создать...»** -&gt; В поле «Начать задачу» выберите **«При запуске»** (At startup) -&gt; ОК.
    - **«При подключении к сети»** (On workstation unlock / или по событию сна) — чтобы время корректировалось, когда вы открываете крышку ноутбука или разблокируете экран.
- **На вкладке «Действия»**:
    
    
    - Нажмите **«Создать...»** -&gt; Действие: **«Запуск программы»** (Start a program).
    - В поле «Программа или сценарий» введите: `powershell.exe`
    - В поле «Добавить аргументы (необязательно)» введите: `-ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Scripts\SyncTime.ps1"`
- **На вкладке «Условия» и «Параметры»**:
    
    
    - Снимите галочку «Запускать задачу только при питании от электросети» (если это ноутбук).
    - Поставьте галочку «Запускать задачу как можно скорее после пропуска планового запуска».