Working with Time in JavaScript

The Date Object

In JavaScript, we can call on the Date object to generate a generic Date.

However, the object is a number in milliseconds since midnight of January 1, 1970 (UTC).

It is like this, to make sure we have a universal and timezone-independent way of calculating time.

Date Methods

To generate a Date object, we can generate it like so:

new Date()        // UTC date + time
// 28th of August, 2025, 3.30
// (note that August = 7)
new Date(2025, 7, 28, 3, 30)
Date()            // Local time string
Date.now()        // Unix timestamp
                  // (ms since Jan 1, 1970)

Getting Current Month

When we call on the Date.getMonth() method, it returns a numbers, representing the index in an array of 12 Months, starting at January - which means to access April, we call upon monthNames[3].

// Manual array approach
const monthNames = [
  "January", "February", "March",
  "April", "May", "June", "July",
  "August", "September", "October",
  "November", "December"
];

app.get('/months/v1', (req, res) => {
  // 0-11
  const today = new Date().getMonth();
  res.send(monthNames[today]);
});

If we don't have a hardcoded array of month names, we can call on the method toLocaleString().

// Using toLocaleString
app.get('/months/v2', (req, res) => {
  const currentMonth = new Date()
    .toLocaleString('en-uk', { month: 'long' });
  res.send({ data: currentMonth });
});

Unix Timestamp Counter

In an assignement with the dogma "Time", I created a new epoch for the unix counter, dated at my son's birth. In order to do so, I had to first generate a Date object, then in a function make const elapsedTimeUnix, which I then updated every second with setInterval() to generate a counter.

const newUnix = new Date(2025, 7, 28, 3, 30).getTime();

function getTimeSinceBirthInUnix() {
  const elapsedTimeUnix = Math.floor(
    (Date.now() - newUnix) / 1000
  );
  unixCounter.textContent = elapsedTimeUnix;
}

// Updates every second
setInterval(getTimeSinceBirthInUnix, 1000);

Fetch API

Introduction to Fetch

In our frontend, we can utilize the fetch() method, for making HTTP requests to our server and process the responses.

The metod starts the process of fetching a resource from a network, which then returns a promise, that gets fulfilled once the response is available.

Handling Responses

When requesting a resource, we expect a response from the server, that's where the .then() method comes in When the promise has been resolved, .then() takes the raw response and calls .json(), which parses it to a JSON string - this also returns a promise, which is why there is a second .then().

The second .then() recieves the parsed JavaScript object (data) and logs it to the console.

Basic Fetch Request

fetch('/movies')
  .then(response => response.json())
  .then(data => console.log(data));

POST Request

If you do not set a HTTP-verb for the method, it will default to GET, however, you can use the method: option to use a different type of request.

After defining the verb, you can set the headers and then the body, which is the actual payload of the request.

This is very useful when we want to send data to a server, in this instance we want to send a JSON object, containing a Movie.

fetch('/movies', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'New Movie',
    description: 'Description'
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

JavaScript and HTML Integration

The Document Object Model (DOM)

The DOM (Document Object Model) is an API that represents the HTML page as a tree of objects - we can use JavaScript to access these objects and modify them in memory. The DOM tree consists of nodes, where each of these nodes represents a part of the document.

The DOM is not part of the JavaScript language - it was designed to be independent of any language, and therefore we can theoretically use any langauge to access it, since it is available from a single API.

DOM Manipulation In Practice

In this example, JavaScript updates the text inside an HTML element, whenever the function runs, meaning that the page can change, without it being reloaded.

document represents the HTML page - but the .getElementById() is a DOM method, which finds and returns the HTML element with the given id.

DOM Manipulation In Practice

const counter =
  document.getElementById('guest-book-counter');
let counterValue = 0;

function incrementCounter() {
  counter.textContent = ++counterValue;
}

Event Handling

The incrementCounter function demonstrates how to update DOM elements dynamically, typically triggered by user events.

JavaScript Loading

Now that we know we can manipulate the DOM, we need to load the script.

This can be done two ways: Inline or External.

The first example, is using Inline. This can be fine for small or few lines of scripts since it is laoded directly into the HTML file.

Second example is by calling upon a JavaScript file - this is great when we have a bunch of logic, which we then can divide into separate modules or files, granting us with a better overview of scripting. We are required to think more about our architecural decision in our project, but granted that, we have improved maintainability and readability by moving it into an external script.

// Inline (avoid mixing)
<script> /* code */ </script>

// External (preferred)
<script src="./frontpage.js"></script>

Server Setup and Error Handling

Previously, when we have set up a server in our Node.js backend, we did it by only using app.listen(8080).

While this can be fine, it can be better to have a more verbose method, not only telling us if the server is running, but also if the server failed to start, giving us a much faster failure response.

To do so, we need to create a callback function to app.listen, and parse error as a paramter to the function. If something goes wrong, the error object will contain information about the problem.

Inside the callback, if error exists, we log an error - if not, we log that the Server is running on port 8080

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.sendFile(
    __dirname + '/public/frontpage.html'
  );
});

app.listen(8080, (error) => {
  if (error) {
    console.log('Error starting the server');
    return;
  }
  console.log('Server is running on port', 8080);
});

Error Handling and Validation

Falsy Values

JavaScript treats these as false in conditionals:

  • false
  • null
  • undefined
  • NaN (not a number)
  • "" (empty string)
  • 0

Truthy Checks in Practice

if (error) {  // Truthy check
  console.log('Error occurred');
  return;
}

Deployment

Whenever we are developing an app, when we want to access it, it can only run on localhost. We might want to make that publicly available, and that's where deployment comes in.

There are several ways of deploying an application, ranging from incredibly simple to very advanced, depending on what you need.

Is it a single static page with no database? Use Vercel or GitHub Pages. Are you deploying a full-scale application with many microservices and high user load? Use a cloud provider like AWS, Azure, or orchestrate containers with Docker and Kubernetes.

Simple Deployment With Vercel

However, so far we have only made small applications without databases or any complex infrastructure, which makes Vercel a great fit. Vercel is a cloud platform that lets us deploy Node.js and frontend projects with minimal configuration, it utilizes serverless computing, which means it will only spin up a VM, when there is a request for the page.

To deploy with Vercel, we can register at their website, connect our GitHub account and deploy within minutes.

Vercel integrates really well with GitHub, which means that pushing to a repository can automatically trigger a new deployment, so every time we push new code, our live site updates as well.