In today's tutorial we will create a digital clock that will show us the current time and it will also have a nice alarm feature. By the end of this tutorial you'll be familiar with working with the Javascript Date object, and also you'll have a minimal understanding of asynchronous code execution and the setTimeout API.
Video tutorial
If you prefer a detailed video tutorial instead, feel free to check out the tutorial that I created on my YouTube channel:
HTML
The html markup for this project is pretty simple. But before we implement that, let's add the custom font from Google that we will use in the head
section of the HTML document. I'll also include the stylesheet that we will create later.
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Orbitron&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
We will have a section with a class of container
which will hold our clock. Below that we need to create an empty div, which will be used to display the current time. I give it an id of clock
, so it will be easier to target.
<section class="container">
<div id="clock"></div>
</section>
Next we will add the input field, so the user will be able to select a date and time to set the alarm. The important thing here is, that the input type should be "datetime-local"
. We'll also give it a name attribute and an onchange event handler. When the onchange event happens (so the value of the input field changes), we will fire this function setAlarmTime(this.value)
that we will implement in our js file just in a bit. We pass this.value
to the function which will give is the new, updated value of the input field.
<input onchange="setAlarmTime(this.value)" name="alarmTime" type="datetime-local">
Next we have to add the control buttons. We will wrap these two buttons into a wrapper div, and give it a css class of controls
. Inside that we'll add two buttons, "Set alarm" and "Clear alarm". Besides the css classes, we add click event hanler functions. We will create the functions: setAlarm()
and clearAlarm()
in javascript later.
<div class="controls">
<button onclick="setAlarm()" class="button set-alarm">Set alarm</button>
<button onclick="clearAlarm()" class="button clear-alarm">Clear alarm</button>
</div>
Lastly, we have to include our javascript file at the bottom of our HTML document's body. We need to import it at the end of the document, so when our script will run, the DOM tree will be ready. (You could also include it in the head with the defer
keyword).
<script src="index.js"></script>
CSS
In our styles.css
file I'll start with clearing every browser defined paddings and margins, and also set a dark background color.
body,html {
margin: 0;
padding: 0;
background-color: #12181B;
}
* {
box-sizing: border-box;
}
Using flexbox we'll make the container take the full viewport, and center its content.
.container {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
For the clock we will set the font that we included earlier in the HTML, and set the desired font size. I'll also add a gradient color to the clock. To do that we will set a gradient as a background image, then we will color the font with the background gradient using the background-clip: text
CSS rule.
#clock {
font-family: 'Orbitron', sans-serif;
font-size: 15vw;
background-image: linear-gradient(180deg,
rgba(99,253,136,1) 0%,
rgba(51,197,142,1) 50%,
rgba(39,97,116,1) 100%);
background-clip: text;
-webkit-background-clip: text;
-moz-background-clip: text;
-webkit-text-fill-color: transparent;
-moz-text-fill-color: transparent;
}
Lastly, we make some styling to the control buttons and the wrapper div.
.controls {
margin-top: 16px;
}
.button {
font-weight: bold;
border-radius: 5px;
border: none;
color: white;
padding: 4px 8px;
margin-left: 4px;
cursor: pointer;
}
.set-alarm {
background-color: #498AFB;
}
.clear-alarm {
background-color: #FF3860;
}
Javascript
This will be the hearth of our clock application. First, we will save a reference to our clock display (the div with the clock
id) into a display variable. We'll also set up the audio for the alarm. To do that I'll use a free alarm sound form Mixkit, feel free to use any music/sound of your choice.
We will create a new Audio object and save it to the audio
variable. We'll also set the loop property of the audio object to true, as we want to play the sound, till the alarm is turned off manually. As you can see we have an alarmTime
and alarmTimeout
variables, that we initialise with null. We will use these variables to implement the alarm functionality.
const display = document.getElementById('clock');
const audio = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-alarm-digital-clock-beep-989.mp3');
audio.loop = true;
let alarmTime = null;
let alarmTimeout = null;
Now we'll implement the clock functionality. In the updateTime
function we create a new Date object. As we didn't provide any parameter to it it will create an object with the current time. Then we create 3 variables to get the hour, minute and second values from the Date object. We can do it easily using the API of the javascript Date object.
To have a nice digital display, we'll create a function which format's the time values. It places a leading zero if the number is only one digit, otherwise it uses the number. So for example if the time value provided is 9
, it returns 09
instead.
function formatTime(time) {
if ( time < 10 ) {
return '0' + time;
}
return time;
}
Lastly we have to override the display
DOM node's innerText to represent the current time. I used string template literals here, so anything between ${}
will be replaced with the value of that variable.
function updateTime() {
const date = new Date();
const hour = formatTime(date.getHours());
const minutes = formatTime(date.getMinutes());
const seconds = formatTime(date.getSeconds());
display.innerText=`${hour} : ${minutes} : ${seconds}`
}
Now we just have to call this function every second to update the displayed time. We can do that by using the setInterval API, pass the updateTime function to it and pass 1000 (it is in ms) as it's second parameter.
setInterval(updateTime, 1000);
Now we have a working clock. It's time to implement the alarm feature. The first thing is that we have to collect and save the date and time selected by the user. We already attached an onchange
event listener in the HTMl, now we just have to implement that in javascript. We will simply get the value from the event handler and save it to the alarmTime
variable.
function setAlarmTime(value) {
alarmTime = value;
}
Now we should implement the setAlarm
function. This will be responsible for setting the alarm to the desired time and play the sound. If an alarmTime
is set we create two Date objects, one with the current time (empty parameters), and one using the user selected alarm time and date. If the time of the alarm is in the future, we will set the alarm. To calculate the time left till the alarm, we convert both dates to time in ms (this will give us pack time in ms since unix epoch, more details here) and subtract the future value from the current. This ways we know, how much ms is left till the alarm shall play. We just have to set a timeout to call the play method of the audio object. We'll also save the return result of the setTimeout function into the global alarmTimeout
variable. We will use this reference to clear the timeout if needed.
function setAlarm() {
if(alarmTime) {
const current = new Date();
const timeToAlarm = new Date(alarmTime);
if (timeToAlarm > current) {
const timeout = timeToAlarm.getTime() - current.getTime();
alarmTimeout = setTimeout(() => audio.play(), timeout);
alert('Alarm set');
}
}
}
The last thing that we have to implement is the clear functionality of the alarm. We will stop the alarm sound if it already playing, and we will cancel the set alarm if it is in the future. So in our clearAlarm
function we will call the pause method of our audio object. Then if we have a scheduled alarm (so the alarmTimeout has a value), we will use the built in clearTimeout
function to cancel that future function call.
function clearAlarm() {
audio.pause();
if (alarmTimeout) {
clearTimeout(alarmTimeout);
alert('Alarm cleared');
}
}
The whole project is available on GitHub.
Conclusion
So this is how you can create a digital clock with alarm features in a beginner-friendly way using javascript. I think that this is an interesting project that you can build, and you also practice some fundamental javascript topics, like Dates, DOM modification and asynchronous API-s like setInterval and setTimeout.
Where you can learn more from me?
I create education content covering web-development on several platforms, feel free to 👀 check them out.
I also create a newsletter where I share the week's or 2 week's educational content that I created. No bull💩 just educational content.
🔗 Links:
- 🍺 Support free education and buy me a beer
- 💬 Join our community on Discord
- 📧 Newsletter Subscribe here
- 🎥 YouTube Javascript Academy
- 🐦 Twitter: @dev_adamnagy
- 📷 Instagram @javascriptacademy
Top comments (7)
i think we can use requestAnimationFrame instead of setInterval
set time interval works perfectly. But with request animation frame you need to refresh the browser before the time updates.
That is mostly used for animations but can work here too. Nice suggestion. 😊
I would second vsam.. interval api would not be accurate
Set time interval works perfectly. But with request animation frame you need to refresh the browser before the time updates.
The order of your project here on dev.to is a little different from github.
I'm very beginner, I made the project following the explanation, but I checked and it was the same, I saw that in the git hub it was different, I redid it, still it gave an unsatisfied error, I gave a git clone. And it gave an error, several errors
Hi Valeria!
The order is a little bit different here because I wanted to have a clear way of how I think and plan the project.
The project itself should 100% work, if you are a beginner I highly suggesting to check the video I attached in the beginning. I think that will be easier to follow for you.
Good luck! Feel free to reach out if you face any problems.
*Also please provide error messages so we can help you resolve those issues.