Stephen Last
Stephen Last

Reputation: 5781

Formatted dates in Node/JavaScript to UTC

I'm using a Node/Express server to format a date before it's sent to the browser. The date I have is saved in the database as UTC, for example this:

2020-09-15 11:52:22.000

I now want to format this date, without changing it, and send it to browser, so not matter where the Node server is, and not matter where the browser is, it always shows this UTC date. People viewing this date will be in the US, UK, EU, but I'd like them all to see the same UTC date.

I'm in the UK, I'm using date-fns, and I'm running Node locally at the moment. My app already uses date-fns and I don't want to add another date/time dependency just for this one task.

If I do this:

const d = format(new Date('2020-09-15 11:52:22.000'), 'dd MMM yyyy HH:mm:ss')

I get: 15 Sep 2020 12:52:22... That is the date in my local time (UK, BST).

If there is one thing that confuses me, it's dates & times! :-)

In Node, how do I take 2020-09-15 11:52:22.000 and format it to get 15 Sep 2020 11:52:22 ..?

Upvotes: 1

Views: 1506

Answers (3)

RobG
RobG

Reputation: 147403

Your problem is:

new Date('2020-09-15 11:52:22.000')

Using the built–in parser for unsupported formats is strongly discouraged. It's implementation dependent and often returns different results in different implementations.

Also, the string doesn't have a timezone so should be treated as local. So even if parsed correctly it will represent a different instant in time for each place with a different offset.

Date-fns has a capable parser so you should use it instead of the built–in paser. If you want the timestamp to be treated as UTC, the simplest way is to add a trailing "Z" and timezone token for parsing.

To support timezones for output, you have to include date-fns-tz. Following is some code you can run at npm.runkit. The format part appears to produce the correct result, however if a timezone token is added to the format string (i.e. 'X' or 'XX'), it shows the local timezone offset, not the one applied to the string so to show the offset correctly, you have to add it manually (I think this is a bug in date-fns-tz).

const dateFns = require("date-fns");
const { zonedTimeToUtc, utcToZonedTime, format } = require('date-fns-tz');

let timestamp = '2020-09-15 11:52:22.000';
let tz = 'Z';
let date = dateFns.parse(timestamp + tz, 'yyyy-MM-dd HH:mm:ss.SSSX', new Date()); 
// Show timestamp was parsed as UTC
console.log(date.toISOString()); // 2020-09-15T11:52:22.000Z

// Produce UTC output - need to set timezone first
let utcDate = utcToZonedTime(date, 'UTC');
// Manually add timezone to formatted string
console.log(format(utcDate, 'd MMM yyyy HH:mm \'UTC\'', 'UTC')); // 15 Sep 2020 11:52 UTC

Note that utcToZonedTime(date, 'UTC') actually creates a new date modified by the specified offset and assigns it to utcDate, which I think is a real kludge. It's only useful now if you know how it's been modified, you don't know what time it's actually supposed to represent. In this case it might be clear because we're using UTC, but other offsets are much more problematic.

It would save a lot of effort if initial timestamp was in a format that is supported by ECMAScript, e.g. the same as that produced by toISOString: 2020-09-15T11:52:22.000Z.

Upvotes: 2

dna
dna

Reputation: 2317

You can try to do that (my timezone is +2 GTM)

  1. Parse your date to obtain an UTC string
const parsedDate = parse('2020-09-15 11:52:22.000', 'yyyy-MM-dd HH:mm:ss.SSS', new Date()).toUTCString(); 
// Tue, 15 Sep 2020 09:52:22 GMT
// or simply 
// new Date('2020-09-15 11:52:22.000').toUTCString();
    
// format a new date starting from UTC format 
// new Date(parsedDate) --> Tue Sep 15 2020 11:52:22 GMT+0200
const date = format(new Date(parsedDate), 'dd MMM yyyy HH:mm:ss');

the new Date(parsedDate) in format will reconvert utc to your timezone

Upvotes: 0

Suhag Lapani
Suhag Lapani

Reputation: 695

You should use https://momentjs.com/

For example:

moment().format('Do MMMM YYYY, h:mm:ss');

Upvotes: -1

Related Questions