-1

A component in our app allows the user to input their birthdate and then, later, display it again. It works for most cases, but there is a problem for some use cases, I suspect because of Daylight Savings Time.

I am sending the date to the backend in ISO format (UTC time) and receiving it also in ISO format, but with relative time. Example (8. 8. 2000):

sending: 2000-08-07T22:00:00.000Z
receiving: 2000-08-08T00:00:00+02:00

For some dates, the returned date is one day lower. Example (8. 8. 1977, becomes 7. 8. 1977):

sending: 1977-08-07T23:00:00.000Z
receiving: 1977-08-08T00:00:00+02:00

I have a theory that it's because the client and server use different locales - which have historically observed DST differently. I am based in the Czech Republic, and the country hasn't observed DST in 1977.

How can I fix this problem? If my theory is correct, how do I find out what locales are being used and how do I set the frontend/client one?

Thanks in advance!

Barruzi
  • 163
  • 2
  • 8
  • You can always send just the date itself back and forth (ISO 8601 is YYYY-MM-DD). But as a test simply pick a time in the middle of the day, any time that adding or subtracting an hour won't affect the day and try that. For example 10am. – imvain2 Apr 29 '19 at 17:35
  • 1
    the pairs of dates in your two example actually both have identical dates, just in different formats. in short, nothing is wrong, all 4 dates are all accurate. you need to serialize the date in a locale-aware output in order to get the date back in a locale-specific time. once you do that, you'll see the dates are the same, even if they look shifted when recorded in UTC. – dandavis Apr 29 '19 at 17:44
  • The two date are the same, except that first has the TimeZone at the middle of the string, where received has TZ at the end. You need to choose which one you will use. – Marco Apr 29 '19 at 17:46

2 Answers2

2

You don't want to have to be aware of locales ! We're talking about dates. You need to construct and transmit your dates so that locale never becomes a problem. To do this, your dates need to represent midnight UTC. Looking at your examples, neither your sending nor receiving dates fit this condition, so I think you risk to go insane.

Hopefully this answer will have useful information for you.

bbsimonbb
  • 27,056
  • 15
  • 80
  • 110
  • Thanks, the answer you linked helped a lot! – Barruzi Apr 30 '19 at 12:53
  • This is not an answer. If the referenced answer answers this question, you should mark this question as a duplicate. If the OP only wants to deal with date and not time, they should transmit only dates, not times. In half the world, "midnight UTC" is a different date to the current local date for the period of the timezone offset. – RobG May 01 '19 at 22:08
1

If you only want to deal in dates, then do not use the time component, only transmit dates, e.g. 2000-08-07.

Unfortunately, the TC39 made a bad decision in deciding that the ISO 8601 date only format YYYY-MM-DD should be parsed as UTC instead of following ISO 8601 and treating it as local. The decision seems to have been a commercially motivated rather than following common sense.

But regardless, you can send and receive the date in ISO 8601 date–only format by parsing and creating the date yourself. It's only a couple of lines of code and has been answered many time elsewhere, but here are some simple functions:

function parseISODate(s) {
  var [y, m, d] = s.split(/\D/);
  return new Date(y, m-1, d);
}
function formatISODate(date) {
  let z = n => (n<10?'0':'')+n;
  return date.getFullYear() + '-' +
         z(date.getMonth()+1) + '-' +
         date.getDate();
}

let s = '2000-08-31';
let d = parseISODate(s);
console.log(d.toLocaleString());
console.log(formatISODate(d));
RobG
  • 142,382
  • 31
  • 172
  • 209