Skip to content

Instantly share code, notes, and snippets.

@cho45
Created June 22, 2025 02:19
Show Gist options
  • Save cho45/a20e8713bb57173a2617dd3bb5c4c7c7 to your computer and use it in GitHub Desktop.
Save cho45/a20e8713bb57173a2617dd3bb5c4c7c7 to your computer and use it in GitHub Desktop.
システム時刻の調整が入ったことを検出する
// ClockMonitor: システム時計の大幅な変更(NTP補正・手動変更等)を検知し、イベントを発行するクラス
// WebAudioやperformance.now()はmonotonicな経過時間だが、絶対時刻(Date.now())はシステム時計依存でジャンプすることがある
// そのため、performance.timeOrigin+performance.now()で絶対時刻を計算している場合、
// システム時計が変化しても自動で補正されない(ズレたままになる)
// このクラスは、定期的にDate.now()とperformance.timeOrigin+performance.now()の差分を監視し、
// 一定以上の差分が発生した場合に"clockchange"イベントを発行することで、
// 利用側がoffset等を補正できるようにする
class ClockMonitor extends EventTarget {
constructor({ threshold = 2000, interval = 1000 } = {}) {
super();
this.threshold = threshold; // 何ms以上の差分で検知するか
this.interval = interval; // 監視間隔(ms)
this.offset = performance.timeOrigin || 0; // performance.now()の起点(初期化時の絶対時刻)
this._timer = null;
}
start() {
if (this._timer) return;
this._timer = setInterval(() => {
const perfNow = performance.now();
const now = Date.now();
// 現在の絶対時刻の期待値(初期offset+経過時間)
const expected = this.offset + perfNow;
const diff = now - expected;
// threshold以上の差分が出たらシステム時計変更とみなす
if (Math.abs(diff) > this.threshold) {
// offsetを補正し、イベント発行
this.offset += diff;
this.dispatchEvent(new CustomEvent("clockchange", {
detail: { offset: this.offset, diff }
}));
}
}, this.interval);
}
stop() {
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment