The KIRUPA orange logo! A stylized orange made to look like a glass of orange juice!

FORUMS

Creating a Sweet Digital Clock

by kirupa   |  filed under Coding Exercises

Build a really cool (and sweet!) digital clock using a bunch of handy HTML, CSS, and JS techniques!

You and I probably look at a digital clock to figure out what time it is at least a billion times a day. Our phone’s lock screen makes up more than half of that number, but I’m sure our microwaves (and smart watches and car displays) are probably not too far behind. Anyway, we aren’t here to take inventory of all the digital clocks in our lives. We’ll save that as a fun family activity for another time. Instead, we are here to build our own digital clock...just like our ancestors did by using nothing but sweet HTML, CSS, and JavaScript.

Onwards!

Our Digital Clock

The digital clock we will be building will look as follows:

We have the hours, minutes, and seconds values that update. Because this happens to be a 12 hour clock, there is also the AM and PM modifier to let us know which half of the two 12 hours in a day we are currently in.

Building the Clock

Now that we have an idea of what we will be building, all that is left is for us to actually build it. Now, I encourage you to first try building this out on your own first. There is no better way to learn than by getting your hands dirty, possibly falling a few times, but still getting back up and powering through. Stop here if you want to try this out on your own. Otherwise, do read on and we will build this together.

Overview

Our digital clock is made up of just a single text element that displays the time and the AM/PM detail. The way this clock works is by relying on the global Date object. This object gives us a bunch of handy properties and methods that give us easy access to the system time. To ensure the time is updated every second, we will rely on a timer that is based on requestAnimationFrame. These are the biggest pieces in our app that deal with getting the time displayed and updated.

As we are building the app, we'll address a handful of other use cases around how our time is displayed. One activity is ensuring our minutes and seconds values are always two digits in length with a 0 at the beginning if we are dealing with a single digit value. For example, we will want to see 12:03:08 PM instead of 12:3:8 PM. Our clock is 12 hours as opposed to 24 hours, so we want to make the appropriate adjustments to the hours value as well as throw in the AM and PM detail as well.

In the following sections, we'll turn all of these words into working HTML, CSS, and JavaScript!

Getting Started

The first thing we will need is a HTML document, so create a new document called digital_clock.htm from your code editor of choice. My favorite is Visual Studio Code, but you can use whatever editor you prefer. Once you have created your document, add the following boilerplate HTML to get our app started:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Digital Clock</title>
</head>
<body>
  
</body>
</html>

This is typically the bare minimum markup we need to provide to have a proper HTML document. In Visual Studio Code, you can also just type ! in the code editor and hit Enter/Return to get this same markup provided for you.

Displaying the Time

Our next activity is to display the time. We won't be displaying the actual time just yet. Instead we'll hard-code a time value to ensure we get the visuals of everything going just the way we want to. To display the time on our page, we'll be using a p element. Go ahead and add the following highlighted line:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Digital Clock</title>
</head>
<body>
  <p id="timerField">12:10:45 AM</p>
</body>
</html>

If we save our page and preview what we have in our browser, we will see something that looks as follows:

This is a start! Next, let's add some CSS to make this look a bit nicer. Go back to the code editor and add the following highlighted lines into it:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Digital Clock</title>
  <style>
    body {
      display: grid;
      place-content: center;
      height: 100vh;
      margin: 0;
      padding: 0;
      background-color: #EEE;
    }
    #timerField {
      font-size: 72px;
      font-family: "Courier New", monospace;
      background: linear-gradient(180deg,rgba(255, 255, 255, 0) 0%, 
                                         rgba(255, 255, 255, 0) 53%, 
                                         #CFBFF7 53%,
                                         #CFBFF7 100%);
      padding-left: 20px;
      padding-right: 20px;
    }
  </style>
</head>
<body>
  <p id="timerField">12:10:45 AM</p>
</body>
</html>

The CSS we added will make our timer look as follows when we preview it in the browser:

