Forcing Date() constructor argument time zone interpretation - javascript

I have an use case where I use input from the user, which is on the form YYYY-MM-DD'T'TT:mm to create a Date object in Javascript. The problem is that Firefox and Chrome interpret the input as the local time (which is what I want), whilst Safari interprets the input as UTC time and converts it to local. How do I force Safari to use the same interpretation of the input as the other two?

The simplest way is to parse the string yourself (it's trivial, after all) and use the multiple-argument Date constructor, which always works in local time. Or use a library like Moment.js to do it for you. I was tempted to suggest adding a timezone offset (+0400, etc.) to the string (based on getTimezoneOffset on a Date object), but determining the right timezone offset requires that you know the date/time (because of Daylight Savings Time), and so...you'd have to do the work anyway.

Related

Javascript convert string to date, but ignore the timezone that is assumed it's in

A really long title, I know, but I had to highlight the fact, that I'm confronting a situation that's a little different than all the usual javascript date conversions.
I am getting the following datetime in a string from the server:
2017-05-18T08:00:00
When I put this string into the following statement:
var newDate = new Date("2017-05-18T08:00:00");
It assumes it's in the UTC timezone, so it automatically adjusts, and converts it into local time, which in Sidney would become 2017/05/18 18:00:00.
Any way that I can stop the date constructor to assume that the string is UTC time (make it assume that it's local time)?
use getTimezoneOffset() function to adjust timezone. By default Date converts it to local timezone :(
If you're applying your code in serious applications, consider a tool like Moment.js

new Date('yyyy-MM-ddTHH:mm:ss') without locale

I am based in the UK so when I attempt to parse a new date in JavaScript as follows:
new Date('2016-06-03T09:05:15');
Results in the following date:
Fri Jun 03 2016 10:05:15 GMT+0100 (BST)
I want the date to be parsed as is, and for no locale adjustments (in this instance, BST) to occur. Is this achievable without writing my own date/time parser?
I want the date to be parsed as is, and for no locale adjustments (in this instance, BST) to occur
That is exactly what should occur, however it doesn't in all browsers. You should not parse strings using the Date constructor or Date.parse (they are equivalent for parsing). Always manually parse strings, a library can help but usually isn't necessary.
According to EMCAScript 2015, '2016-06-03T09:05:15' should be parsed as a "local" date (i.e. based on the host system settings for date, time and time zone on the date and time supplied). A Date object's time value is UTC, so when creating the time value, the host settings are taken into consideration. The same settings are also used for output, so if the OP string is correctly parsed and then written to output, you should get back exactly the same date and time (though probably in a different format).
If you're seeing a different time from the input string, then the string isn't being correctly parsed (hence advice to manually parse strings).
Is this achievable without writing my own date/time parser?
Yes, use a library that someone else wrote. However, if you also want host settings to be ignored for output, you'll also need to write your own formatter, or use a library.
The good news is that there are many to choose from.

Strange behavior formatting moment.js date

We are tracking down a bug in our application that seemingly is related to moment.js formatting.
Here's the problematic call (reproduced in Chrome, FF, and Edge, for reference):
moment('2016-03-13T23:59:59.999-06:00').format('YYYY-MM-DD')
What we expect:
2016-03-13
What we get:
2016-03-14
This seemingly has something to do with daylight savings time as this is the only date (so far) that we've been able to reproduce this incorrect behavior on and DST flipped on that day.
If we switch the UTC offset to -05:00 then it works properly.
Here's a simple JSBIN to demonstrate
What's going on here? How can we address this?
Moment will convert a date with an offset to the local time zone of the computer that you are on, if you use the default moment constructor function.
For this reason, your code is working as expected. The date is taken from -6 and converted to your local offset.
If you want to use the date in the timezone offset specified, use moment.parseZone:
moment.parseZone('2016-03-13T23:59:59.999-06:00').format()
"2016-03-13T23:59:59-06:00"
If you want to ignore the timezone offset, and work in local time, specify a format that does not include the offset. By doing this, you cause the offset to be ignored.
moment('2016-03-13T23:59:59.999-06:00', 'YYYY-MM-DDTHH:mm:ss.SSS').format()
"2016-03-13T23:59:59-05:00"
Note that I am in UTC-5 and the offset is displayed as -5 because I ignored the offset in the date.
The parsing guide may be of some help:
http://momentjs.com/guides/#/parsing/
In the momentjs documentation regarding parsing with time zones, they show that in order to take into account the specified time zone in the input string you should be using moment.parseZone().
console.log(moment.parseZone('2016-03-13T23:59:59.999-06:00').format('YYYY-MM-DD'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.min.js"></script>
The above output "2016-03-13" on the console for me.
You are specifying a time zone on encoding (-6) yet are relying on the client time zone for formatting. The difference is the culprit.
Basically there's nothing wrong with the moment's format function.
console.log(moment.utc('2016-03-13T23:59:59.999-06:00').toString());
console.log(moment('2016-03-13T23:59:59.999-06:00').toString());
If you try to execute both of the above lines, you'll see that moment.utc() basically takes off the offset and converts it to the UTC time note the time, not just the date and moment() translates -06:00 offset to your local timezone and if you have smaller offset, you basically get the wrong date, because of the time.
Hope I helped.

Initialize a Moment with the timezone offset that I created it with

I'm using moment and moment-timezone in javascript, and this part of it is one of the most unintuitive API's I've ever seen.
I would expect that:
moment("2015-12-14T04:00:00Z").utcOffset()
would be a pure function and return the offset included in the argument, which is 0. But instead it implicitly converts it to my local timezone offset (PST), so this returns -480 Why?? I asked what offset the object i just created has, not what offset I'm currently in. It would be like if I wrote an api where calling User.find(123).name() returns your name instead of the name of user 123.
Anyway, I can do
moment("2015-12-14T04:00:00Z").tz("utc").utcOffset()
But my datetime string is dynamic, so I don't know the timezone.
How can I get the behavior I expected, a Moment in js that is in the timezone offset included in the string i passed in?
Use parseZone to keep the offset as it was passed in.
moment.parseZone("2015-12-14T04:00:00Z")
As to the "why?" part of your question:
moment(...) is local mode. Ambiguous input (without offset) is assumed to be local time. Unambiguous input (with offset) is adjusted to local time.
moment.utc(...) is utc mode. Ambiguous input is assumed to be UTC. Unambiguous input is adjusted to UTC.
moment.parseZone() keep the input zone passed in. If the input is ambiguous, it is the same as local mode.
moment.tz(...) with the moment-timezone plugin can parse input in a specific time zone.
Keep in mind that moment has to contend with a wide variety of inputs.
Also keep in mind that a time zone and a time zone offset are two different things. An offset of -08:00 doesn't necessarily mean you are in the US Pacific time zone.

Convert timestamp with specified offset for timezone with Date();

I've been digging through as many things as I can find, and I can't seem to find what it is I am looking for, so I am coming to the conclusion that I either don't know what I am looking for or its not possible. Either way..
What I am trying to achieve is taking a timestamp example: 1373439600000 and a given offset of -12 to 12 (is that correct, as far as range goes?) so I can then take that timestamp above subtract from it accordingly, and pass that new timestamp to the Date() function so I can then manipulate it for human readable display.
The offset is two part, It is user specified in one instance while in the other it is going to default to the local getTimezoneOffset() if not specified. So trying to figure out how to take that range and work with that. To do everything accordingly.
Ideas? Am I even approaching this in a correct manor?
The timestamps I am working with are already UTC, not sure of that makes a difference.
The JavaScript Date type has many problems, but one of its major quirks is that it only understands two time zones - UTC, or Local. It uses UTC internally and in certain properties and functions like .toUTCString(), but otherwise it uses the local time zone.
Many browsers will accept an offset when parsing a Date from a string, but that will just be used to set the UTC time. Anything on the way out will be converted back to the local time zone again.
Fortunately, there are some great libraries out there for working around these problems. Moment.js is perfectly suited for this. Here is an example of what you might be looking for:
moment(1373439600000).zone(8).format("YYYY-MM-DD HH:mm:ss Z")
// output: "2013-07-09 23:00:00 -08:00"
Of course, you can format as needed, or pass in a more complex zone offset like "+05:30". And if you need to use an actual IANA time zone, there is the moment-timezone companion project, which you could do something like this:
moment(1373439600000).tz('America/New_York').format("YYYY-MM-DD HH:mm:ss Z")
// output: "2013-07-10 03:00:00 -04:00"
Unfortunately the Date object does not provide may facilities for working with timezones. If you have the offset though, you should be able to compute the offset in milliseconds. Then you can add (subtract?) that value to your timestamp and use it to construct the appropriate Date.
Does that help?

Categories

Resources