Countdown

Event Timer and Date Countdown Script

Countdown is a Perl CGI script that displays the time remaining until a specific date or event. You can configure the countdown to show seconds, minutes, hours, days, months, or years. Perfect for launch pages, event announcements, promotions, and milestone celebrations.

Free Download
Version 1.0
Perl CGI

Modern Countdown Libraries (2024)

JavaScript countdown libraries provide real-time updates, animations, and rich styling without page refreshes.

Flip Clock Style (Retro)

FlipDown

Lightweight, performant flip clock. Multiple instances, custom themes, completion callback. Pure JavaScript.

Free MIT ~3KB
npm install flipdown
simplyCountdown.js

Zero dependencies, TypeScript support. Multiple themes (dark, cyber, circle). Perfect for landing pages.

Free MIT TypeScript
npm install simplycountdown.js

Modern / Lightweight

EasyTimer.js

Stopwatch/countdown library. Event-driven, configurable precision. Works with Node.js and browsers.

Free MIT ~5KB
npm install easytimer.js
Day.js + setInterval

Use Day.js for date math with custom rendering. Tiny (2KB), immutable, works like Moment.js.

Free 2KB
npm install dayjs
Native JavaScript

No library needed! See our code examples above for a production-ready vanilla JS solution.

Free 0KB No deps

Framework-Specific

react-countdown

Customizable React component. Render props, completion callback.

React
vue-countdown

Vue 3 countdown component. Scoped slots for custom rendering.

Vue 3
svelte-countdown

Svelte countdown with slots. Minimal bundle size.

Svelte

Comparison: CGI vs JavaScript Countdown

Feature Perl CGI (1990s) Modern JavaScript
Real-time updatesNo (page refresh)Yes
Server requiredYes (CGI)No
AnimationsNoneFlip, fade, etc.
Timezone handlingServer TZ onlyUser's local TZ
Multiple countdownsMultiple iframesEasy
Mobile-friendlyBasicResponsive
Completion actionNoneCallbacks, redirects

Live Demo

Countdown to New Year
Loading...
JavaScript recreation of Countdown output
Custom Event Countdown
Select a date above

Overview

The Countdown script calculates the time difference between the current date/time and a target date you specify. It can be configured to show the countdown at various levels of precision, from years down to seconds.

Package Contents
File Description
countdown.pl Main Perl script that calculates and displays the countdown
countdown.html Example HTML file showing various implementation methods
README Installation instructions and configuration guide
Common Uses
  • Product launch pages
  • Event announcements
  • Holiday promotions
  • Anniversary celebrations
  • Sale end timers
  • Conference countdowns

Features

Multiple Precision Levels

Display countdown in years, months, days, hours, minutes, or seconds - choose the precision that fits your needs.

Flexible Date Format

Specify target dates in a simple format: year, month, day, hour, minute, second.

Customizable Output

Configure the HTML template to match your site's design and style.

URL Parameters

Pass target date via URL query string for dynamic countdown pages.

Past Date Support

Calculate time elapsed since past dates for "time since" displays.

SSI Compatible

Can be modified to work with Server Side Includes for inline display.

Usage Examples

URL Format Description Example Output
countdown.cgi?2025,12,31,0,0,0 Countdown to New Year's Eve 2025 15 days, 6 hours, 23 minutes, 45 seconds
countdown.cgi?2025,7,4,12,0,0 Countdown to July 4th, 2025 at noon 200 days, 18 hours, 0 minutes, 0 seconds
countdown.cgi?2026,1,1,0,0,0 Full year countdown 1 year, 15 days, 6 hours...
URL Parameter Format
countdown.cgi?YEAR,MONTH,DAY,HOUR,MINUTE,SECOND
  • YEAR: 4-digit year (e.g., 2025)
  • MONTH: 1-12 (January = 1)
  • DAY: 1-31
  • HOUR: 0-23 (24-hour format)
  • MINUTE: 0-59
  • SECOND: 0-59

