論よりコード(結論)
前提条件
- WSL2 内から Windows プロセスの起動を許可していること
- PowerShell 7 以上であること
wsl.exe -u root date --set @$(pwsh.exe -Command 'Get-Date -UFormat %s')
#=> 設定日付が表示される (e.g. Fri Jan 26 12:25:47 JST 2024)
前提条件についての説明
Windows プロセスの起動を許可の件は、defaultが許可なので特に手を入れる必要はないはず。確認先は wsl.conf
内 [interop]
セクションの enabled
キーの値が true
です。
PowerShell の件は、Windows 標準添付は 1 や 5 だったりするので https://aka.ms/PSWindows から 7 をインストールしておきましょう。PowerShell 1 でもやる方法は後述。
どういうことなのか
2024年1月時点で標準入手できる Linux kernel では「WindowsとWSL2の時刻のずれを修正する」あるように、時刻がズレます。
同記事に書かれているように hwclock
コマンドの参照先 /dev/rtc0
もズレてることがあるため、同記事ではファイルのタイムスタンプで Windows OS 側と同期する手法が紹介されていました。
仕組み
記事内では、時刻比較に PowerShell を使っているではありませんか。PowerShell 側から wsl.exe 経由で date コマンド実行しているわけです。逆も然りと考え、Linux(Ubuntu)側から PowerShell を呼び出し、その返却値を date --set
に流し込んだというのが、この仕組みです。
- PowerShell に Windows OS の時刻を基にした UNIX エポック秒を出力させる
-
date --set @エポック秒
の引数にする
date --set
は root 権限が必要なため
-
sudo
で実行 (sudoerr に追加しておく準備が必要) -
wsl.exe -u root
で実行 (事前準備無し)
どちらかで時刻設定ができます。
ちなみに PowerShell 1 だと Get-Date -UFormat %s
の返却値はミリ秒込みになり、また(なぜか)+9時間されたあとの値になってしまい、そのまま date --set の引数に設定できなかったので、PowerShell 7 にしました。こちらは希望通りの操作になります。
どうしても PowerShell 1 でやりたい場合は
powershell.exe -Command '[int](Get-Date -UFormat %s)-32400'
という手もあります。
実際の使い勝手
pwsh.exe の呼び出しに300msくらいかかってるようなので、すこし詰まった感じはしますが、ntpdate するよりは速いでしょう。
あと、実行すると必ず日付表示がされるため wsl.exe -u root date ... > /dev/null
とするのもよいでしょう。
私は .bashrc
の先頭に、このワンライナーを入れておきました。これで Shell 起動毎に時刻を Windows OS 側と同期してくれるので、もはや心配なし!(だと思う)
あとがき
お昼にしよう。
EoT