Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing handling of date inputs in JavaScript regardless of time zone

I have a form where a user can enter a date, i.e. <input type="date"> the value is submitted in yyyy-MM-dd format. When I create a Date object with the string it assumes the time zone is the one the user's browser is set to – this is the behavior I want.

I'm then using the date value to make queries against a REST API that expects ISO date/time strings. That's no problem as the toISOString function on the Date object handles everything correctly.

However, when I'm unit testing this code – setting my input to a yyyy-MM-dd string then asserting that the output is an expected ISO timestamp string the tests can only work in a particular time zone. Is there a way I can force the time zone in the test?

I've tried using Jasmine spies to do something like:

var fixedTime = moment().zone(60).toDate()
spyOn(window, 'Date').andCallFake(function() {
    return fixedTime;
});

But given there are so many variants of the constructor and so many ways it gets called by moment.js this is pretty impractical and is getting me into infinite loops.

like image 964
Rob Fletcher Avatar asked Sep 19 '13 10:09

Rob Fletcher


1 Answers

A JavaScript Date cannot be set to a particular time zone. It only knows about UTC and the computer's local time from the environment it is running on.

There are time zone libraries for javascript, but I don't think that will help you here.

First, understand that "ISO" refers to ISO8601, which is a specification that defines a collection of related formats, such as YYYY-MM-DDTHH:MM:SS.

It is a separate concept from UTC, which refers to Universal Coordinated Time. UTC is the timekeeping system that we all synchronize our clocks to, which uses GMT as its basis - that is, the time in effect at the prime meridian not adjusted for daylight saving time.

Put together, the Date.toISOString() method will return the UTC form of an ISO8601 formatted timestamp, such as 2013-09-20T01:23:45Z. The Z at the end indicates that the time is in UTC.

But a value such as 2013-09-20 is still ISO formatted - it's just that it only has precision to the whole day, which means that it can't carry any time zone information.

When you use <input type="date">, the resulting value is not a Date class. It's a string containing the ISO formatted YYYY-MM-DD. You should just pass this directly to your application.

Now if what you are looking for is the full date and time, at midnight in the local time zone, of the date selected, and adjusted to UTC, well that's a different story. It is certainly doable but you have to understand that it is not the same as just passing the calendar date.

The easiest way to do that would be with moment.js as follows:

var s = "2013-09-20";  // from your input's value property
var m = moment(s);
var result = m.toISOString();  // "2013-09-20T07:00:00.000Z"

The value is adjusted because my time zone offset is -07:00.

You can do it without moment, but you have to replace dashes with slashes or the original value will be interpreted as if it is already in UTC.

new Date(s.replace('-','/')).toISOString()
like image 161
Matt Johnson-Pint Avatar answered Sep 28 '22 08:09

Matt Johnson-Pint