0

I'm building a web app where I need to store the user's birthday in the database and then display it on their profile. Naturally, birthdays shouldn't depend on the timezone.

My problem is on the javascript client, the new Date() object operates on the user's local timezone even if the underlying date is in UTC.

If the user is in the GMT+02:00 timezone and selects a birthday of January 1, 2000 00:00, that date in UTC will be December 31, 1999 23:00.

The problem is displaying that date back to the user on their profile. What if the user suddenly travels to a different timezone, say GMT-05:00 and looks at their profile? They will see December 31, 1999 as their birthday.

How does one deal with dates that should be the same regardless of timezone within a Javascript frontend and a server? In what format should they be stored in the database? And how do you display them indifferent of current timezone?

Darius Mandres
  • 778
  • 1
  • 13
  • 31

2 Answers2

1

Unfortunately ECMAScript parses ISO 8601 date–only forms as UTC, but you can easily parse them as local with a simple function. Store the dates however you want, but send an ISO 8601 date–only timestamp to the client like "2020-09-23", then parse and display as local, e.g.

function parseISOLocal(s) {
  let [y, m, d] = s.split('-');
  return new Date(y, m-1, d);
}

let timestamp = '2020-09-23';

// Wed Sep 23 2020 or similar
console.log(parseISOLocal(timestamp).toDateString());
RobG
  • 142,382
  • 31
  • 172
  • 209
  • I would make the hour be 12 (noon) rather than the default 0, in order to avoid possible glitches caused by Daylight Saving Time changes happening at night. I'd do it thus: `new Date(y, m-1, d, 12)` – Robert Lozyniak Sep 24 '20 at 00:51
  • @RobertLozyniak—there is no scenario where daylight saving will change a date constructed using year, month and day values. – RobG Sep 24 '20 at 10:26
0

The way I ended up approaching it is slightly similar to @RobG's answer.

I created this function to convert my date object to yyyy-mm-dd, based on the user's local timezone:

export const formatDateISO = (date: Date) => {
  let month = "" + (date.getMonth() + 1);
  let day = "" + date.getDate();
  let year = date.getFullYear();

  if (month.length < 2) month = "0" + month;
  if (day.length < 2) day = "0" + day;

  return [year, month, day].join("-");
};

In the backend, I converted that to yyyy-mm-dd 00:00 UTC and got the unix timestamp for it, which I stored in the database.

To display the value back to the user, I used:

new Date(unixTimestamp * 1000).toLocaleDateString('en-US', { timezone: 'UTC' })

This way, the user selects a date based on their timezone, and that gets translated to a 00:00 UTC timestamp in the database.

Note: This only works for use cases where you want to display the same date no matter the time zone. Usually, this is not what you want.

You usually want to display the time converted to the user's local timezone, e.g. an online event's date and time should be according to the user's timezone. A birthday should not.

Darius Mandres
  • 778
  • 1
  • 13
  • 31