dev

DynamicCountdown is a JavaScript which displays a live countdown to a specified date anywhere on a page using a simple class and data attributes. It supports IANA timezones, custom format strings, automatic year rollover, and more.

Installation

Usage

Add the class dynamic-countdown to any element and configure it using data attributes. It is recommended to add placeholder text such as Loading... inside the element so users see something before the script runs.

<span class="dynamic-countdown" data-date="2027-01-01 00:00:00">Loading...</span>

Configuration

Parameters

Attribute Description Default
data-date The target date and time in YYYY-MM-DD HH:MM:SS format (24-hour). Required
data-timezone IANA timezone name (e.g. America/New_York). If not set, uses the viewer's local timezone. Viewer's local timezone
data-format Format string controlling how the countdown is displayed. See Tokens below. [Y !years, ][M !months, ][D !days, ][H !hours, ][N !minutes and ][S !seconds]
data-trim Set to true to automatically hide units that are currently 0. Does not apply to seconds. false
data-end Controls what happens when the countdown ends. Values must be provided in order — you cannot skip a value to set a later one.

End message, Display duration, Rollover interval

* End message — the text to display when the countdown reaches zero.
* Display duration — how long to show the end message before the next action (e.g. 30s, 10m, 2h). If omitted, the message displays indefinitely.
* Rollover interval — how long until the countdown resets (e.g. 7d, 1mo, 1y). Requires a display duration. If omitted, an error will display after the duration ends.

Supported units: s (seconds), m (minutes), h (hours), d (days), mo (months), y (years). If the display duration is greater than or equal to the rollover interval, an error will display immediately.
Countdown over
data-event Fires a countdownEnd JavaScript event when the countdown ends. Accepts a boolean and optional ID (e.g. true, myEvent). The ID is passed in the event's detail object. false

Tokens

The following tokens can be used in data-format. To use a letter literally without it being treated as a token, escape it with ! (e.g. !D outputs a literal D).

Wrapping a segment in square brackets (e.g. [D !days, ]) marks it as trimmable — when data-trim="true" is set, the entire segment is hidden if its value is 0. This does not apply to seconds tokens.

Token Description Example
Y Years, no leading zero 2
YY Years, with leading zero 02
M Months, no leading zero 3
MM Months, with leading zero 03
D Days, no leading zero 5
DD Days, with leading zero 05
H Hours, no leading zero 7
HH Hours, with leading zero 07
N Minutes, no leading zero 4
NN Minutes, with leading zero 04
S Seconds, no leading zero 9
SS Seconds, with leading zero 09

If a higher unit is not present in the format string, the next lower unit will display the total accumulated value. For example, if D is omitted, H will show total hours remaining rather than just the hours component.

Examples

Basic

<span class="dynamic-countdown" data-date="2027-01-01 00:00:00">Loading...</span>

With timezone

<span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="America/New_York">Loading...</span>

With trim

<span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-format="[Y !years, ][M !months, ][D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-trim="true">Loading...</span>

New Year countdown with rollover

<span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Europe/London" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>

With event

<span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-event="true, newyear">Loading...</span>
document.addEventListener('countdownEnd', function(e) {
    if (e.detail.id === 'newyear') {
        // your code here
    }
});

Weekly Countdown

Every week, counts down to the same time next week forever.

<span class="dynamic-countdown"
    data-date="2026-04-26 18:44:00"
    data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]"
    data-end="Anniversary of this script!!!!!, 30m, 7d"
    data-trim="true">
Loading...
</span>

New Year countdowns by timezone

The following table shows live New Year countdowns for a selection of timezones around the world.

Region Live Countdown Code
UTC-12 (Baker Island) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Etc/GMT+12" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-11 (Samoa) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Pacific/Pago_Pago" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-10 (Hawaii) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Pacific/Honolulu" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-9 (Alaska) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="America/Anchorage" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-8 (Los Angeles) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="America/Los_Angeles" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-7 (Denver) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="America/Denver" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-6 (Chicago) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="America/Chicago" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-5 (New York) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="America/New_York" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-4 (Halifax) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="America/Halifax" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-3 (São Paulo) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="America/Sao_Paulo" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-2 (South Georgia) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Atlantic/South_Georgia" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC-1 (Azores) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Atlantic/Azores" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+0 (London) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Europe/London" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+1 (Paris) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Europe/Paris" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+2 (Cairo) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Africa/Cairo" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+3 (Moscow) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Europe/Moscow" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+4 (Dubai) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Asia/Dubai" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+5:30 (India) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Asia/Kolkata" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+6 (Dhaka) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Asia/Dhaka" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+7 (Bangkok) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Asia/Bangkok" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+8 (Singapore) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Asia/Singapore" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+9 (Tokyo) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Asia/Tokyo" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+10 (Sydney) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Australia/Sydney" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+11 (Noumea) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Pacific/Noumea" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+12 (Auckland) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Pacific/Auckland" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+13 (Tonga) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Pacific/Tongatapu" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>
UTC+14 (Kiritimati) Loading... <span class="dynamic-countdown" data-date="2027-01-01 00:00:00" data-timezone="Pacific/Kiritimati" data-format="[D !days, ][H !hours, ][N !minutes and ][S !seconds]" data-end="Happy New Year!, 1h, 1y" data-trim="true">Loading...</span>

Changelog

Date Notes Updated by
April 27, 2026 Updated rollover to use typed duration units (s, m, h, d, mo, y) instead of a plain number of days. Added overlap validation between message duration and rollover. DaBritishWaffle
April 26, 2026 First publication of the script. DaBritishWaffle

See Also

Text above can be found here (edit)