#EXT-X-PROGRAM-DATE-TIME: Wall-Clock Sync for HLS DVR and Multi-Stream Capture
August 5, 2026 · 6 min read
Every segment in an HLS playlist has a position — a sequence number that says where it sits relative to the other segments. What it doesn't have, by default, is a position in real-world time: no information connecting a segment to the actual clock on the wall. The #EXT-X-PROGRAM-DATE-TIME tag adds that connection, and a surprising number of live streaming features depend on it.
What the tag declares
#EXT-X-PROGRAM-DATE-TIME appears in a media playlist immediately before a segment URI and carries an ISO 8601 date-time value:
#EXTM3U
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:42
#EXT-X-PROGRAM-DATE-TIME:2026-08-03T14:30:00.000Z
#EXTINF:6.006,
segment042.tsThis tells a player: "The first frame of segment042.tswas captured at 14:30:00.000 UTC on 2026-08-03." From that anchor, the player can derive the wall-clock time of any frame in the playlist by adding the appropriate offset — a frame three seconds into the third subsequent segment is at 14:30:15.018 UTC (three full segments at 6.006 s each, plus three seconds).
The tag doesn't need to appear before every segment. It only needs to appear at the start of the playlist window and after any discontinuity. Once an anchor is established, players interpolate positions for all following segments from that anchor and the segment durations declared by #EXTINF.
Why absolute timestamps matter for DVR
Live streams often expose a DVR window — a rolling buffer of past content that viewers can seek back into. Without #EXT-X-PROGRAM-DATE-TIME, a player can only represent that window in relative terms: "you are 4 minutes and 32 seconds behind live." The player has no way to say what real-world moment that position corresponds to.
With the tag, the player can display an actual clock — "you are watching the feed as it was at 14:25:28 UTC" — and more importantly, it can seek to a specific wall-clock time. Users scrubbing back to catch something they missed can seek to "two minutes ago" or "10:15 PM" rather than needing to estimate from an abstract offset. Sports broadcasts, news streams, and any live content where specific moments matter all benefit substantially from this.
Synchronized multi-stream capture
Another use case is capturing multiple HLS streams that represent different camera angles or audio feeds of the same event. Without wall-clock anchors, aligning them requires external synchronization data. With #EXT-X-PROGRAM-DATE-TIME present in each stream, a tool can use the timestamps to align the streams to the same moment in time automatically.
This is how broadcast-grade multi-angle DVR works. The playlists don't need to have the same segment boundaries or durations — the timestamps let a player lock them independently to the same wall-clock reference.
How hls.js uses the tag
hls.js exposes #EXT-X-PROGRAM-DATE-TIME values through its fragment metadata. When the tag is present, frag.programDateTime on each parsed fragment carries the absolute timestamp as a Unix millisecond value. The library also exposes a Hls.Events.FRAG_CHANGED payload that includes the program date-time, which is what enables the DVR clock display in players that choose to surface it.
The site's own live player (/play?broadcast=1) uses hls.js with lowLatencyMode as described in the LL-HLS post. It doesn't currently surface frag.programDateTimein the UI — it shows offset-from-live rather than a wall-clock readout. That's a presentation decision, not a hls.js limitation; the data is available in the fragment metadata whether or not it's displayed.
The precision question
#EXT-X-PROGRAM-DATE-TIMEcarries millisecond precision in the ISO 8601 format, and most encoders populate it that way. In practice, the timestamp's accuracy depends on whether the encoder's clock was synchronized — if the stream was produced by equipment with a well-calibrated NTP source, the timestamp will be accurate to a few milliseconds of real time. If the encoder clock drifted or was set manually, the timestamp may be accurate in a relative sense (segment N is 6.006 seconds after segment N-1) without being accurate in an absolute sense (the date-time value doesn't match what a global clock would show).
Players that rely on the tag for DVR positioning don't require absolute accuracy — they require relative consistency across the playlist window. A timestamp that's consistently ten seconds behind real time still produces correct DVR seek behavior; it just shows a clock that's ten seconds behind.
What happens when the tag is absent
Most live HLS streams don't include #EXT-X-PROGRAM-DATE-TIME. When it's absent, players work with relative positions only. hls.js handles this gracefully — it tracks segment sequence numbers and durations for buffering and ABR decisions without needing wall-clock anchors.
The downside is that any feature depending on wall-clock time — DVR clock display, absolute seek by time-of-day, synchronized multi-stream playback — is unavailable. The stream still plays correctly; it just looks like any other live stream without a DVR clock.
Interaction with discontinuities
When a playlist contains a #EXT-X-DISCONTINUITY tag — signaling a break in the content timeline, such as an ad insertion or encoder failover — the wall-clock timestamp sequence is also broken. Players can't interpolate across a discontinuity boundary. A new #EXT-X-PROGRAM-DATE-TIME tag immediately after the discontinuity re-establishes the anchor for the segments that follow.
Some discontinuity situations produce a timestamp that goes backward — an ad inserted at 14:32:00 may be timestamped from its original recording time rather than the live moment, so the DVR clock jumps back when the ad starts and then jumps forward again when the main content resumes. Players that surface a DVR clock need to handle this gracefully.
What the extension captures
When the Stream Video Downloader extension detects an HLS stream on a page, it captures the playlist URL. The #EXT-X-PROGRAM-DATE-TIMEtags in that playlist are preserved in the fetched manifest — the extension doesn't strip them. If you're converting a stream with /convert, the timestamps survive into the output MP4's container metadata, carried as a stream start time that reflects the original broadcast moment.