Installation

  1. Upload the Script
    Upload countdown.pl to your cgi-bin directory.
  2. Configure Perl Path
    Edit the first line of the script to point to your Perl interpreter (usually #!/usr/bin/perl).
  3. Set Permissions
    Set the script permissions to 755: chmod 755 countdown.pl
  4. Customize Output (Optional)
    Edit the HTML template within the script to match your site's design.
  5. Link to the Script
    Create links or redirects pointing to the script with your target date in the query string.

Code Examples

Perl Implementation
#!/usr/bin/perl
use strict;
use warnings;
use Time::Local;
use CGI;

my $cgi = CGI->new;

# Get target date from query string
my $query = $ENV{'QUERY_STRING'} || '2025,1,1,0,0,0';
my ($year, $month, $day, $hour, $min, $sec) = split(/,/, $query);

# Validate input
$year  ||= 2025;
$month ||= 1;
$day   ||= 1;
$hour  ||= 0;
$min   ||= 0;
$sec   ||= 0;

# Calculate target timestamp
my $target = eval {
    timelocal($sec, $min, $hour, $day, $month - 1, $year);
};

if ($@) {
    print $cgi->header('text/html');
    print "Invalid date specified";
    exit;
}

# Calculate difference
my $now = time();
my $diff = $target - $now;
my $past = 0;

if ($diff < 0) {
    $past = 1;
    $diff = abs($diff);
}

# Break down the difference
my $days    = int($diff / 86400);
my $hours   = int(($diff % 86400) / 3600);
my $minutes = int(($diff % 3600) / 60);
my $seconds = $diff % 60;

# Output
print $cgi->header('text/html');
print $cgi->start_html('Countdown');

if ($past) {
    print "

Time Since Event

"; } else { print "

Countdown

"; } print "

$days days, $hours hours, $minutes minutes, $seconds seconds

"; print $cgi->end_html; exit 0;
PHP Implementation
<?php
/**
 * Countdown Timer - PHP Version
 */

// Get target date from query string or use default
$target_str = $_GET['date'] ?? '2025-01-01 00:00:00';

try {
    $target = new DateTime($target_str);
    $now = new DateTime();
    $diff = $target->diff($now);

    $is_past = $target < $now;
} catch (Exception $e) {
    die("Invalid date format. Use: YYYY-MM-DD HH:MM:SS");
}

// Function to format countdown
function formatCountdown($diff, $is_past) {
    $parts = [];

    if ($diff->y > 0) {
        $parts[] = $diff->y . ' ' . ($diff->y == 1 ? 'year' : 'years');
    }
    if ($diff->m > 0) {
        $parts[] = $diff->m . ' ' . ($diff->m == 1 ? 'month' : 'months');
    }
    if ($diff->d > 0) {
        $parts[] = $diff->d . ' ' . ($diff->d == 1 ? 'day' : 'days');
    }
    if ($diff->h > 0) {
        $parts[] = $diff->h . ' ' . ($diff->h == 1 ? 'hour' : 'hours');
    }
    if ($diff->i > 0) {
        $parts[] = $diff->i . ' ' . ($diff->i == 1 ? 'minute' : 'minutes');
    }
    if ($diff->s > 0) {
        $parts[] = $diff->s . ' ' . ($diff->s == 1 ? 'second' : 'seconds');
    }

    $prefix = $is_past ? 'Time since event: ' : 'Time remaining: ';
    return $prefix . implode(', ', $parts);
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Countdown</title>
</head>
<body>
    <h1><?php echo $is_past ? 'Time Since' : 'Countdown'; ?></h1>
    <p><?php echo formatCountdown($diff, $is_past); ?></p>

    <!-- Total seconds remaining (useful for JavaScript) -->
    <p>Total seconds: <?php
        $total = $diff->days * 86400 + $diff->h * 3600 + $diff->i * 60 + $diff->s;
        echo $is_past ? -$total : $total;
    ?></p>
</body>
</html>
JavaScript Implementation (Recommended)
/**
 * Countdown Timer - JavaScript Version
 * Real-time updating countdown with no page refresh
 */

class CountdownTimer {
    constructor(element, targetDate, options = {}) {
        this.element = typeof element === 'string'
            ? document.querySelector(element)
            : element;

        this.target = new Date(targetDate);
        this.options = {
            showYears: true,
            showMonths: true,
            showDays: true,
            showHours: true,
            showMinutes: true,
            showSeconds: true,
            onComplete: null,
            updateInterval: 1000,
            ...options
        };

        this.intervalId = null;
        this.start();
    }

    start() {
        this.update();
        this.intervalId = setInterval(() => this.update(), this.options.updateInterval);
    }

    stop() {
        if (this.intervalId) {
            clearInterval(this.intervalId);
            this.intervalId = null;
        }
    }

    update() {
        const now = new Date();
        let diff = this.target - now;
        const isPast = diff < 0;

        if (isPast) {
            diff = Math.abs(diff);
        }

        const time = this.calculateTime(diff);
        this.render(time, isPast);

        if (diff <= 0 && this.options.onComplete) {
            this.options.onComplete();
            this.stop();
        }
    }

    calculateTime(ms) {
        const seconds = Math.floor(ms / 1000);
        const minutes = Math.floor(seconds / 60);
        const hours = Math.floor(minutes / 60);
        const days = Math.floor(hours / 24);
        const months = Math.floor(days / 30);
        const years = Math.floor(days / 365);

        return {
            years: years,
            months: months % 12,
            days: days % 30,
            hours: hours % 24,
            minutes: minutes % 60,
            seconds: seconds % 60,
            totalDays: days,
            totalHours: hours,
            totalMinutes: minutes,
            totalSeconds: seconds
        };
    }

    render(time, isPast) {
        const parts = [];

        if (this.options.showYears && time.years > 0) {
            parts.push(`${time.years} ${time.years === 1 ? 'year' : 'years'}`);
        }
        if (this.options.showMonths && time.months > 0) {
            parts.push(`${time.months} ${time.months === 1 ? 'month' : 'months'}`);
        }
        if (this.options.showDays && time.days > 0) {
            parts.push(`${time.days} ${time.days === 1 ? 'day' : 'days'}`);
        }
        if (this.options.showHours) {
            parts.push(`${time.hours} ${time.hours === 1 ? 'hour' : 'hours'}`);
        }
        if (this.options.showMinutes) {
            parts.push(`${time.minutes} ${time.minutes === 1 ? 'minute' : 'minutes'}`);
        }
        if (this.options.showSeconds) {
            parts.push(`${time.seconds} ${time.seconds === 1 ? 'second' : 'seconds'}`);
        }

        const prefix = isPast ? 'Time since: ' : '';
        this.element.innerHTML = prefix + parts.join(', ');
    }

    // Static method for simple countdown display
    static simple(elementId, targetDate) {
        return new CountdownTimer(elementId, targetDate);
    }
}

// Usage examples:

// Basic usage
new CountdownTimer('#countdown', '2025-12-31T00:00:00');

// With options
new CountdownTimer('#event-countdown', '2025-07-04T12:00:00', {
    showYears: false,
    showMonths: false,
    onComplete: () => {
        alert('Event has started!');
    }
});

// Simple one-liner
CountdownTimer.simple('#timer', 'January 1, 2026');
HTML Usage Examples
<!-- Link to countdown page -->
<a href="/cgi-bin/countdown.cgi?2025,12,31,0,0,0">
    Countdown to New Year 2026!
</a>

<!-- Embed in iframe -->
<iframe src="/cgi-bin/countdown.cgi?2025,7,4,0,0,0"
        width="400" height="100" frameborder="0">
</iframe>

<!-- SSI include (if modified for SSI) -->
<!--#exec cgi="/cgi-bin/countdown.cgi?2025,12,25,0,0,0"-->

<!-- Modern JavaScript approach (recommended) -->
<div id="my-countdown"></div>
<script>
    // Countdown to specific date
    new CountdownTimer('#my-countdown', '2025-12-31T23:59:59', {
        onComplete: function() {
            document.getElementById('my-countdown').innerHTML =
                '<span class="text-success">Happy New Year!</span>';
        }
    });
</script>

<!-- Bootstrap card with countdown -->
<div class="card">
    <div class="card-header bg-primary text-white">
        <i class="bi bi-clock"></i> Special Sale Ends In:
    </div>
    <div class="card-body text-center">
        <div id="sale-countdown" class="display-6"></div>
    </div>
</div>

Download

Compressed Archives
  • countdown.tar.gz 5.1 KB
  • countdown.zip 5.5 KB
  • countdown.tar.Z 8.1 KB
  • countdown.tar 20.5 KB
Individual Files
  • countdown.pl

    Main Perl script that calculates and displays the countdown

  • countdown.html

    Example HTML file with implementation examples

  • README

    Installation instructions and configuration guide

Frequently Asked Questions

Yes, you can add a return link by editing the HTML output section of the script. Find the section where the countdown is printed and add an anchor tag like <a href="/">Return to Home</a>. You can also pass a return URL as an additional query parameter and include it dynamically in the output.

Yes, there are several ways to inline the countdown: (1) Modify the script to work with Server Side Includes by removing the HTML headers and just outputting the countdown text, (2) Use an iframe to embed the countdown page, or (3) Better yet, use JavaScript for a real-time updating countdown that doesn't require page refreshes. The JavaScript approach is recommended for modern websites.

The Perl CGI version generates a static page that shows the countdown at the moment the page loads. To see an updated countdown, you need to refresh the page. For a live-updating countdown without page refreshes, you should use JavaScript. The JavaScript examples above provide a modern implementation that updates in real-time.

The original script uses the server's timezone. To handle different timezones: (1) In Perl, set the TZ environment variable before calculating times, (2) In PHP, use DateTime with DateTimeZone objects, (3) In JavaScript, Date objects work in the user's local timezone by default, or you can use libraries like Luxon or date-fns-tz for specific timezone handling.

The original script will show a negative countdown (time since the event). You can modify the script to display a custom message when the target date is reached, redirect to another page, or simply stop at zero. The JavaScript example above includes an onComplete callback that fires when the countdown reaches zero.

With the CGI script, you would need to use multiple iframes. However, with JavaScript, you can easily create multiple countdown instances on the same page by giving each a unique element ID. Just create multiple new CountdownTimer() instances with different target elements and dates.

Edit the HTML template section in the Perl script to add CSS classes or inline styles. You can wrap each time unit in span tags with different classes for styling. With JavaScript, you have complete control over the HTML output and can create elaborate designs with separate boxes for days, hours, minutes, and seconds.

Yes, JavaScript is the preferred method for countdown timers today. It provides real-time updates without server requests, works with any hosting (no CGI required), and offers better user experience. The JavaScript examples on this page demonstrate modern implementations. For advanced features, consider libraries like Countdown.js or FlipClock.js.