This looks much nicer, doesn't it? If we go back to our CSS, we can map what we see in our browser to some of the lines of code we added. In the body selector, we specify the CSS for centering our timer in the middle of our screen using the Grid element:

body {
  display: grid;
  place-content: center;
  height: 100vh;
  margin: 0;
  padding: 0;
  background-color: #EEE;
}

For a Flexbox approach, you can use this technique instead. The purple background behind our timer is defined as a linear gradient:

#timerField {
  font-size: 72px;
  font-family: "Courier New", monospace;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, 
                                      rgba(255, 255, 255, 0) 53%, 
                                      #CFBFF7 53%,
                                      #CFBFF7 100%);
  padding-left: 20px;
  padding-right: 20px;
}

The top half of our gradient is transparent. The bottom half of the gradient is where the purple color is defined, and the way we create a hard boundary between both halves is by specifying overlapping gradient stops at the 53% mark.

Displaying the Actual Time

All that remains now is the behind-the-scenes plumbing to actually display the time. We will do this in stages. First, just below our existing p element, add the script tag and the following JavaScript:

  .
  .
  .
<body>
  <p id="timerField">12:10:45 AM</p>

  <script>
    let timerPlace = document.querySelector("#timerField");
    
    function timer() {
      let date = new Date();

      let seconds = date.getSeconds();
      let hours = date.getHours();
      let minutes = date.getMinutes();

      timerField.textContent = `${hours}:${minutes}:${seconds}`;

      requestAnimationFrame(timer);
    }
    timer();
  </script>
</body>

If you preview this page in your browser now, you'll see the current time being displayed:

This is...something! Take a few moments to see how the JavaScript we added leads to the behavior we see on screen. The main magic is in our timer function. Inside it, we have our Date object that gives us access to the current hours, minutes, and seconds values via the handy getHours, getMinutes, and getSeconds methods:

let timerPlace = document.querySelector("#timerField");
    
function timer() {
  let date = new Date();

  let seconds = date.getSeconds();
  let hours = date.getHours();
  let minutes = date.getMinutes();

  timerField.textContent = `${hours}:${minutes}:${seconds}`;

  requestAnimationFrame(timer);
}
timer();

We print those time values to the screen by setting the textContent property on our text element (our p tag with an id value of timerField) and printing the time to the screen using the template literal syntax. Lastly, we have our timer function looping via the requestAnimationFrame call we have at the bottom. This ensures our timer gets called a nice sixty times a second to ensure our time values update in near real-time.

What we have right now is a digital clock, but it has some gaps. Minute and second values that are just a single digit don't have a 0 in front of them. The AM or PM flag isn't there either. That's OK right now, for the default Date behavior is for our time to be returned in a 24-hour format. That explains the 14 instead of a 2 in the earlier screenshot. We'll address these little omissions next.

Going to a 12-Hour Clock

To go from our 24 hour clock to a 12 hour clock, make the following additions and changes highlighted below:

let timerPlace = document.querySelector("#timerField");
let morningOrEvening = "";

function timer() {
  let date = new Date();

  let seconds = date.getSeconds();
  let hours = date.getHours();
  let minutes = date.getMinutes();

  // Is it AM or PM?
  if (hours >= 12) {
    morningOrEvening = "PM";
  } else {
    morningOrEvening = "AM";
  }

  // Normalize to the 12 hour clock
  if (hours > 12) {
    hours -= 12;
  }

  timerField.textContent = `${hours}:${minutes}:${seconds} ${morningOrEvening}`;

  requestAnimationFrame(timer);
}
timer();

What we are doing here is peforming some checks to see if we are into PM territory or whether we are still in AM territory. Once we have decided where we are, especially if we are in PM territory, we subtract 12 from the hours value to get us into a 12 hour time range. We also set the correct AM or PM value as part of all of this checking.

Ensuring Two Digits for Minutes and Seconds

