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 |