WSL2时钟与Windows不同步。

174

从睡眠/休眠恢复后,WSL2时钟会失去同步。 illustration showing Windows clock and WSL clock out of sync

GitHub上分享了一个解决方法sudo hwclock -s来重新同步WSL中的时钟,但是每次从睡眠/休眠中恢复都需要执行此操作。


44
2023年了,问题仍然存在... - CodeWarrior
17个回答

234

如果有人通过搜索找到这篇文章,并没有注意到问题中实际上已经列出了解决方案,你可以通过以下方式修复WSL时钟漂移。

sudo hwclock -s

如果您只需要偶尔这样做,这是一个不错的解决方案。如果您需要更频繁地这样做,请考虑 @piouson 的解决方案。


1
我希望这也能在WSL 1上运行,但是我得到了错误信息hwclock: Cannot access the Hardware Clock via any known method. - Ryan
请注意,此错误已修复,您只需要安装内核更新即可-请参考其他答案。 - mikemaccana
6
仍然(或再次)在Kernel 5.15.79.1-microsoft-standard-WSL2上看到漂移(WSL日期在未来)。 - leopold.talirz
3
有时候硬件时钟也会显示错误的时间,因此这并没有帮助,你需要使用类似于ntpdate的东西。这个问题在某个时间点被修复了,但是又重新出现了。在WSL GitHub上有一个针对此问题的问题:https://github.com/microsoft/WSL/issues/10006 - Juha Palomäki
4
我仍然遇到这个问题,但是hwclock没有帮助。对我来说,sudo ntpdate ntp.ubuntu.com起作用了。 - crockeea

66

更新

修复现在已经在WSL2 Linux内核的5.10.16.3及更高版本中实现!请注意,您可能需要从Windows商店安装WSL2以获取最新的内核版本,参见这个与Microsoft的Craig的对话

旧回答

sudo hwclock -s可以帮助您接近目标,但由于某种原因,它无法获得精确的时间-我经常发现它比实际时间快一分钟左右!

sudo ntpdate pool.ntp.org应该可以为您提供正确的时间。

但这都是因为Linux内核中的一个错误,这个错误应该会在某个时候包含在Windows更新中...

GitHub问题中引用了许多解决此问题的hack,但根据我的经验,它们并不总是有效...


4
我调试脚本花了两天时间,最后才意识到问题出在时钟上。使用"hwclock -s"命令对我没有用,但使用"ntpdate"命令解决了问题。非常感谢! - Peppershaker
2
我已经安装了5.10.102.1-microsoft-standard-WSL2,但每次都需要这样做。我错过了什么吗? - Micah Smith
22
我正在使用内核版本为5.15.79.1-microsoft-standard-WSL2,但当我暂停我的笔记本电脑时仍然受到影响。 - Paulo Freitas
10
我也是,我使用的是“5.15.79.1-microsoft-standard-WSL2”,但我仍然遇到了这个问题。wsl --status显示“默认发行版:Ubuntu-22.04”、“默认版本:2”。 - user1507435
13
那个内核更新肯定没有修复这个问题,我在最新的WSL Insider版本上仍然遇到了这个问题。 - Tofandel
显示剩余7条评论

40

只需重新启动WSL,对我来说它可以正常工作

wsl --shutdown

那么

wsl

在PowerShell中


4
但是每次问题重新出现时,您都必须重新启动吗? - piouson
2
我的解决方案通过使用Windows任务计划程序进行自动重新运行,从而消除了每次重启的需要。 - piouson
2
我给任何懒得做解决方案的人提供选项。由他们自己选择哪一个。 - fahmiduldul
3
我试图将我的WSL和Windows日期更改为未来的某个时间,以进行一些测试,以下是对我有效的操作:有些人误认为 sudo hwclock -s 会同步到 Windows,但其实不是。它实际上是将日期同步到您的硬件时钟。重新启动WSL(这正是此答案建议的方式)会将日期同步到Windows,因此您可以轻松地将Windows和WSL都更改为某个虚假日期。谢谢 :) - Float07
2
这是Windows用户最常用的解决方案:关掉然后再打开。 - Damien
显示剩余3条评论

27

更新:drkvogel所提到的,时钟同步修复已在WSL2内核版本5.10.16.3中发布,但您应安装Windows Store版本的WSL:

# powershell install by id
winget install 9P9TQF7MRM4R

# powershell install by name
winget install 'Windows Subsystem for Linux'

撰写本文时,这个GitHub Issue仍然存在。

我选择的解决方法(在WSL2中使用单个发行版)是使用Windows任务计划程序,在Windows重新同步硬件时钟时运行hwclock命令。