The last item we are going to be taking care of is normalizing our minutes and seconds values to always display in two digits. If our value is a single digit, we prepend a 0. This seems like it might involve some irritating string manipulation by checking the current value length, but it turns out JavaScript now has a handy padStart method that makes this task a whole lot less irritating. To see this at work, make the following highlighted changes:

let timerPlace = document.querySelector("#timerField");
let morningOrEvening = "";

function timer() {
  let date = new Date();

  let seconds = date.getSeconds();
  let hours = date.getHours();
  let minutes = date.getMinutes();

  // Is it AM or PM?
  if (hours >= 12) {
    morningOrEvening = "PM";
  } else {
    morningOrEvening = "AM";
  }

  // Normalize to the 12 hour clock
  if (hours > 12) {
    hours -= 12;
  }

  // Ensure second and minutes values are two digits
  let paddedSeconds = String(seconds).padStart(2, "0");
  let paddedMinutes = String(minutes).padStart(2, "0");

  timerField.textContent = `${hours}:${paddedMinutes}:${paddedSeconds} ${morningOrEvening}`;

  requestAnimationFrame(timer);
}
timer();

We have the paddedSeconds and paddedMinutes variables that now store the appropriately padded values respectively for seconds and minutes. Notice that we are converting our original seconds and minutes variables into a string by using String(value) before calling padStart. This is because padStart only works on strings. Calling it on a number, which is what seconds and minutes originally are won't work.

And with this last change, we are done! The final markup and code for our digital clock is as follows:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Digital Clock</title>
  <style>
    body {
      display: grid;
      place-content: center;
      height: 100vh;
      margin: 0;
      padding: 0;
      background-color: #EEE;
    }

    #timerField {
      font-size: 72px;
      font-family: "Courier New", monospace;
      background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%,
          rgba(255, 255, 255, 0) 53%,
          #CFBFF7 53%,
          #CFBFF7 100%);
      padding-left: 20px;
      padding-right: 20px;
    }
  </style>
</head>

<body>
  <p id="timerField">12:10:45 AM</p>

  <script>
    let timerPlace = document.querySelector("#timerField");
    let morningOrEvening = "";

    function timer() {
      let date = new Date();

      let seconds = date.getSeconds();
      let hours = date.getHours();
      let minutes = date.getMinutes();

      // Is it AM or PM?
      if (hours >= 12) {
        morningOrEvening = "PM";
      } else {
        morningOrEvening = "AM";
      }

      // Normalize to the 12 hour clock
      if (hours > 12) {
        hours -= 12;
      }

      // Ensure second and minutes values are two digits
      let paddedSeconds = String(seconds).padStart(2, "0");
      let paddedMinutes = String(minutes).padStart(2, "0");

      timerField.textContent = `${hours}:${paddedMinutes}:${paddedSeconds} ${morningOrEvening}`;

      requestAnimationFrame(timer);
    }
    timer();
  </script>
</body>

</html>

If you go back to the browser and check what we have, you will see our digital clock looking (and working!) exactly like the version of the clock we started off this article with. If something looks off, definitely take a look at the final code above with what you have to see where something has gone astray.

Conclusion

A digital clock may not seem like the most exciting thing to create, but it does contain a lot of interesting and useful techniques that we should be comfortable with. As part of building out this example, I hope you were able to reinforce some things you already knew and maybe even learn a few new things as well. I know I certainly learned something new, for the padStart method wasn't one that I realized was so broadly available across all the browsers.

Got a question or just want to chat? Comment below or drop by our forums (they are actually the same thing!) where a bunch of the friendliest people you'll ever run into will be happy to help you out!

When Kirupa isn’t busy writing about himself in 3rd person, he is practicing social distancing…even on his Twitter, Facebook, and LinkedIn profiles.

Hit Subscribe to get cool tips, tricks, selfies, and more personally hand-delivered to your inbox.

COMMENTS

Serving you freshly baked content since 1998!
Killer hosting by (mt) mediatemple

Twitter Youtube Facebook Pinterest Instagram Github