clockwindows-task-schedulerwindows-subsystem-for-linux

WSL2 REST API Error due to WSL2 clock out of sync with Windows clock


WSL2 clock goes out of sync after resuming from sleep/hibernate. illustration showing Windows clock and WSL clock out of sync

A workaround was shared on GitHub sudo hwclock -s to resync clock in WSL, but you have to do this every time you resume from sleep/hibernate.


Solution

  • UPDATE: as mentioned by drkvogel, the Clock Sync fix was released in WSL2 kernel version 5.10.16.3, however, you should install the Windows Store version of WSL:

    # powershell install by id
    winget install 9P9TQF7MRM4R
    
    # powershell install by name
    winget install 'Windows Subsystem for Linux'
    

    At time of writing, this GitHub Issue was open for the bug.

    The workaround I chose for my situation (single distro in WSL2) is to use Windows Task Scheduler to run hwclock in WSL whenever Windows resyncs hardware clock.

    Windows: Open PowerShell as Administrator

    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: Run sudo visudo and add hwclock to sudoers to skip password prompt

    # 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

    See image for how to get Event XPath from Windows Event filtering. Use as provided to let task scheduler auto-display scheduled triggers.

    illustration showing scheduled task created

    Here is a batch script that does this process automatically, for each registered distro:

    @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://stackoverflow.com/a/65086857/120398 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!
    )