3

This question is related to this question.

So if we construct a date using an ISO string like this:

new Date("2000-01-01")

Depending on what timezone we are in, we might get a different year and day.

I need to be able to construct dates in Javascript that that always have the correct year, day, and month indicated in a string like 2000-01-01, and based on the answer in one of the questions if we use back slashes instead like this:

const d = new Date("2000/01/01")

Then we will always get the right year, day, and month when using the corresponding date API methods like this:

d2.getDate();
d2.getDay();
d2.getMonth();
d2.getFullYear();

So I just wanted to verify that my understanding is correct?

Ultimately I need to be able to create Date instances like this for example:

const d3 = new Date('2010/01/01');
d3.setHours(0, 0, 0, 0);

And the time components should always be zero, and the year, month, and day should be the numbers specified in the string.

Thoughts?

I just did a quick test with this: https://stackblitz.com/edit/typescript-eztrai

const date = new Date('2000/01/01');
console.log(`The day is ${date.getDate()}`);
const date1 = new Date('2000-01-01');
console.log(`The day is ${date1.getDate()}`);

And it logs this:

The day is 1
The day is 31

So it seems like using backslashes should work ...

Or perhaps using the year, month (0 based index), and day constructor values like this:

const date3 = new Date(2000, 0, 1);
date3.setHours(0, 0, 0, 0);
console.log(`The day is ${date3.getDate()}`);
console.log(`The date string is ${date3.toDateString()}`);
console.log(`The ISO string is ${date3.toISOString()}`);
console.log(`Get month ${date3.getMonth()} `);
console.log(`Get year ${date3.getFullYear()} `);
console.log(`Get day ${date3.getDate()} `);

NOTE

Runar mentioned something really important in the accepted answer comments. To get consistent results when using the Javascript Date API use methods like getUTCDate(). Which will give us 1 if the date string is 2000-01-01. The getDate() method could give us a different number ...

Ole
  • 41,793
  • 59
  • 191
  • 359
  • So you want the `Date` object to be created in the users current timezone (instead of UTC as in the first snippet)? Couldn't you just attach a `"T00:00"` to it to force it to be parsed that way? – UnholySheep Dec 25 '21 at 16:31
  • I guess you want (new Date("2000-01-01")).toISOString() – digitalniweb Dec 25 '21 at 16:32
  • 1
    If you want to store just the day, month, and year without timezone or time, I wouldn't use a `Date`. Just make a custom object. – skara9 Dec 25 '21 at 16:34
  • Well ... One of the questions said that if we use `2000/01/01`, then we always will get the right year, month, and day from the Javascript API ... so just wanted to confirm that this is the case ... – Ole Dec 25 '21 at 16:36
  • 1
    Everything seems well explained in this impressive article https://codeofmatt.com/javascript-date-parsing-changes-in-es6/ and yes, a library like moment.js makes it quite trivial: `moment("yyyy-mm-dd")` (local) vs `moment.utc("yyyy-mm-dd")` (UTC) – Roko C. Buljan Dec 25 '21 at 16:42
  • First time I've ever heard of the difference between `/` and `-` doing that. They do however seem to produce different values in a Date object. Some years ago ( in this decade) different browsers would not parse both of those formats. Storing UTC strings or timestamps has always been reliable – charlietfl Dec 25 '21 at 16:42
  • I agree with @skara9. Something like `const [year, month, day] = "2000/01/01".split("/").map(Number); const d = {year, month, day};` – Aluan Haddad Dec 25 '21 at 16:43
  • Well ... I have to be able to create `Date` instances from the string, so that I can call `getTime()` on the instances. The only requirement is that the `year` `month` and `day` have to be consistent always ... – Ole Dec 25 '21 at 16:48
  • year / month /day consistent for storage or display? If you store UTC values you always know what you are starting from. If the spec was changed that using `/` makes them UTC then so be it – charlietfl Dec 25 '21 at 16:50
  • Consistent from the ability to create Date instances that always have the `year`, `day`, and `month` indicated in the string ... – Ole Dec 25 '21 at 16:51
  • I'm starting to think that perhaps the only way to guarantee this is to parse the values from the string and use the Javascript API to set the components directory ... like `const d = new Date(); d.setFullYear(2000` ... – Ole Dec 25 '21 at 16:53
  • new Date() defaults as local .... (new Date()).toISOString() will produce same year/ month/day when run in any timezone as it is UTC time – charlietfl Dec 25 '21 at 16:57
  • Yeah ... I just tried the setting the values directly idea... and that does not provide consistent values either ... – Ole Dec 25 '21 at 16:59

1 Answers1

3

From the ECMA standard of the Date.parse method:

When the UTC offset representation is absent, date-only forms are interpreted as a UTC time and date-time forms are interpreted as a local time.

What is happening is that New Date() implicitly calls Date.parse on the string. The "2000-01-01" version conforms to a Date Time String Format with a missing offset representation, so it is assumed you mean UTC.

When you use "2000/01/01" as input the standard has this to say:

If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats.

So in short the browser can do what they want. And in your case it assumes you mean the offset of the local time, so whichever offset you are located in gets added when you convert to UTC.

For consistent results, perhaps you want to take a look at Date.UTC

new Date(Date.UTC(2000, 0, 1))

If you need to pass in an ISO string make sure you include the time offset of +00:00 (is often abbreviated with z)

new Date("2000-01-01T00:00:00Z");

If you want to later set the date to something different, use an equivalent UTC setter method (e.g. setUTCHours).

When you retrieve the date, also make sure to use the UTC getter methods (e.g. getUTCMonth).

const date = new Date("2000-01-01T00:00:00Z");

console.log(date.getUTCDate());
console.log(date.getUTCMonth());
console.log(date.getUTCFullYear());

If you want to retrieve the date in a specific format you can take a look at Intl.DatTimeFormat, just remember to pass in timeZone: "UTC" to the options.

const date = new Date("2000-01-01T00:00:00Z");
const dateTimeFormat =
  new Intl.DateTimeFormat("en-GB", { timeZone: "UTC" });

console.log(dateTimeFormat.format(date));
Rúnar Berg
  • 4,229
  • 1
  • 22
  • 38
  • So if I have strings like `2000-01-01` just append `T00:00:00Z` and the dates will always be consistent? – Ole Dec 25 '21 at 21:33
  • Yes, although according to the standard the short `2000-01-01` it is basically the same as `2000-01-01T00:00:00Z`, although the latter is more explicit. – Rúnar Berg Dec 25 '21 at 21:35
  • Hmm ... I just tested logging this: `const startDate = new Date('2010-10-20T00:00:00Z')` and getting the day like this `console.log('THE DAY IS: ', startDate.getDate());` and it still gives me `19`, so it looks like using the constructor parameters like this `new Date(Date.UTC(2000, 0, 1))` is the only thing that is safe ... – Ole Dec 25 '21 at 21:38
  • Yes, you want to use the UTC getters `startDate.getUTCDate()` for consistent results. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCDate – Rúnar Berg Dec 25 '21 at 21:40