Windows:以管理员身份打开PowerShell

schtasks /create /tn WSLClockSync /tr "wsl.exe sudo hwclock -s" /sc onevent /ec system /mo "*[System[Provider[@Name='Microsoft-Windows-Kernel-General'] and (EventID=1)]]"
Set-ScheduledTask WSLClockSync -Settings (New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries)

WSL2:运行sudo visudo并将hwclock添加到sudoers以跳过密码提示。
# bottom of my file looks like this
...
...
#includedir /etc/sudoers.d
<username> ALL=(ALL) NOPASSWD:/usr/sbin/hwclock, /usr/bin/apt update, /usr/bin/apt upgrade

Results

illustration showing Windows clock and WSL clock in sync

请参考图片中的步骤,获取Windows事件过滤器中的事件XPath。按照提供的方式使用,让任务计划程序自动显示预定的触发器。

illustration showing scheduled task created

这里有一个批处理脚本,可以自动完成这个过程,适用于每个已注册的发行版。
@echo off
rem this is a programmatic reminder of how to set up wsl clock sync
rem to prevent clock drift after sleep etc
rem see https://dev59.com/D1EG5IYBdhLWcg3wf_nV#65086857 and https://github.com/microsoft/WSL/issues/5324

set WSL_UTF8=1
setlocal EnableDelayedExpansion
for /F "tokens=* delims=" %%D in ('wsl --list --quiet') DO (
    set hwclock_count=0
    for /f "tokens=* delims=" %%C in ('wsl -d %%D bash -c "grep -c hwclock /etc/sudoers.d/hwclock 2>/dev/null"') DO set hwclock_count=%%C
    if !hwclock_count! neq 1 (
        echo Setting up sudo permissions for hwclock on distro %%D - will prompt for password...
        wsl -d %%D sudo bash -c "echo -e '\x25adm ALL=(ALL)  NOPASSWD:/usr/sbin/hwclock -s' > /etc/sudoers.d/hwclock"
    ) else echo hwclock permissions already set up with !hwclock_count! - not changing...
    echo Testing resetting the clock - shouldn't prompt for password...
    wsl -d %%D sudo /usr/sbin/hwclock -s
    set syncname="WSLClockSync%%D"
    echo Creating scheduled task %syncname%...
    schtasks /create /f /tn "%syncname%" /tr "wsl.exe sudo hwclock -s" /sc onevent /ec system /mo "*[System[Provider[@Name='Microsoft-Windows-Kernel-General'] and (EventID=1)]]"
    echo Scheduling %syncname% to run even when on batteries...
    powershell -command "& {Set-ScheduledTask %syncname% -Settings (New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries)}"
    echo Done!
)

2
如果您正在运行常见于WSL的Ubuntu操作系统,则此方法将会默默失败,因为hwclock列出的路径是不正确的。在Ubuntu上,正确的路径是/sbin/hwclock - Don Alvarez
hwclock命令无法工作,不得不重新启动WSL。我认为这是由于笔记本电脑完全失去RTC时间,因为电量耗尽所致。 - tyger
1
可以确认@fepegar所说的。我也因为5.10.102.1-microsoft-standard-WSL2上的时钟不同步而找到了这篇文章。但是命令sudo hwclock -s有效(Ubuntu 20.04)。 - M. Eriksson
1
如果你使用 wsl.exe -u root hwclock -s,就不需要使用 sudo - undefined
1
我已经添加了一个DOS批处理脚本,可以自动设置这个过程。 - undefined
显示剩余4条评论

8

回复楼上的帖子:截至2022年5月,这个问题仍然存在。

该问题有两个组成部分。

首先,Windows时间同步需要合理。对于未加入域的计算机,默认情况下不合理。

  • 更改w32time自动启动。在管理员cmd中(但不是PowerShell),输入sc triggerinfo w32time start/networkon stop/networkoff。使用sc qtriggerinfo w32time进行验证。通过此方式进入cmd,可以在管理员PowerShell中启动,然后只需键入cmd即可。

  • 在regedit中进行几个更改。

    • Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w32time\Config中,将MaxPollInterval设置为十六进制c,十进制12
    • 检查Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w32time\Parameters\NtpServer。如果以0x9结尾,则完成。如果以0x1结尾,则需要在Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w32time\TimeProviders\NtpClient中调整SpecialPollInterval,使其读取3600
  • 重新启动计算机,然后从PowerShell运行w32tm /query /status /verbose以验证w32time服务是否已启动。如果未启动,请再次检查触发器。如果一切都失败了,请将其设置为自动延迟启动。

其次,WSL2需要保持同步。微软很可能会发布另一个内核修复程序。同时,可以使用定期计划任务将其带回同步状态: schtasks /Create /TN WSL2TimeSync /TR "wsl -u root hwclock -s" /SC ONEVENT /EC System /MO "*[System[Provider[@Name='Microsoft-Windows-Kernel-Power'] and (EventID=107 or EventID=507) or Provider[@Name='Microsoft-Windows-Kernel-General'] and (EventID=1)]]" /F


1
我应该指出,对我来说,“hwclock -s”没有解决这个问题,尽管我正在运行最近的WSL内核。我的Windows时间没问题,但同步出了问题……导致我的WSL时间比实际时间晚30秒以上。因为我调用API时需要非常敏感的时间要求(5秒钟),所以我必须依靠“ntpdate”。 - Mike Caron
你是否为时间同步在更新后仍然失败而提出了Github问题?如果你认为问题仍然存在,微软的某个人将会查看它。 - mikemaccana

7

使用cron调度sudo hwclock -s

正如其他人之前所说的,sudo hwclock -s可以同步时钟,但你需要在每次睡眠/休眠后执行此操作。解决方案是添加一个每小时运行的cron任务来同步时钟。

使用sudo打开crontab(由于该命令使用sudo,必须使用sudo打开):

sudo crontab -e 

并在任务之后添加这段代码(这是cron的要求):

PATH=/sbin:/bin:/usr/bin
@hourly hwclock -s

因为root-cron没有PATH环境变量,所以您必须设置它,或使用绝对路径,例如/usr/sbin/hwclock

cron故障排除:

  • 要验证cron是否工作,您可以添加一个虚拟任务(不要忘记添加一个新行):
    * * * * * date > /tmp/log.txt
  • 如果没有文件被创建,请验证cron是否在运行:pgrep cron
    如果没有PID显示,请使用sudo service cron start启动cron。
  • 要了解cron时间方法:cron时间生成器

6
这在我的Ubuntu 22.04.2 LTS上有效。
安装ntpdate。
sudo apt install ntpdate

将此行添加到 ~/.profile 文件中。
sudo ntpdate time.windows.com

现在每次打开一个新的会话,日期和时间都会同步。如果你想要为一个已存在的会话进行同步,运行以下命令:
sudo ntpdate time.windows.com

5

我大约6-9个月前开始遇到这个问题。 重启 wsl 总是有效的,但由于明显的原因,这并不理想。hwclock -s 通过 cron 定时作业定期运行几个月,但现在不再起作用了。@igor-alex 的方法对我有用,但需要一些不同的步骤:

/etc/wsl.conf(与上面相同)

[boot]
systemd=true

安装systemd-timesync(与上述相同)

sudo apt install systemd-timesyncd

对于 timesyncd 的建议编辑对我没有起作用,导致服务无法启动。相反,我采取了以下措施:

sudo systemctl edit systemd-timesyncd.service

[Unit]
ConditionVirtualization=
ConditionVirtualization=wsl

感谢https://unix.stackexchange.com/a/737366/547670提供的帮助。

并启动它(与上述相同)

sudo systemctl start systemd-timesyncd

HTH


还可以将ConditionVirtualization=这一行注释掉。我使用的是Windows 11。 - undefined

4

这个GitHub问题已经被关闭。

你也可以在PowerShell终端中运行以下命令进行同步:

wsl.exe sudo hwclock -s


对我来说,这很有效。昨天我更新了我的Windows 11到新版本,发现Ubuntu时钟从那时起就坏了。上面的命令解决了这个问题。 - Laerion
非常感谢,它解决了我的问题。在WSL2上开发Python应用程序时遇到了时间不同步的问题。 - Ali Abdi
如果你使用wsl.exe -u root hwclock -s,就不需要使用sudo - undefined

4
如果在高于5.10.16.3版本上仍然出现该问题(就像我的版本5.15.90.1一样),您可以通过systemd服务来修复它。
首先,请确保您已启用systemd,/etc/wsl.conf中有以下内容:
[boot]
systemd=true

然后安装 systemd-timesyncd

sudo apt install systemd-timesyncd

编辑 timesyncd 配置:

sudo systemctl edit systemd-timesyncd

使用(使其在虚拟化环境中运行):

[Unit]
ConditionVirtualization=

然后开始它:

sudo systemctl start systemd-timesyncd

感谢Github问题的解决方案。


1
好的,我会把这个写进 nixos-wsl :) - SuperSandro2000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接