Skip to content

TheHuman00/precise-time-ntp

precise-time-ntp

OpenSSF Baseline OpenSSF Best Practices

Sync your Node.js app with NTP servers and get the real time.

Your system clock drifts. Servers disagree. Date.now() lies. This library fixes that with a proper 4-timestamp NTP implementation that compensates for network latency, validates server consistency, and corrects drift gradually without breaking your running timers.


Install

npm install precise-time-ntp

Quick start

const timeSync = require('precise-time-ntp');

await timeSync.sync();

timeSync.now()        // Date object — precise NTP time
timeSync.timestamp()  // "2026-04-25T15:30:45.123Z"
timeSync.offset()     // how far off your system clock is, in ms

Configuration

See the 📖 Documentation

All options can be set at construction time or overridden per sync() call.

const { TimeSync } = require('precise-time-ntp');

const t = new TimeSync({
    // NTP servers to query (up to 3 are used for coherence validation)
    servers: ['time.cloudflare.com', 'time.google.com', 'pool.ntp.org'],

    timeout: 5000,             // ms before a server is considered unreachable
    coherenceValidation: true, // compare servers and use median offset

    // Auto-sync on startup
    autoSync: true,
    autoSyncInterval: 300000,  // re-sync every 5 minutes

    // Smooth correction (see section below)
    smoothCorrection: true,
    maxCorrectionJump: 1000,  // ms — apply instantly if diff is under this
    correctionRate: 0.1,      // fraction per sync cycle (0.1 = 10%)
    maxOffsetThreshold: 5000, // ms — always apply instantly if diff exceeds this

    locale: 'fr-FR',           // used by format() — defaults to system locale
});

Or pass options directly to sync() for a one-off override:

await timeSync.sync({
    servers: ['time.cloudflare.com'],
    timeout: 3000,
    coherenceValidation: false,
});

The default global instance uses pool.ntp.org, time.google.com, and time.cloudflare.com.


Keep it synced automatically

await timeSync.sync();
timeSync.startAutoSync(300000); // ms — re-sync every 5 minutes

Or enable it at construction: new TimeSync({ autoSync: true, autoSyncInterval: 300000 }).

coherenceValidation queries multiple servers and uses the median offset — useful if one server is having a bad day. Emits a coherenceWarning event if servers disagree by more than 100ms.


Smooth correction

By default, if your clock is off by 500ms and you re-sync, it jumps 500ms instantly. That can break timers and logs. Smooth correction applies the fix gradually:

timeSync.setSmoothCorrection(true, {
    maxCorrectionJump: 1000,  // ms — apply instantly if diff is under 1s
    correctionRate: 0.1,      // fraction per sync cycle (0.1 = 10%)
    maxOffsetThreshold: 5000  // ms — always apply instantly if diff > 5s
});

// If you can't wait for the gradual correction to finish:
timeSync.forceCorrection();

Utilities

// Format current NTP time (pass null as first argument to use NTP time)
timeSync.format(null, 'iso')              // "2026-04-25T15:30:45.123Z"
timeSync.format(null, 'locale')           // system locale, e.g. "25/04/2026, 17:30:45"
timeSync.format(null, 'locale', 'en-US') // "4/25/2026, 5:30:45 PM"
timeSync.format(null, 'utc')             // "Sat, 25 Apr 2026 15:30:45 GMT"
timeSync.format(null, 'date')            // date only
timeSync.format(null, 'time')            // time only
timeSync.format(null, 'timestamp')       // Unix timestamp as string

// Format a specific date
timeSync.format('2026-01-01', 'iso')     // "2026-01-01T00:00:00.000Z"
timeSync.format(new Date(), 'locale')    // any Date object works too

// Difference between two dates — returns ms
timeSync.diff('2026-01-01', timeSync.now()) // e.g. 9849600000 ms

// console.log with NTP timestamp prefix
timeSync.log('order processed')
// → [2026-04-25T15:30:45.123Z] order processed

// Check sync status without throwing
if (timeSync.isSynchronized()) {
    console.log(timeSync.now());
}

Live HTML clock via WebSocket

// server.js
await timeSync.sync();
timeSync.startWebSocketServer(8080);
timeSync.startAutoSync(300000);
<h1 id="clock"></h1>
<script>
const ws = new WebSocket('ws://localhost:8080');
ws.onmessage = (e) => {
    const { data } = JSON.parse(e.data);
    document.getElementById('clock').textContent =
        new Date(data.timestamp).toLocaleTimeString();
};
</script>

Events

timeSync.on('sync', (data) => {
    // data.server, data.offset (ms), data.rtt (ms)
    console.log(`synced — offset: ${data.offset}ms, rtt: ${data.rtt}ms`);
});

timeSync.on('error', (err) => {
    // err.message, err.server
    console.error(`sync failed on ${err.server}: ${err.message}`);
});

timeSync.on('coherenceWarning', (data) => {
    // servers disagree by more than 100ms
    console.warn(`server variance: ${data.variance}ms`, data.servers);
});

timeSync.on('driftWarning', (data) => {
    // now() called more than 1 hour after last sync
    console.warn(`${(data.elapsed / 3600000).toFixed(1)}h since last sync`);
});

timeSync.on('correctionComplete', (data) => {
    // data.finalOffset, data.converged, data.forced, data.timeout
    console.log(`correction done — final offset: ${data.finalOffset}ms`);
});

Stats

const s = timeSync.stats();

s.synchronized         // true/false
s.offset               // ms — current system clock error
s.rtt                  // ms — last network round-trip time
s.correctedOffset      // ms — offset currently being applied
s.correctionInProgress // true while smooth correction is running
s.lastSync             // Date of last successful sync
s.uptime               // ms since last sync

API

Method Description
sync(options?) Sync with NTP servers
now() Current precise time as a Date
timestamp() Current time as ISO string
offset() System clock error in ms
isSynchronized() Returns true if synced (no throw)
stats() Full sync diagnostics
startAutoSync(interval) Re-sync on an interval (interval in ms)
stopAutoSync() Stop auto-sync
setSmoothCorrection(bool, options?) Configure gradual correction
forceCorrection() Apply pending correction immediately
startWebSocketServer(port) Broadcast time over WebSocket
stopWebSocketServer() Stop WebSocket server
format(date?, format?, locale?) Format a date (iso, locale, utc, date, time, timestamp)
diff(date1, date2?) Difference between two dates — returns ms
log(message) console.log with NTP timestamp prefix

Full option reference: docs/api-reference.md


Try it

npm run basic        # simple sync
npm run auto-sync    # auto-sync loop
npm run websocket    # WebSocket + HTML clock

License

MIT

GitHub npm version

About

⏰ Simple NTP time sync for Node.js - Auto-drift, WebSocket & HTML clocks

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors