Loading your tools...
Loading your tools...
Learn how to build a real-time countdown timer in React. Master the Date object, setInterval, and the math behind converting milliseconds to days.
Handling time in JavaScript is notoriously painful. Timezones? Leap years? Daylight savings? For a countdown, we can bypass most of that pain by using Unix Time (milliseconds since 1970).
In this guide, we will build a countdown that automatically targets the next January 1st, ensuring it works year after year.
We don't want to hardcode 2025. We want the code to work forever.
We get the current year, add 1, and target January 1st (Month 0 in JS).
const currentYear = new Date().getFullYear();
const nextYear = new Date(currentYear + 1, 0, 1); // Month is 0-indexed (0 = Jan)
When you subtract two dates in JS, you get the difference in milliseconds.
1000 ms = 1 second.
We need to slice this big number into Days, Hours, Minutes, and Seconds.
The Formula:
Total / (1000 * 60 * 60 * 24)(Total % Day) / (1000 * 60 * 60) -> The Remainder(Total % Hour) / (1000 * 60)(Total % Minute) / 1000The % (Modulo) operator is the hero here. It gives us what is "left over" after we strip away the larger units.
setInterval) 🔄We need the UI to update every second.
We use useEffect to set up a setInterval.
CRITICAL: You must clear the interval when the component unmounts, or your app will leak memory and crash.
useEffect(() => {
const timer = setInterval(() => {
// Update state here
}, 1000);
return () => clearInterval(timer); // Cleanup phase
}, []);
It looks ugly if the timer says 10:5:9.
It should say 10:05:09.
We use a helper function to add the leading zero.
const format = (num) => num.toString().padStart(2, '0');
Countdown.jsx) 💻Here is the complete, self-correcting countdown timer.
'use client';
import { useState, useEffect } from 'react';
export default function NewYearCountdown() {
const [timeLeft, setTimeLeft] = useState({
days: 0, hours: 0, minutes: 0, seconds: 0
});
useEffect(() => {
const calculateTime = () => {
const now = new Date();
const currentYear = now.getFullYear();
const nextYear = new Date(currentYear + 1, 0, 1);
const diff = nextYear.getTime() - now.getTime();
if (diff <= 0) {
// Happy New Year! (Reset logic or fireworks could go here)
return;
}
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
setTimeLeft({ days, hours, minutes, seconds });
};
// Run immediately so we don't wait 1 second for first render
calculateTime();
// Start loop
const timer = setInterval(calculateTime, 1000);
// Cleanup
return () => clearInterval(timer);
}, []);
return (
<div className="flex flex-col items-center justify-center p-8 bg-neutral-900 text-white rounded-xl shadow-2xl">
<h2 className="text-2xl font-light tracking-widest uppercase mb-8 text-neutral-400">
New Year Countdown
</h2>
<div className="flex gap-4 md:gap-8">
<TimeBox val={timeLeft.days} label="Days" />
<TimeBox val={timeLeft.hours} label="Hours" />
<TimeBox val={timeLeft.minutes} label="Minutes" />
<TimeBox val={timeLeft.seconds} label="Seconds" />
</div>
</div>
);
}
// Reusable Time Box Component
const TimeBox = ({ val, label }) => (
<div className="flex flex-col items-center">
<div className="w-20 h-20 md:w-24 md:h-24 flex items-center justify-center bg-neutral-800 rounded-lg border border-neutral-700 shadow-inner">
<span className="text-3xl md:text-4xl font-bold font-mono text-cyan-400">
{val.toString().padStart(2, '0')}
</span>
</div>
<span className="mt-3 text-xs md:text-sm uppercase tracking-wider text-neutral-500">
{label}
</span>
</div>
);
Developer Tools & Resource Experts
FastTools is dedicated to curating high-quality content and resources that empower developers. With nearly 5 years of hands-on development experience, our team rigorously evaluates every tool and API we recommend, ensuring you get only the most reliable and effective solutions for your projects.