Working with Time in Javascript Applications
Intro
If you are building an application at some point it's likely you will have to deal with the concept of time. You may need to synchronize actions across various systems, you may need to fetch data in a specific time range, the list goes on.
UTC
The crux of the problem is that people all over the world use different timezones, daylight savings time, etc etc.
The first and most important concept to understand is that we need to use a synchronized clock, no matter what part of the world a user, or server is located in. That synchronized time is called Coordinated Universal Time or UTC.
Anytime you create a timestamp in your application, or schedule an event, or serve data with dates, it should always be UTC. That way the time is the time, no matter what. This time should be stored and transferred in ISO 8601 format. Ex: 2017-05-15T13:30:34Z
.
Showing Local Time
If we use UTC for all dates, you can simply convert UTC into the local timezone for a user at the last moment. Local timezones are typically detected by the browser, and then can be quickly converted with the use of a library.
Time Libraries
So how do we actually do this?
It is possible to use built in Javascript time calculations and formatting.
For example if we wanted to get yesterdays date in YYYYMMDD format we could do the following
// get yesterdays date in timeformat YYYYMMDD
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
let isodate = yesterday.toISOString().split('T')[0];
let finaldate = isodate.replace(/-/g,"");
return finaldate;
// "20220515"
It's not very semantic is it? Fortunately there are some very good libraries that make dealing with time much easier.
Moment.js
For many years Moment.js was the defacto library for dealing with time. For a long time it was completely essential because those native Date()
methods didn't even exist. Now however Moment.js is outdated, and they will be the first ones to tell you so.
They have a list of recommended alternatives, the first of which is Luxon.
Luxon.js
This is going to be the new defacto time library in my opinion. Written by one of the Moment.js contributors to take advantage of the new nate Date()
functions. Tons of features, and well supported.
Let's take a look at a couple of examples using Luxon.
Generate UTC
Let's generate a UTC date and then view it in four different formats.
const { DateTime } = require("luxon");
let today = DateTime.utc();
console.log(today);
console.log(today.toISO());
console.log(JSON.stringify(today));
console.log(Date.parse(today));
Date Formats
Object
The first item is just the raw object that Luxon creates. It notes the unix timestamp and other information that is useful for Luxons methods.
ISO
One of those methods for example is converting the time to ISO format.
2022-05-16T18:28:52.464Z
Remember, this is the preferred format for storing and transferring time data.
String
We can also use the native JSON.stringify
method, which curiously does not stringify the whole object, but outputs a string of the ISO format.
"2022-05-16T18:28:52.464Z"
Timestamp
And lastly the native Date.parse()
method which just returns the unix timestamp.
1652725732464
The unix timestamp is the number of seconds that have elapsed since January 1st, 1970 at UTC.
It is very handy to know the methods to convert the date, because it can only be consumed in certain formats in certain situations.
Display Format
Changing the display format is easy with Luxon. For example I have a specific application that requires the date to be in YYYYMMDD format. So I can simply do the following.
let todayYYYYMMDD = DateTime.utc().toFormat("yyyyMMdd");
console.log(todayYYYYMMDD);
// 20220516
There are many many options for display formatting.
Convert to Local Time
Luxon can easily convert to local time with the .toLocal()
method. It uses your system settings to determine your locale and timezone.
let todayLocal = DateTime.utc().toLocal();
console.log(todayLocal);
Which then returns the Luxon date object we learned about earlier.
And we now know how to convert this object to other formats.
Past Dates
What if we wanted to specify a date in the past or future? Very easy.
let fiveDaysAgo = DateTime.utc().minus({days: 5}).toISO();
console.log(fiveDaysAgo)
// 2022-05-11T19:14:59.794Z
let verySpecificFutureTime = DateTime.utc().plus({ years: 10, months: 2, days: 5, hours: 12, minutes: 13, seconds: 59}).toISO();
console.log(verySpecificFutureTime);
// 2032-07-22T07:31:38.437Z
Past Date at Specific Time
Additionally we can generate a past date at a specific time, for example midnight is a common time. Specifying a past date is pretty easy if we know the exact date. But what if we just want a function that gives us days from today, whatever today is?
function generatePastDateMidnightISOUTC(daysAgo) {
let now = DateTime.now();
let currentYear = now.year;
let currentMonth = now.month;
let currentDay = now.day;
let currentDateMidnightUTC = DateTime.utc(
currentYear,
currentMonth,
currentDay
);
let pastDateMidnightUTC = currentDateMidnightUTC.minus({ days: daysAgo });
let pastDateMidnightISOUTC = pastDateMidnightUTC.toISO();
return pastDateMidnightISOUTC;
}
First we get the current date, then we extract the year month and day from that. We use that to generate a Datetime of UTC Midnight today. Then we subtract the number of days. Lastly we can convert that to ISO.
Conclusions
- Dates should be in UTC
- Preferred storage and transfer format is ISO
- Convert to local time only for display in the client
- Use Luxon library
Comments
Recent Work
Basalt
basalt.softwareFree desktop AI Chat client, designed for developers and businesses. Unlocks advanced model settings only available in the API. Includes quality of life features like custom syntax highlighting.
BidBear
bidbear.ioBidbear is a report automation tool. It downloads Amazon Seller and Advertising reports, daily, to a private database. It then merges and formats the data into beautiful, on demand, exportable performance reports.