更新履歴(3件・最終更新 2026年08月02日)
この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。
- 記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
- 外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
- ワークグループPCのポーリング間隔を短くする節を新設しました(レジストリ設定だけでは効かず、`0x9`での`/manualpeerlist`指定が要る理由を含みます)。ドメインの時刻階層の図、NtpServerフラグの表(`0x1`単独が誤りである理由)、`w32tm /query /status`の項目名の日本語と英語の対応表を追加しました。
- 初版公開
この記事を引用する(DOI: 10.5281/zenodo.21547425)
この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。
小村 豪(2026)「Windowsの時刻同期(w32time)と業務システム ── 「ログのタイムスタンプが合わない」を仕組みから解決する」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21547425 https://staging.comcomponent.com/blog/windows-time-sync-w32time-guide/
- DOI(最新版)
- 10.5281/zenodo.21547425
- DOI(この版)
- 10.5281/zenodo.21733136
「装置が異常停止した。装置側のログとPC側のアプリログを突き合わせたら、時刻が40秒ずれていて、装置のエラーとアプリの通信断のどちらが先だったのか確定できない」── 装置連携システムの障害調査で、私たちが何度も出会ってきた場面です。ネットワークカメラ、PLC、検査装置、そしてWindows PC。それぞれが自分の時計でログを刻んでおり、その時計たちが合っている保証は、実は誰も取っていなかった、という話です。
時刻のずれは平常時にはほとんど誰も気づきません。困るのは決まって障害調査のとき、つまり「イベントの前後関係」が証拠として必要になったときです。そして調べ始めると、「ワークグループのPCは週1回しか同期していなかった」「仮想マシンがホストとNTPの両方から時刻をもらって揺れていた」「そもそも装置の時計は誰も合わせていなかった」といった事実が次々に出てきます。
この記事では、装置とPC、サーバーと端末のログ突合に苦労した経験のある開発者・情シス担当者を対象に、Windowsの時刻同期サービス(w32time)の仕組み、w32tmコマンドによる診断の実務、精度の現実的な期待値、そして「時刻はずれる・戻る」前提での業務システム側の設計までを、Microsoftの一次情報の裏付けつきで整理します。
1. まず結論
- Windowsの時刻はWindows Timeサービス(w32time)が管理します。NTPの厳密な実装ではありませんが、NTP仕様のアルゴリズム群を使ってクロックを調整するNTPクライアント/サーバーで、通信はUDP 123番ポートです。1
- ドメイン環境には決まった時刻階層があります。メンバーはDCと、DCは親ドメインのDCと同期し、頂点はフォレストルートドメインのPDCエミュレーターです。頂点が外部の正確な時刻源と同期していなければ、ドメイン全体が揃って間違います。1
- ワークグループ(非ドメイン)機は既定でtime.windows.comと低頻度同期です。レジストリ既定のSpecialPollIntervalはスタンドアロン構成で604,800秒(1週間)。数十秒のずれは「仕様どおり」に起こります。23
- 診断はw32tmコマンド一式で足ります。
w32tm /query /statusで同期状態と同期元、/stripchartで相手との時刻差の実測、/config /manualpeerlistで同期先の指定、/resyncで即時再同期です。2 - w32timeは、小さなずれはクロックの進む速度を上げ下げして徐々に合わせ(スルー、slew)、大きなずれは時計を直接書き換えて合わせます(ステップ、step)。つまりシステム時計は前にも後ろにも跳ぶことがあります。ずれが上限(MaxPos/MaxNegPhaseCorrection)を超えると補正されずイベントログに記録されるだけ、という動きも重要です。12
- 既定設定の精度は「Kerberosの5分制約を満たす」程度が設計目標でした。Windows Server 2016 / Windows 10 1607以降は大幅に改善され、正確なStratum 1時刻源・ネットワーク遅延・ホップ数などの条件を満たせば1秒/50ms/1msの精度がサポート対象になりました。4
- Hyper-VゲストにはホストとNTPの2つの時刻プロバイダーがあります。Windows Server 2016以降はゲストが最適な方を選ぶよう改善されましたが、2012 R2以前のドメイン参加ゲストではHyper-V時刻同期プロバイダーの無効化が推奨です。3
- アプリ側は「時刻はずれる・戻る」前提で設計します。ログの時刻はUTCで記録し、経過時間の測定はシステム時計と独立に単調増加するStopwatchで行う。この使い分けが土台です。56
この記事の知識マップ
装置とPCのログでタイムスタンプがずれる原因は、Windowsの時刻同期サービスw32timeの既定動作にあります。ドメイン環境ではドメインコントローラーを経てフォレストルートのPDCエミュレーターへ至る時刻階層に従いKerberosの5分要件を満たす一方、ワークグループ機はSpecialPollIntervalの既定604,800秒という低頻度でtime.windows.comとしか同期せず、数十秒のずれが常態化します。w32timeは小さなずれをスルー、大きなずれをステップで補正するため、システム時計は前にも後ろにも跳びうるので、経過時間の測定はDateTime.UtcNowではなくStopwatchで行い、ログのタイムスタンプはUTCで記録し、装置との時刻オフセットは定期的に記録しておくことが実務上の設計原則になります。
flowchart LR
accTitle: Windowsの時刻同期(w32time)の知識マップ
accDescr: ドメインの時刻階層とワークグループの低頻度同期という既定動作の違い、w32tmによる診断とmanualpeerlistでの同期先指定、Hyper-Vの二重の時刻プロバイダー、Kerberosの時刻要件、StopwatchとDateTime.UtcNowを使い分けるアプリ側設計の関係を示す図
w32time["Windows Timeサービス(w32time)"]
w32tm["w32tmコマンド"]
ntp["NTP(Network Time Protocol)"]
domain_controller["ドメインコントローラー"]
pdc_emulator["PDCエミュレーター"]
workgroup["ワークグループ構成"]
special_poll_interval["SpecialPollIntervalレジストリ値"]
manualpeerlist_config["/manualpeerlistによる同期先の手動指定"]
group_policy["グループポリシー"]
kerberos["Kerberos"]
kerberos_time_sync["Kerberosの時刻同期要件"]
clock_discipline["クロック規律(スルー/ステップ補正)"]
datetime_utcnow["DateTime.UtcNowプロパティ(.NET)"]
elapsed_time_measurement["経過時間・タイムアウト判定"]
stopwatch_class["Stopwatchクラス(.NET)"]
hyper_v_time_sync["Hyper-V時刻同期統合サービス(VMICTimeSync)"]
ntp_stratum["階層(Stratum)"]
high_accuracy_time_boundary["高精度時刻のサポート境界"]
device_clock_offset_logging["装置とPCの時刻オフセット定期記録"]
log_timestamp_utc["ログタイムスタンプのUTC記録"]
elapsed_time_error["経過時間・タイムアウト判定の誤り"]
w32time -->|"利用する"| ntp
w32time -->|"で構成できる"| w32tm
w32time -->|"で確認できる"| w32tm
domain_controller -.->|"前提とする"| pdc_emulator
w32time -.->|"前提とする"| domain_controller
workgroup -->|"利用する"| w32time
w32time -.->|"利用する"| special_poll_interval
special_poll_interval -.->|"前提とする"| manualpeerlist_config
manualpeerlist_config -->|"で構成できる"| group_policy
w32time -.->|"利用する"| kerberos
kerberos -->|"前提とする"| kerberos_time_sync
w32time -->|"実装を担う"| clock_discipline
datetime_utcnow -->|"用いるのは非推奨"| elapsed_time_measurement
stopwatch_class -->|"推奨される対応"| elapsed_time_measurement
hyper_v_time_sync -.->|"両立しない"| w32time
w32time -->|"利用する"| ntp_stratum
high_accuracy_time_boundary -->|"前提とする"| ntp_stratum
device_clock_offset_logging -->|"利用する"| w32tm
log_timestamp_utc -->|"推奨される対応"| clock_discipline
manualpeerlist_config -->|"推奨される対応"| pdc_emulator
manualpeerlist_config -.->|"用いるのは非推奨"| domain_controller
clock_discipline -->|"原因になり得る"| elapsed_time_error
stopwatch_class -->|"防止する"| elapsed_time_error
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全23件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2. w32timeの仕組み ── ドメインとワークグループで動きがまったく違う
Windows Timeサービス(W32Time)は、Windows標準の時刻同期コンポーネントです。NTP(およびドメイン用のセキュアなMS-SNTP)でネットワーク上の時刻源から時刻サンプルを取得し、NTPのクロックフィルター/クロック選択アルゴリズムで最良のサンプルを選び、ローカル時計を調整します。1
押さえておきたいのは、構成によって同期先の決まり方が根本的に違うことです。
ドメイン環境(Type=NT5DS)では、AD DSフォレストにあらかじめ決められた時刻階層があります。メンバーPC/サーバーは自ドメインのDCと同期し、DCは親ドメインのDCと同期し、階層の頂点はフォレストルートドメインのPDCエミュレーター(または信頼できる時刻源として構成されたDC)です。NTPパケットはKerberosセッションキーで署名され、認証された時刻だけが受け入れられます。1 このため、ドメイン内のPC同士は普通そこそこ揃います。問題は頂点で、PDCエミュレーターが外部の正確な時刻源(GPS時計や信頼できるNTPサーバー)と同期していないと、「全員で揃って間違った時刻」になります。ログを社外のシステムやクラウド側の記録と突き合わせた瞬間に、このずれが露呈します。
flowchart TD
EXT["外部の正確な時刻源<br/>GPS時計 / 信頼できるNTPサーバー"]
PDC["フォレストルートドメインの<br/>PDCエミュレーター"]
CDC1["子ドメインのDC"]
CDC2["同じドメインの他のDC"]
M1["メンバーサーバー / PC"]
M2["メンバーサーバー / PC"]
M3["メンバーサーバー / PC"]
EXT -->|"ここを設定するのは管理者"| PDC
PDC --> CDC1
PDC --> CDC2
CDC1 --> M1
CDC1 --> M2
CDC2 --> M3
図1: ドメインの時刻階層 ── 矢印は時刻が配られる向き
この木を1枚の絵で見ると、根が間違えば全員が同じだけ間違うことがはっきりします。しかも全員が揃って間違うので、社内のログだけを見比べているかぎり誰も気づきません。外部と突き合わせた日に、初めて発覚します。頂点の設定を最初に確認すべき理由はここにあります。
ワークグループ環境(Type=NTP)では、既定の同期先は time.windows.com,0x1 です。0x1(SpecialInterval)はポーリング間隔をSpecialPollIntervalレジストリ値で決めるフラグで、その既定値はスタンドアロン構成で604,800秒=1週間です。2 Windows 10クライアントでも1日1回程度で、Windows Server 2012 R2世代の既定は週1回でした。3 PCの内蔵時計(水晶発振器)は温度などの環境で日に秒単位でドリフトすることが珍しくないため、週1回の同期では数十秒のずれは普通に起こります。冒頭の「40秒ずれ」の正体は、たいていこれです。
もうひとつ実務で重要なのがクロック規律(clock discipline)の動きです。w32timeはずれが小さいうちはクロックの進む速度を上げ下げして徐々に合わせ(スルー)、ずれがMaxAllowedPhaseOffsetを超えると時計を直接設定します(ステップ)。12 さらに、ずれがMaxPosPhaseCorrection/MaxNegPhaseCorrection(スタンドアロン既定54,000秒=15時間)を超えると、補正せずイベントを記録するだけになります。2 「同期しているはずなのに直らない」ときは、この上限に引っかかっているケースがあります。そして、ステップ補正は負方向にもかかる、つまりWindowsのシステム時計は後ろに跳ぶことがある── これが後半のアプリ設計の話につながります。
3. w32tmコマンド実務 ── 現状確認、差の実測、同期先の変更
時刻まわりの調査で使うコマンドは実質5つです。いずれも管理者権限のコマンドプロンプトで実行します。2
まず現状確認です。
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点です。「ソース」が意図した相手か(Local CMOS Clock や Free-running System Clock なら実質未同期)、「最終正常同期時刻」が最近か(何日も前なら同期は機能していない)、「階層」(Stratum)が妥当か(正確な時刻源から何段目か。w32timeはStratum 15以下しか受け入れません)。7 同期元だけ知りたいときは 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 |
次に、相手との時刻差の実測です。障害調査で「サーバーとこのPC、今どれだけずれているか」を数値にするのに使います。
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にも安心して使えます。ログ突合の前に関係マシン全部に対して実行し、オフセット一覧表を作ってから突合を始めるのが、当社が障害調査で最初にやることです。
同期先を明示するには /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の案内です)。2 手動指定をやめてドメイン階層に戻すときは w32tm /config /syncfromflags:domhier /update してサービスを再起動します。w32tm /resync は蓄積された誤差統計を破棄して即時再同期させるコマンドで、設定変更後の反映確認に使います。2
サーバー名のうしろに付ける数値がNtpServerフラグです。散らばると誤用しやすいので、1つの表にまとめます。2
| フラグ | 名前 | 意味 |
|---|---|---|
0x1 |
SpecialInterval | ポーリング間隔を SpecialPollInterval レジストリ値で決める |
0x2 |
UseAsFallbackOnly | ほかの時刻源が使えないときの予備として扱う |
0x8 |
Client | クライアントモードでこの相手と同期する |
0x9 |
Client + SpecialInterval | 0x8 と 0x1 の組み合わせ。間隔を自分で決めたいときの定番 |
0x1 を単独で指定しないでください。クライアントモードのフラグが立たないため、間隔だけ指定して同期しない構成になります。間隔を指定したいなら 0x9 です。
ワークグループPCのポーリング間隔を短くする
第7章の判断表で挙げている「SpecialPollIntervalの短縮」は、レジストリ値の変更とサービス再起動で行います。既定の604,800秒(1週間)を3,600秒(1時間)にする場合の手順は次のとおりです。2
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)を省くと、レジストリだけ変えても間隔は変わりません。SpecialPollInterval は、0x1 フラグの付いた時刻源に対してしか使われないためです。また、グループポリシーで時刻設定を配っている環境では、ローカルのレジストリ変更は次のポリシー適用で上書きされます。w32tm /query /configuration の出力で各値の出所を確認し、ポリシー管理下なら「コンピューターの構成」>「管理用テンプレート」>「システム」>「Windows Time Service」>「Time Providers」>「Windows NTP クライアントを構成する」で設定してください。
なお、/manualpeerlist での外部NTP指定はドメインの認証された時刻とは別物で、認証されないため、ドメインメンバーには原則使わず、頂点(PDCエミュレーター)や非ドメイン機に対して使うものです。1
4. 精度の話 ── 既定でどこまで合うのか、1msの条件
「WindowsのNTP同期って、結局どのくらい合うんですか」という質問には、時代で答えが分かれます。
Windows Server 2012 R2 / Windows 8.1以前のw32timeは、Kerberos認証の要件(既定5分)を満たす精度と、同一フォレスト内での「おおむね正確な時刻」を提供するのが設計目標で、それより厳しい精度要件は設計仕様の範囲外・サポート対象外と明言されています。4 つまり「秒単位で合っていれば設計どおり」の世界です。
Windows Server 2016 / Windows 10 1607以降はアルゴリズムが改善され、クロック更新頻度も既定で大幅に引き上げられました(例: サーバーはクロック調整が1時間に1回から毎秒に)。3 その結果、条件を満たせば1秒・50ms・1msの精度がサポート境界として定義されています。1msの主な条件は次のとおりで、逆に言えばこれが揃わない環境で1msを期待してはいけません。4
- 正確で安定したStratum 1時刻源(GPS時計など)を頂点とするNTP階層で、経路上のWindowsがすべて高精度構成であること
- 時刻源との間のネットワーク遅延が0.1ms未満、時刻源からStratum 5以内・4ホップ以内
- 各階層のCPU使用率(1日平均)が80%以下(仮想化環境ではホストも)
また、time.windows.comのようなインターネット上のリモート時刻源では、経路の非対称性や混雑の影響を受けるため1ms精度は期待できないとされています。7 実務の相場観としては、「既定のワークグループ=秒〜数十秒ずれうる」「まともに構成した社内NTP同期=数十ms〜1秒以内」「専用の時刻源と設計をしたとき=ms級」の3段階で考えるのが安全です。装置連携でms単位の前後関係が必要なら、時刻同期に頼るのではなく、後述のとおり片側のクロックで測る設計に寄せるべきです。
5. 仮想マシンの時刻 ── Hyper-V時刻同期統合サービスとNTPの二重関係
仮想マシンの時刻は物理機よりこじれやすい領域です。理由は単純で、時刻をくれる相手が2系統あるからです。Hyper-VゲストのWindowsには、ホストから時刻をもらうHyper-V時刻同期統合サービス(VMICTimeSyncプロバイダー)と、通常のNTPクライアントの両方があり、Windowsは階層(Stratum)、ルート遅延、ルート分散、オフセットの順で「良い方」を選びます。7
Windows Server 2016でこの仕組みは大きく改善されました。VM起動・復元時の初期時刻が正確になり、割り込み遅延を補正したサンプルがw32timeに渡されるようになって、ホストに対して10µs程度の精度を保てます。ホストがゲストに報告するStratumも「ホストのStratum+1」という実態に沿った値になり、ドメイン参加した2016以降のゲストは、ホスト任せではなく最も正確なクロックを選ぶようになりました。3
一方、Windows Server 2012 R2以前のゲストをドメインで動かす場合は、Hyper-V時刻同期プロバイダーがドメインの時刻同期を乱すことがあるため、Microsoftはプロバイダーの無効化を案内しています。3
reg add HKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\VMICTimeProvider /v Enabled /t REG_DWORD /d 0 /f
net stop w32time && net start w32time
AzureのVMについても整理されており、要点は「ドメイン参加VM(特に仮想化DC)はTimeSyncを無効化してドメイン階層に一本化、非ドメインの単独VMは既定のままホスト同期」です。3 サードパーティのハイパーバイザー(VMwareなど)でも考え方は同じで、ドメイン参加ゲストではホスト側の時刻同期機能を切ることが推奨されています。3 「NTPとホスト同期が交互に時計を引っ張り合って、ログの時刻が行ったり来たりする」という症状は、この二重関係を疑ってください。VMの保存状態からの復元やライブマイグレーション直後は時刻が大きくずれた状態から補正が始まるため、復元直後のログの時刻は特に信用しない、という運用上の注意も添えておきます。
6. 業務システム側の設計 ── 時刻は「ずれる・戻る」前提で作る
ここまでがインフラ側の話ですが、時刻同期をどれだけ整えても、ずれはゼロにはなりません。装置連携ソフトを作る側は、時刻はずれるし、戻ることもあるという前提でログと時間測定を設計します。
第一の原則は、ログのタイムスタンプはUTCで記録することです。ローカル時刻で記録すると、タイムゾーンやサマータイム、機器ごとの設定差が突合の邪魔をします(この話は「業務アプリの日時とタイムゾーン」で詳しく扱っています)。第二の原則は、「いつ起きたか」と「どれだけかかったか」でクロックを使い分けることです。
// 【罠】システム時計で経過時間を測る
// 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相当)でティックを数える経過時間測定専用のクラスで、システム時計の補正の影響を受けません。5 一方DateTime.UtcNowはシステム時計そのもので、分解能もシステムタイマー依存(概ね0.5〜15ms)です。6 タイムアウト判定、リトライ間隔、性能計測、装置の応答時間測定──「長さ」を扱う処理は全部Stopwatch側に寄せます。
ログには両方を併記します。壁時計(UTC)と単調クロックを対で持たせておくと、後からNTPのステップ補正をまたいだ区間でも順序と間隔を復元できます。
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へ出力
}
}
複数マシン・装置のログ突合に向けては、さらに2つ足します。ひとつは、相手の時計とのオフセットを定期記録することです。カメラやPLCのように独自時計を持つ装置は、通信プロトコル経由で装置時刻を読めることが多いので、アプリ起動時と定期(例: 1時間ごと)に「PCのUTC時刻と装置時刻の差」をログに残します。これはw32tm /stripchartの装置版に相当し、障害後に「この期間、装置ログの時刻には+12.3秒の補正をかけて読む」という突合が機械的にできるようになります。もうひとつは、イベントログ・ETW側の記録と自前ログの時刻系を揃えておくことです(「Windowsイベントログ・ETW入門」参照)。クラッシュ時の証跡設計(「クラッシュ時にログとダンプを残す設計」)や、カメラ通信断のようなネットワーク起因の障害調査(「TCP再送で産業用カメラ通信が止まる」)では、時刻系が揃っているかどうかで調査時間が桁で変わります。
オフラインの工場LAN(インターネット非接続)では、time.windows.comには届かないので、LAN内にローカルNTPサーバーを立てて全機器をそこに揃えるのが定石です。GPS時計があれば理想ですが、なくても「絶対時刻は多少狂っていても、全機器が同じ基準に揃っている」状態にできれば、ログ突合の目的はほぼ達成できます。基準サーバーには、外部と同期できない間の自己申告精度を決めるLocalClockDispersionの調整も検討します。2
7. 環境別の判断表
| 環境 | 既定の同期先・頻度 | 起きがちな症状 | 推奨アクション |
|---|---|---|---|
| ドメイン参加PC/サーバー | DC(NT5DS)→頂点はPDCエミュレーター1 | ドメイン全体で揃って外部とずれる | PDCエミュレーターに/manualpeerlistで外部の正確な時刻源を設定。メンバーは既定のまま |
| ワークグループPC | time.windows.com、既定は週1回程度と低頻度2 | 数十秒のずれが常態化 | 社内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以降+高精度構成の条件確認4。可能なら片側マシンの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系統を持ちます。ドメイン参加VMはドメイン同期に一本化(旧OSゲストはVMICTimeProvider無効化)、単独VMはホスト同期のままが原則です。
- アプリ側は、タイムスタンプはUTC、経過時間はStopwatchと使い分け、装置の独自時計とのオフセットを定期記録しておく。この3点で「どちらが先か分からない」障害調査から抜け出せます。
関連記事
- 業務アプリの日時とタイムゾーン ── DateTimeの罠からUTC保存の原則、テスト設計まで
- Windowsアプリのクラッシュ時にログとダンプを残す設計
- Windowsイベントログ・ETW入門
- TCP再送で産業用カメラ通信が止まる原因と切り分け
- タスクスケジューラの安全な運用設計
- 業務アプリの和暦・祝日・締め日処理
関連する相談領域
合同会社小村ソフトでは、「装置とPCでログの時刻が合わず障害の前後関係が特定できない」といった調査のご相談、工場LAN・装置連携環境での時刻同期設計、タイムアウトや時間測定まわりの不具合を含む装置連携ソフトの開発・改善を扱っています。
参考リンク
-
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 ↩8
-
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
-
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 ↩10
-
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
-
Microsoft Learn, Stopwatch Class (System.Diagnostics). Stopwatchが経過時間を正確に測定するためのクラスであり、ハードウェアとOSが対応していれば高分解能パフォーマンスカウンターでティックを数えること、Frequency/GetTimestampがQueryPerformanceFrequency/QueryPerformanceCounterの代わりに使えること、GetTimestampとGetElapsedTimeによる測定について。 ↩ ↩2
-
Microsoft Learn, DateTime.UtcNow Property. DateTime.UtcNowがコンピューターの現在日時(UTC)すなわちシステム時計を返すこと、その分解能がシステムタイマー依存でおおむね0.5〜15msであることについて。 ↩ ↩2
-
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
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
グループポリシー(GPO)実務入門 ── 仕組み・反映確認・Intuneとの使い分け
「GPOで配布」の意味が分からないままAD環境を触っていませんか。グループポリシーの仕組みとLSDOUの適用順序、gpupdate・gpresultでの反映確認、Intuneとの使い分け、客先GPOがアプリの動作を変える落とし穴まで実務目線で解説します。
Windows LAPS実務ガイド ── 全PC共通のローカル管理者パスワードをやめる
全PC共通のローカル管理者パスワードは、1台の侵害が全台に波及するPass-the-Hash攻撃の温床です。OS標準機能になったWindows LAPSによる自動ローテーションと、AD/Entra IDへの保存設定、運用の落とし穴を解説します。
SMB署名とLDAPチャネルバインディング ── NTLM対策の「残り半分」を実務で締める
NTLMを止めるまでの間、リレー攻撃の被害を抑える防御がSMB署名とLDAP署名・チャネルバインディングです。OSごとの既定値、監査イベントの読み方、強制へ進める手順、業務アプリと機器の直し方までを実務目線で整理します。
図解でわかるNTLMとKerberos ── なぜ認証はNTLMに「落ちる」のか
NTLMとKerberosの違いを図解で整理します。チャレンジ/レスポンス、TGTとサービスチケット、SPNが引けないときにNegotiateがNTLMへ落ちる条件、リレー攻撃とPass-the-Hashが成立する理由、NTLMv1の削除までを公式ドキュメントの裏付けつきで...
NTLM廃止で業務アプリは止まるか ── 監査ログの取り方と、依存を潰す順番
NTLM廃止に向けて、自社のWindows環境と業務アプリがどこでNTLMに依存しているかを洗い出す手順をまとめます。監査ポリシー、NTLM/Operationalログのイベント8001〜8004の追い方、NTLMに落ちる典型パターンと直し方、SMBのNTLMブロックまでを...
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- 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は「いつ起きたか」の記録専用と割り切るのが安全です。