Windowsの時刻同期(w32time)と業務システム ── 「ログのタイムスタンプが合わない」を仕組みから解決する

· 更新日: · · w32time, NTP, 時刻同期, Windows, ログ, 障害調査, 装置連携, Active Directory

更新履歴(3件・最終更新 2026年08月02日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
ワークグループPCのポーリング間隔を短くする節を新設しました(レジストリ設定だけでは効かず、`0x9`での`/manualpeerlist`指定が要る理由を含みます)。ドメインの時刻階層の図、NtpServerフラグの表(`0x1`単独が誤りである理由)、`w32tm /query /status`の項目名の日本語と英語の対応表を追加しました。
初版公開
この記事を引用する(DOI(登録済みアーカイブ): 10.5281/zenodo.21547425)

以下のDOIは過去に登録されたアーカイブを指しており、現在の本文とは一致しない場合があります。現在の本文を参照するときは、このページのURLを使用してください。

小村 豪(2026)「Windowsの時刻同期(w32time)と業務システム ── 「ログのタイムスタンプが合わない」を仕組みから解決する」合同会社小村ソフト. https://comcomponent.com/blog/windows-time-sync-w32time-guide/

DOI(登録済みアーカイブ)
10.5281/zenodo.21547425
DOI(前回登録した版)
10.5281/zenodo.21733136

「装置が異常停止した。装置側のログとPC側のアプリログを突き合わせたら、時刻が40秒ずれていて、装置のエラーとアプリの通信断のどちらが先だったのか確定できない」── 装置連携システムの障害調査で、私たちが何度も出会ってきた場面です。ネットワークカメラ、PLC、検査装置、そしてWindows PC。それぞれが自分の時計でログを刻んでおり、その時計たちが合っている保証は、実は誰も取っていなかった、という話です。

この記事で分けて考えるのは、「今のずれを調べる」「同期設定を整える」「ずれても調査できるログを残す」の3つです。 時計を直す操作と、ログを読み解くための測定を混同しないよう、順番に整理します。

時刻のずれは平常時にはほとんど誰も気づきません。困るのは決まって障害調査のとき、つまり「イベントの前後関係」が証拠として必要になったときです。そして調べ始めると、「ワークグループのPCは週1回しか同期していなかった」「仮想マシンがホストとNTPの両方から時刻をもらって揺れていた」「そもそも装置の時計は誰も合わせていなかった」といった事実が次々に出てきます。

この記事では、装置とPC、サーバーと端末のログ突合に苦労した経験のある開発者・情シス担当者を対象に、Windowsの時刻同期サービス(w32time)の仕組み、w32tmコマンドによる診断の実務、精度の現実的な期待値、そして「時刻はずれる・戻る」前提での業務システム側の設計までを、Microsoftの一次情報の裏付けつきで整理します。

1. まず結論

最初に設定を変えるのではなく、同期元・最終同期時刻・相手との時刻差を確認します。 w32tm /query /status で同期状態を読み、/stripchart で差を実測するのが出発点です。/config は設定変更、/resync は再同期なので、診断だけの操作とは分けて実施します。1

同期先を見直すときは、ドメイン参加機か、ワークグループ機かを先に分けます。ドメインではDCをたどる階層の頂点、フォレストルートのPDCエミュレーターを確認します。ワークグループでは既定の低頻度同期がずれの要因になります。仮想マシンでは、ホストとNTPの2系統があることに加え、OSの世代による違いも確認します。213

アプリ側の土台は、「いつ起きたか」はUTC、「どれだけかかったか」はStopwatchです。w32timeの補正でシステム時計は前後に跳ぶことがあるためです。また、「同期している」と「必要な精度を満たしている」は別で、1ms級の精度には時刻源・ネットワーク・負荷などの条件があります。456

目的別の読み方

今やりたいこと 先に読むところ 押さえる点
装置とPCのログの時刻差を調べたい 3.1〜3.2: 現状確認と差の実測 設定を変える前に、同期状態とオフセットを記録する
ドメイン全体が外部のログとずれる 2章: 同期先の決まり方 メンバーを個別設定する前に、階層の頂点を見る
ワークグループPCの同期先・間隔を変えたい 3.3以降: 設定変更 対象機とポリシーを確認し、変更後も状態と差を測る
1msの精度が必要 4章: 精度の条件 OSの対応だけでなく、構成条件と実測を確認する
VMの時計が揺れる・復元後にずれる 5章: 仮想マシン ホスト同期・NTP・OS世代を分ける
時刻が戻ってもログを追えるようにしたい 6章: アプリ設計 UTC・単調経過時間・装置とのオフセットを使い分ける

環境ごとの推奨アクションは7章の判断表にもまとめています。以下のOS世代や既定値は、本記事で扱う各構成についての説明です。自分の環境にそのまま当てはめず、実際の設定を第3章のコマンドで確認してください。

図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全23件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle

2. w32timeの仕組み ── ドメインとワークグループで動きがまったく違う

Windows Timeサービス(W32Time)は、Windows標準の時刻同期コンポーネントです。NTP(およびドメイン用のセキュアなMS-SNTP)でネットワーク上の時刻源から時刻サンプルを取得し、NTPのクロックフィルター/クロック選択アルゴリズムで最良のサンプルを選び、ローカル時計を調整します。NTPの厳密な実装ではありませんが、その仕様のアルゴリズム群を使うNTPクライアント/サーバーで、通信にはUDP 123番ポートを使います。2

押さえておきたいのは、構成によって同期先の決まり方が根本的に違うことです。

2.1 ドメイン: メンバーだけでなく、階層の頂点を見る

ドメイン環境(Type=NT5DS)では、AD DSフォレストにあらかじめ決められた時刻階層があります。メンバーPC/サーバーは自ドメインのDCと同期し、DCは親ドメインのDCと同期し、階層の頂点はフォレストルートドメインのPDCエミュレーター(または信頼できる時刻源として構成されたDC)です。NTPパケットはKerberosセッションキーで署名され、認証された時刻だけが受け入れられます。2 このため、ドメイン内のPC同士は普通そこそこ揃います。

問題は頂点で、PDCエミュレーターが外部の正確な時刻源(GPS時計や信頼できるNTPサーバー)と同期していないと、「全員で揃って間違った時刻」になります。ログを社外のシステムやクラウド側の記録と突き合わせた瞬間に、このずれが露呈します。

ここを設定するのは管理者外部の正確な時刻源GPS時計 / 信頼できるNTPサーバーフォレストルートドメインのPDCエミュレーター子ドメインのDC同じドメインの他のDCメンバーサーバー / PCメンバーサーバー / PCメンバーサーバー / PC

図1: ドメインの時刻階層 ── 矢印は時刻が配られる向き

この木を1枚の絵で見ると、根が間違えば全員が同じだけ間違うことがはっきりします。しかも全員が揃って間違うので、社内のログだけを見比べているかぎり誰も気づきません。外部と突き合わせた日に、初めて発覚します。頂点の設定を最初に確認すべき理由はここにあります。

2.2 ワークグループ: 既定の同期頻度と実際の設定を確認する

ワークグループ環境(Type=NTP)では、既定の同期先は time.windows.com,0x1 です。0x1(SpecialInterval)はポーリング間隔をSpecialPollIntervalレジストリ値で決めるフラグで、その既定値はスタンドアロン構成で604,800秒=1週間です。1 Windows 10クライアントでも1日1回程度で、Windows Server 2012 R2世代の既定は週1回でした。3

PCの内蔵時計(水晶発振器)は温度などの環境で日に秒単位でドリフトすることが珍しくないため、週1回の同期では数十秒のずれは普通に起こります。冒頭の「40秒ずれ」の正体は、たいていこれです。

2.3 補正方法: 徐々に合わせる場合と、時計を直接変える場合

もうひとつ実務で重要なのがクロック規律(clock discipline)の動きです。w32timeはずれが小さいうちはクロックの進む速度を上げ下げして徐々に合わせ(スルー)、ずれがMaxAllowedPhaseOffsetを超えると時計を直接設定します(ステップ)。21

さらに、ずれがMaxPosPhaseCorrection/MaxNegPhaseCorrection(スタンドアロン既定54,000秒=15時間)を超えると、補正せずイベントを記録するだけになります。1 「同期しているはずなのに直らない」ときは、この上限に引っかかっているケースがあります。そして、ステップ補正は負方向にもかかる、つまりWindowsのシステム時計は後ろに跳ぶことがある── これが後半のアプリ設計の話につながります。

3. w32tmコマンド実務 ── 現状確認、差の実測、同期先の変更

この章は、3.1〜3.2が現状の確認・測定、3.3以降が設定変更です。掲載したコードを上からすべて続けて実行する手順ではありません。いずれも管理者権限のコマンドプロンプトで実行します。1

3.1 現状確認: 同期元・最終同期時刻・階層を読む

最初は w32tm /query /status です。次のブロックは1行目がコマンド、それより下が出力例です。出力部分までコマンドとして貼り付けないでください。日付・サーバー名・数値は例です。

w32tm /query /status

うるう秒インジケーター: 0(警告なし)
階層: 4 (二次参照 - (S)NTP で同期)
精度: -23 (ティックごとに 119.209ns)
ルート遅延: 0.0312500s
ルート分散: 7.7756348s
参照 ID: 0xC0A80A14 (ソース IP:  192.168.10.20)
最終正常同期時刻: 2026/07/22 8:14:02
ソース: dc01.example.local
ポーリング間隔: 10 (1024s)

見るべきは次の3点です。7

  1. ソース: 意図した相手か。Local CMOS Clock や Free-running System Clock なら実質未同期です。
  2. 最終正常同期時刻: 最近か。何日も前なら、同期が機能しているかを疑います。
  3. 階層(Stratum): 正確な時刻源から何段目か。w32timeはStratum 15以下しか受け入れません。

必要に応じて、同期元・接続先・設定の出所を詳しく見る

同期元だけ知りたいときは w32tm /query /source、複数の同期先の状態は w32tm /query /peers、設定値とその出所(ポリシーかローカルか)は w32tm /query /configuration です。

日本語と英語の表示名を対応させる

上の出力は日本語ロケールのWindowsのものです。英語環境では項目名が変わるので、対応を挙げておきます。海外拠点の担当者とやり取りするときや、英語で検索するときに使ってください。なお表示名はロケールで変わるので、この出力を機械的に解析するスクリプトは書かないでください。

日本語ロケールの表示 英語ロケールの表示
うるう秒インジケーター Leap Indicator
階層 Stratum
精度 Precision
ルート遅延 Root Delay
ルート分散 Root Dispersion
参照 ID ReferenceId
最終正常同期時刻 Last Successful Sync Time
ソース Source
ポーリング間隔 Poll Interval

3.2 差の実測: 設定を変えずにオフセットを記録する

次に、相手との時刻差の実測です。障害調査で「サーバーとこのPC、今どれだけずれているか」を数値にするのに使います。ここも1行目がコマンドで、空行より下は出力例です。IPアドレスは実際の確認先に置き換えてください。

確認先はNTPに応答する相手です。NTPに対応しない独自時計の装置は、6.4のように装置時刻を読み出して差を記録します。

w32tm /stripchart /computer:192.168.10.20 /samples:5 /dataonly

192.168.10.20 [192.168.10.20:123] の追跡中。
現在の時刻は 2026/07/24 9:41:03 です。
09:41:03, +28.1246875s
09:41:05, +28.1250120s
09:41:07, +28.1248533s
09:41:09, +28.1251008s
09:41:11, +28.1249517s

この例なら「このPCは相手より約28秒遅れている」と読めます。/stripchart は表示用の測定であり、ローカル時計は変更しません。稼働中の装置PCで、まず差だけを調べるときに使えます。ログ突合の前に関係マシン全部に対して実行し、オフセット一覧表を作ってから突合を始めるのが、当社が障害調査で最初にやることです。

ここで分かるのは、測定した時点の相手との差です。 その値が障害発生時にも同じだったと決めつけず、過去ログの突合には、その期間に残したオフセットの記録も使います(6.4)。

3.3 同期先の変更: 対象機とポリシーを確認してから行う

ここからは設定と時計を変更する操作です。 /manualpeerlist による外部NTP指定は、原則として階層の頂点(PDCエミュレーター)や非ドメイン機向けです。ドメインメンバーの既定の階層同期を、診断のつもりで手動設定へ切り替えないでください。手動指定の時刻源が認証されない点は、この章の末尾でも説明します。2

先に /query /configuration でポリシー管理かローカル設定かを確認します。以下の ntp1.example.local と ntp2.example.local は例示名です。承認された実際の同期先に置き換え、時計の補正が業務へ影響しないタイミングで実施してください。

同期先を明示するには /config を使います。社内NTPサーバー(またはDC)を指定する定石はこうです。

w32tm /config /manualpeerlist:"ntp1.example.local,0x8 ntp2.example.local,0x8" /syncfromflags:manual /update
w32tm /resync

0x8 はクライアントモードで同期するフラグ、0x1(SpecialInterval)を組み合わせる(= ,0x9)とSpecialPollIntervalに従った間隔でポーリングします。0x1 単独ではクライアントモードのフラグが落ちるため、指定するなら ,0x8 か ,0x9 です。

同期先の台数と、ドメイン階層へ戻す操作

サーバーが2台しか用意できない場合は、片方に 0x2(UseAsFallbackOnly)を付けて優先順位を明示することが推奨されています(3台以上用意できるならその方が良い、というのがMicrosoftの案内です)。1

手動指定をやめてドメイン階層に戻すときは w32tm /config /syncfromflags:domhier /update してサービスを再起動します。w32tm /resync は蓄積された誤差統計を破棄して即時再同期させるコマンドで、設定変更後の反映確認に使います。1

3.4 NtpServerフラグ: モードとポーリング間隔を分けて読む

サーバー名のうしろに付ける数値がNtpServerフラグです。散らばると誤用しやすいので、1つの表にまとめます。1

フラグ 名前 意味
0x1 SpecialInterval ポーリング間隔を SpecialPollInterval レジストリ値で決める
0x2 UseAsFallbackOnly ほかの時刻源が使えないときの予備として扱う
0x8 Client クライアントモードでこの相手と同期する
0x9 Client + SpecialInterval 0x8 と 0x1 の組み合わせ。間隔を自分で決めたいときの定番

本記事の手動設定では、クライアントモードを明示する 0x8、間隔も指定するなら 0x9 を使います。 0x1 は間隔の指定であって、クライアントモードの明示ではありません。ただし、0x1 単独なら必ず同期しないという意味ではなく、送信モードは他の設定にも依存します。相手が対称アクティブモードを受け付けず同期できない場合に、0x8 でクライアントモードを明示するのがMicrosoftの案内です。8

ワークグループPCのポーリング間隔を短くする

この手順は、同期間隔を見直す必要があるワークグループPC向けです。3.3の同期先変更例とは選択肢として読み分けてください。ポリシー管理下なら、後述の管理用テンプレートから設定します。

第7章の判断表で挙げている「SpecialPollIntervalの短縮」は、レジストリ値の変更とサービス再起動で行います。既定の604,800秒(1週間)を3,600秒(1時間)にする場合の手順は次のとおりです。1

rem (1) ポーリング間隔を3,600秒にする(REG_DWORDの数値は10進で指定)
reg add "HKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient" /v SpecialPollInterval /t REG_DWORD /d 3600 /f

rem (2) SpecialPollIntervalが効くのは 0x1 を含むフラグを付けた時刻源だけ。0x9 で指定する
w32tm /config /manualpeerlist:"ntp1.example.local,0x9 ntp2.example.local,0x9" /syncfromflags:manual /update

rem (3) サービスを再起動して反映し、その場で同期させる
net stop w32time && net start w32time
w32tm /resync

rem (4) 反映結果と、各設定値の出所(ポリシーかローカルか)を確認する
w32tm /query /configuration
w32tm /query /status

レジストリ値だけでなく、時刻源のフラグと設定の出所を見る

(2)を省き、時刻源のフラグに 0x1 が含まれていなければ、レジストリだけ変えても指定間隔は使われません。SpecialPollInterval は、0x1 フラグの付いた時刻源に対してしか使われないためです。

また、グループポリシーで時刻設定を配っている環境では、ローカルのレジストリ変更は次のポリシー適用で上書きされます。w32tm /query /configuration の出力で各値の出所を確認し、ポリシー管理下なら「コンピューターの構成」>「管理用テンプレート」>「システム」>「Windows Time Service」>「Time Providers」>「Windows NTP クライアントを構成する」で設定してください。

変更後は、最後の2コマンドで設定と同期状態を確認し、必要に応じて /stripchart でも差を測ります。レジストリ値を書けたことだけで、同期が期待どおりに動いているとは判断しません。1

ドメインの認証された時刻との違い

なお、/manualpeerlist での外部NTP指定はドメインの認証された時刻とは別物で、認証されないため、ドメインメンバーには原則使わず、頂点(PDCエミュレーター)や非ドメイン機に対して使うものです。2

4. 精度の話 ── 既定でどこまで合うのか、1msの条件

「WindowsのNTP同期って、結局どのくらい合うんですか」という質問には、時代で答えが分かれます。

4.1 旧世代の設計目標と、2016以降の改善を分ける

Windows Server 2012 R2 / Windows 8.1以前のw32timeは、Kerberos認証の要件(既定5分)を満たす精度と、同一フォレスト内での「おおむね正確な時刻」を提供するのが設計目標で、それより厳しい精度要件は設計仕様の範囲外・サポート対象外と明言されています。6 つまり「秒単位で合っていれば設計どおり」の世界です。

Windows Server 2016 / Windows 10 1607以降はアルゴリズムが改善され、クロック更新頻度も既定で大幅に引き上げられました(例: サーバーはクロック調整が1時間に1回から毎秒に)。3 その結果、条件を満たせば1秒・50ms・1msの精度がサポート境界として定義されています。

4.2 1ms精度には、OS以外にも条件がある

1msの主な条件は次のとおりで、逆に言えばこれが揃わない環境で1msを期待してはいけません。6

  • 正確で安定したStratum 1時刻源(GPS時計など)を頂点とするNTP階層で、経路上のWindowsがすべて高精度構成であること
  • 時刻源との間のネットワーク遅延が0.1ms未満、時刻源からStratum 5以内・4ホップ以内
  • 各階層のCPU使用率(1日平均)が80%以下(仮想化環境ではホストも)

また、time.windows.comのようなインターネット上のリモート時刻源では、経路の非対称性や混雑の影響を受けるため1ms精度は期待できないとされています。7

4.3 実務の目安と、要求精度を分ける

以下は構成を考えるための実務上の相場観であり、個々の環境でその精度を保証する値ではありません。 実務の相場観としては、「既定のワークグループ=秒〜数十秒ずれうる」「まともに構成した社内NTP同期=数十ms〜1秒以内」「専用の時刻源と設計をしたとき=ms級」の3段階で考えるのが安全です。装置連携でms単位の前後関係が必要なら、時刻同期に頼るのではなく、後述のとおり片側のクロックで測る設計に寄せるべきです。

5. 仮想マシンの時刻 ── Hyper-V時刻同期統合サービスとNTPの二重関係

仮想マシンの時刻は物理機よりこじれやすい領域です。理由は単純で、時刻をくれる相手が2系統あるからです。Hyper-VゲストのWindowsには、ホストから時刻をもらうHyper-V時刻同期統合サービス(VMICTimeSyncプロバイダー)と、通常のNTPクライアントの両方があり、Windowsは階層(Stratum)、ルート遅延、ルート分散、オフセットの順で「良い方」を選びます。7

5.1 Hyper-V: 2016以降の改善と、旧ゲストの対処を分ける

Windows Server 2016でこの仕組みは大きく改善されました。VM起動・復元時の初期時刻が正確になり、割り込み遅延を補正したサンプルがw32timeに渡されるようになって、ホストに対して10µs程度の精度を保てます。ホストがゲストに報告するStratumも「ホストのStratum+1」という実態に沿った値になり、ドメイン参加した2016以降のゲストは、ホスト任せではなく最も正確なクロックを選ぶようになりました。3

一方、Windows Server 2012 R2以前のゲストをドメインで動かす場合は、Hyper-V時刻同期プロバイダーがドメインの時刻同期を乱すことがあるため、Microsoftはプロバイダーの無効化を案内しています。3

次の変更は、上記の旧世代のドメイン参加ゲストに対する対処例です。 2016以降のホストとゲストが共存できる構成まで、一律に無効化する手順ではありません。

reg add HKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\VMICTimeProvider /v Enabled /t REG_DWORD /d 0 /f
net stop w32time && net start w32time

5.2 Azure・他社ハイパーバイザーと、復元直後の注意

AzureのVMについても整理されており、要点は「ドメイン参加VM(特に仮想化DC)はTimeSyncを無効化してドメイン階層に一本化、非ドメインの単独VMは既定のままホスト同期」です。3 サードパーティのハイパーバイザー(VMwareなど)でも考え方は同じで、ドメイン参加ゲストではホスト側の時刻同期機能を切ることが推奨されています。3

「NTPとホスト同期が交互に時計を引っ張り合って、ログの時刻が行ったり来たりする」という症状は、この二重関係を疑ってください。VMの保存状態からの復元やライブマイグレーション直後は時刻が大きくずれた状態から補正が始まるため、復元直後のログの時刻は特に信用しない、という運用上の注意も添えておきます。

6. 業務システム側の設計 ── 時刻は「ずれる・戻る」前提で作る

ここまでがインフラ側の話ですが、時刻同期をどれだけ整えても、ずれはゼロにはなりません。装置連携ソフトを作る側は、時刻はずれるし、戻ることもあるという前提でログと時間測定を設計します。

6.1 UTCは「いつ起きたか」の記録に使う

第一の原則は、ログのタイムスタンプはUTCで記録することです。ローカル時刻で記録すると、タイムゾーンやサマータイム、機器ごとの設定差が突合の邪魔をします(この話は「業務アプリの日時とタイムゾーン」で詳しく扱っています)。UTCに揃えるのは時刻の表し方です。時計そのもののずれやステップ補正をなくすものではありません。

6.2 Stopwatchは「どれだけかかったか」の測定に使う

第二の原則は、「いつ起きたか」と「どれだけかかったか」でクロックを使い分けることです。次は比較用の抜粋で、前半は避けたい書き方、後半が経過時間を測る書き方です。ExecuteInspection() は自分の処理を表しています。

// 【罠】システム時計で経過時間を測る
// w32timeのステップ補正が入ると、この差は実際より長くも短くも、負にもなりうる
var start = DateTime.UtcNow;
ExecuteInspection();
var elapsed = DateTime.UtcNow - start;   // タイムアウト判定に使うと誤爆する

// 【定石】経過時間はStopwatch(単調増加クロック)で測る
long t0 = Stopwatch.GetTimestamp();
ExecuteInspection();
TimeSpan elapsed2 = Stopwatch.GetElapsedTime(t0);   // .NET 7以降。それ以前はStopwatch.StartNew()

Stopwatchは高分解能パフォーマンスカウンター(QueryPerformanceCounter相当)でティックを数える経過時間測定専用のクラスで、システム時計の補正の影響を受けません。4 一方DateTime.UtcNowはシステム時計そのもので、分解能もシステムタイマー依存(概ね0.5〜15ms)です。5 タイムアウト判定、リトライ間隔、性能計測、装置の応答時間測定──「長さ」を扱う処理は全部Stopwatch側に寄せます。

6.3 同じプロセスのログに、UTCと単調経過時間を併記する

ログには両方を併記します。壁時計(UTC)と単調クロックを対で持たせておくと、後からNTPのステップ補正をまたいだ区間でも順序と間隔を調べられます。

次は記録項目を示す例です。Stopwatch.GetElapsedTime を使うため.NET 7以降向けで、ファイルやETWへの出力処理は省略しています。ここでの経過時間の基準は _baseTimestamp の初期化時点です。プロセスをまたいで共有される基準時刻ではありません。

public sealed class OpLog
{
    private static readonly long _baseTimestamp = Stopwatch.GetTimestamp();
    private static long _seq;

    public static void Write(string message)
    {
        long seq = Interlocked.Increment(ref _seq);
        // UTC時刻(いつ起きたか)+ 起動からの単調経過ms(順序と間隔)+ 連番(同時刻内の順序)
        var line = $"{DateTime.UtcNow:yyyy-MM-dd'T'HH:mm:ss.fff'Z'}\t" +
                   $"{Stopwatch.GetElapsedTime(_baseTimestamp).TotalMilliseconds:F1}\t" +
                   $"{seq}\t{message}";
        // ... ファイル/ETWへ出力
    }
}

この例の連番はプロセス内で採番するものです。複数スレッドからの呼び出しでは、採番・UTC取得・経過時間取得・実際の出力は別の処理なので、出力順や業務イベントの発生順まで自動で保証するものではありません。連番と時刻が何を記録した値かを決めて使います。

6.4 複数マシン・装置: 時計の差を定期的に残す

複数マシン・装置のログ突合に向けては、さらに2つ足します。ひとつは、相手の時計とのオフセットを定期記録することです。カメラやPLCのように独自時計を持つ装置は、通信プロトコル経由で装置時刻を読めることが多いので、アプリ起動時と定期(例: 1時間ごと)に「PCのUTC時刻と装置時刻の差」をログに残します。これはw32tm /stripchartの装置版に相当し、障害後に「この期間、装置ログの時刻には+12.3秒の補正をかけて読む」という突合が機械的にできるようになります。

もうひとつは、イベントログ・ETW側の記録と自前ログの時刻系を揃えておくことです(「Windowsイベントログ・ETW入門」参照)。クラッシュ時の証跡設計(「クラッシュ時にログとダンプを残す設計」)や、カメラ通信断のようなネットワーク起因の障害調査(「TCP再送で産業用カメラ通信が止まる」)では、時刻系が揃っているかどうかで調査時間が桁で変わります。

6.5 オフライン工場LAN: 全機器を同じ基準に揃える

オフラインの工場LAN(インターネット非接続)では、time.windows.comには届かないので、LAN内にローカルNTPサーバーを立てて全機器をそこに揃えるのが定石です。GPS時計があれば理想ですが、なくても「絶対時刻は多少狂っていても、全機器が同じ基準に揃っている」状態にできれば、ログ突合の目的はほぼ達成できます。基準サーバーには、外部と同期できない間の自己申告精度を決めるLocalClockDispersionの調整も検討します。1

7. 環境別の判断表

最初に自分の環境の行を選び、詳細な条件は該当章で確認してください。 特にVMは、参加形態だけでなくホスト・ゲストのOS世代も見ます(第5章)。

環境 既定の同期先・頻度 起きがちな症状 推奨アクション
ドメイン参加PC/サーバー DC(NT5DS)→頂点はPDCエミュレーター2 ドメイン全体で揃って外部とずれる PDCエミュレーターに/manualpeerlistで外部の正確な時刻源を設定。メンバーは既定のまま
ワークグループPC time.windows.com、既定は週1回程度と低頻度1 数十秒のずれが常態化 社内NTPを/manualpeerlist(,0x9=Client+SpecialInterval)で指定し、SpecialPollIntervalを短縮(例: 3,600秒)。コマンド手順は第3章「ワークグループPCのポーリング間隔を短くする」
Hyper-V/Azure VM(ドメイン参加) ホスト(VMIC)とNTPの2系統7 二重補正で時刻が揺れる、復元直後に大ずれ 2016以降同士なら既定で共存可。2012 R2以前のゲストはVMICTimeProviderを無効化3
Hyper-V/Azure VM(単独) 同上 ほぼ問題なし 既定のままホスト同期を利用3
オフライン工場LAN 同期先なし(各機の内蔵時計任せ) 全機器がバラバラにドリフト ローカルNTPサーバーを基準に全機器(PC・装置)を揃える。装置時計とのオフセットを定期記録
ms級の前後関係が必要 ── 時刻同期精度では足りない Windows Server 2016以降+高精度構成の条件確認6。可能なら片側マシンのStopwatchで測る設計へ

8. まとめ

  • Windowsの時刻はw32timeが管理し、ドメインではPDCエミュレーターを頂点とする階層同期、ワークグループでは既定でtime.windows.comとの低頻度同期です。数十秒のずれは故障ではなく既定値の帰結です。
  • 調査は w32tm /query /status で同期元と最終同期時刻を確認し、w32tm /stripchart で相手との差を実測するところから。設定変更が必要なら、対象機とポリシーを確認して /config /manualpeerlist と /resync を使い、変更後の状態も確かめます。
  • w32timeは小さなずれをスルー、大きなずれをステップで補正します。システム時計は後ろにも跳ぶこと、上限超過時は補正されないことを押さえてください。
  • 既定設定の精度目標は歴史的に「Kerberosの5分」を満たす程度です。1ms級はWindows Server 2016以降で、正確な時刻源・遅延・ホップ数・CPU負荷の条件を満たした場合のサポート範囲です。
  • 仮想マシンはホスト同期とNTPの2系統を持ちます。ドメイン参加ゲストではドメイン階層を基本にしつつ、Hyper-Vの2016以降同士で共存できる構成と、2012 R2以前のゲストでVMICTimeProviderを無効化する対処を分けます。Azure・他社ハイパーバイザー・単独VMの扱いは第5章の条件に従います。
  • アプリ側は、タイムスタンプはUTC、経過時間はStopwatchと使い分け、装置の独自時計とのオフセットを定期記録しておく。この3点で「どちらが先か分からない」障害調査から抜け出せます。

関連記事

関連する相談領域

合同会社小村ソフトでは、「装置とPCでログの時刻が合わず障害の前後関係が特定できない」といった調査のご相談、工場LAN・装置連携環境での時刻同期設計、タイムアウトや時間測定まわりの不具合を含む装置連携ソフトの開発・改善を扱っています。

参考リンク

  1. Microsoft Learn, Windows Time service tools and settings. w32tmコマンドの各オプション(/query /status・/source・/peers・/configuration、/stripchart、/resync、/config /manualpeerlist /syncfromflags)、NtpServerフラグ(0x1 SpecialInterval・0x2 UseAsFallbackOnly・0x8 Client)と2台構成時の0x2推奨、スタンドアロン既定値がtime.windows.com,0x1でSpecialPollInterval既定604,800秒であること、MaxAllowedPhaseOffsetによるスルー/ステップの切り替え、MaxPos/MaxNegPhaseCorrection(スタンドアロン既定54,000秒)超過時はイベント記録のみになること、LocalClockDispersionについて。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13

  2. Microsoft Learn, How the Windows Time Service Works. w32timeがNTP仕様のアルゴリズム群を用いるWindows標準の時刻同期サービスであること、AD DSフォレストの時刻階層(メンバー→DC→親ドメインDC→フォレストルートのPDCエミュレーター)、非ドメイン機が既定でtime.windows.comと同期すること、Kerberosセッションキーによる時刻の認証、手動指定の時刻源が認証されないこと、スルー/ステップによるクロック規律、UDP 123番ポートの使用について。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

  3. Microsoft Learn, Time accuracy improvements for Windows Server 2016. Hyper-V TimeSyncサービスの改善(VM起動/復元時の初期時刻、割り込み遅延補正、ホスト+1のStratum報告、ドメイン参加2016ゲストが最適クロックを選ぶこと)、2012 R2以前のドメイン参加ゲストでのHyper-V時刻プロバイダー無効化の推奨とVMICTimeProviderレジストリ設定、AzureのVM(ドメイン参加はTimeSync無効化・単独VMはホスト同期継続)の指針、既定のポーリング/クロック更新頻度の版別比較(2012 R2世代のスタンドアロンは週1回、2016は毎秒のクロック更新)について。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9

  4. Microsoft Learn, Stopwatch Class (System.Diagnostics). Stopwatchが経過時間を正確に測定するためのクラスであり、ハードウェアとOSが対応していれば高分解能パフォーマンスカウンターでティックを数えること、Frequency/GetTimestampがQueryPerformanceFrequency/QueryPerformanceCounterの代わりに使えること、GetTimestampとGetElapsedTimeによる測定について。 ↩ ↩2

  5. Microsoft Learn, DateTime.UtcNow Property. DateTime.UtcNowがコンピューターの現在日時(UTC)すなわちシステム時計を返すこと、その分解能がシステムタイマー依存でおおむね0.5〜15msであることについて。 ↩ ↩2

  6. Microsoft Learn, Support boundary for high accuracy time. Windows 10 1607 / Windows Server 2016より前のw32timeはKerberos v5の要件を満たす精度が設計目標で高精度はサポート外だったこと、2016以降は条件を満たせば1秒/50ms/1ms精度がサポートされること、および1ms精度の条件(Stratum 1時刻源、ネットワーク遅延0.1ms未満、Stratum 5以内・4ホップ以内、CPU使用率80%以下など)について。 ↩ ↩2 ↩3 ↩4

  7. Microsoft Learn, Accurate Time for Windows Server 2016. Hyper-VゲストがホストのVMICプロバイダーとNTPの複数プロバイダーからStratum等を基準に最良の時刻源を選ぶこと、スタンドアロン機の既定がtime.windows.comであること、リモート時刻源では1ms精度に依存できないこと、w32timeがStratum 15以下のみ受け入れること、正確な時刻の3要件(安定した時刻源・安定したクライアントクロック・対称なNTP通信)について。 ↩ ↩2 ↩3 ↩4

  8. Microsoft Learn, Time synchronization may not succeed. 送信モードがNtpServerプロバイダーの設定にも依存すること、対称アクティブモードに応答しないNTPサーバーとの同期では0x8でクライアントモードを明示すること、0x1がSpecialIntervalを指定するフラグであることについて。 ↩

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

PCのログと装置のログで時刻がずれています。まず何を確認すべきですか?
最初にPC側で w32tm /query /status を実行し、「ソース」(どこと同期しているか)と「最終正常同期時刻」を確認します。ソースがLocal CMOS Clockになっていたり、最終同期が何日も前なら、そのPCは実質どことも同期していません。次に w32tm /stripchart /computer:相手 /dataonly で相手(サーバーや装置のNTPポート)との時刻差を実測し、どちらがどれだけずれているかを数値で押さえます。装置側が独自時計の場合は、装置の時刻設定画面や通信で時刻を読み出してPC時刻との差を記録しておくと、過去ログの突合にも使えます。
ワークグループ環境のWindowsはどのくらいの頻度で時刻同期していますか?
ドメインに参加していないWindowsは既定でtime.windows.comと同期しますが、頻度はかなり低く設定されています。レジストリ既定のSpecialPollIntervalはスタンドアロン構成で604,800秒(1週間)で、Windows 10クライアントでも1日1回程度です。PCの内蔵時計は日単位で秒〜数十秒ずれることが珍しくないため、この頻度では業務ログの突合に耐える精度は期待できません。ログの時刻精度が必要な現場では、w32tm /config /manualpeerlistで社内のNTPサーバーを指定し、SpecialPollIntervalを短くするのが定石です。
Hyper-V上の仮想マシンの時刻はホストとNTPのどちらに合わせるべきですか?
Hyper-VのゲストにはHyper-V時刻同期統合サービス(VMICTimeSync)とNTPクライアントの2つの時刻プロバイダーがあり、Windowsが階層(Stratum)などを基準に良い方を選びます。ドメイン参加ゲストの原則はドメイン階層(DC)との同期で、Windows Server 2016以降のホスト/ゲストの組み合わせなら両者は共存できるよう改善されています。Windows Server 2012 R2以前のゲストをドメインで使う場合は、VMICTimeProviderを無効化してドメイン同期に一本化することがMicrosoftから案内されています。ワークグループの単独VMであれば、既定のままホスト同期を使うのが簡単で確実です。
ドメイン環境で時刻が大きくずれると何が起きますか?
Active Directoryの認証に使われるKerberosは、既定でクライアントとサーバーの間に5分以内の時刻一致を要求します。これを超えてずれると認証が失敗し、共有フォルダーへのアクセスやグループポリシー適用などドメインの基本機能が動かなくなります。ドメイン参加PCは既定でDC、最終的にはフォレストルートのPDCエミュレーターを頂点とする階層で同期するため、通常ここまでずれることはありません。逆に言うと、PDCエミュレーター自体が外部の正確な時刻源と同期していないと、ドメイン全体が「揃って間違った時刻」になるので、頂点の設定確認が重要です。
経過時間の測定にDateTime.UtcNowを使ってはいけないのはなぜですか?
DateTime.UtcNowはシステム時計を読むため、w32timeの補正の影響をそのまま受けるからです。時刻差が大きいとw32timeは徐々に補正(スルー)ではなく時計の直接設定(ステップ)を行い、このとき時刻は先にも後ろにも跳びます。つまりUtcNowの引き算で測った経過時間は、実際より長くなる・短くなる・負になる、のいずれも起こりえます。経過時間やタイムアウトの測定には、システム時計と独立に単調増加するStopwatch(またはStopwatch.GetTimestamp)を使い、UtcNowは「いつ起きたか」の記録専用と割り切るのが安全です。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る