Daylight savings time and JavaScript timezone conversions - javascript

I have this dilemma with JavaScript. I need to convert a list of dates from client's local timezone to NYC (EST) timezone. I'm using the function below:
Date.prototype.toNycTime = function() {
var localTime = this.getTime();
var localOffset = this.getTimezoneOffset() * 60000;
var utc = localTime + localOffset;
this.setTime(utc - 3600000 * 5);
return this;
};
It works OK. One problem is that I need to adjust UTC offset every time there's a daylight saving switch in USA. And that works OK for any date that is before the next switch (earliest coming is 13-MAR-2011). But it doesn't work on dates after the switch. I don't know of any build-in JS function in any of the browsers that will do the conversion for me.
Is there a good library out there that will allow me to do some universal conversions? Or can anyone offer any tips on the code above? I'm trying to avoid programming in the dates/times for the conversion and having to look up all the time.

I'm dealing with this exact problem... corporate users throughout the world, but 'corporate time' is PST/PDT which includes daylight saving time.
How I've been approaching it:
I actually parse a POSIX timezone string for PacificTime starting with
PST8PDT,M3.2.0/2,M11.1.0/2
and reformat those into parseable date strings for when clocks more forward and back.
Using the hours-offset embedded in the TZ string, I convert the forward and back times to epoch timestamps and use an if-then to calculate if corporate time is currently DST.
This yields an offset from UTC I can use to convert local 'epoch' times (which are already in UTC) to a conceptual localtime (that is actually converted in UTC time, but looks local).
I have to do this as 'flot' does everything in UTC

http://www.datejs.com/
Datejs is an open-source JavaScript Date Library.
Comprehensive, yet simple, stealthy and fast. Datejs has passed all trials and is ready to strike. Datejs doesn’t just parse strings, it slices them cleanly in two.

Related

Changing Date time zone in Javascript?

I have a date in UTC format `2020-06-19T03:55:12.000Z. Now i am converting into date of US timezone as
let syncDate = moment(date, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]')
.subtract(7, 'hours')
.format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
This gives me a date 7 hours behind which is date of US. But i want a date in below format
2020-06-18T21:00:24.523-07:00
Here if we can see the hours are defined as -7 so please guide how can we achieve the same ?
You can't extract a timezone out of your date because there is no timezone information in it. You said "I am converting into a date of US timezone as" But you didn't. You just reduced it for 7 hours. The timezone is still UTC.
You should use moment-timezone (not handling things the hard way and manually as #GetSet said). Here the solution:
const moment = require('moment');
const tz = require('moment-timezone');
let date = moment('2020-06-19T03:55:12.000Z');
let syncDate = date.tz('America/Los_Angeles')
console.log(syncDate.format());
But, I suggest you use Day.js. The code will be:
const dayjs = require('dayjs');
const utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
const dDate = dayjs('2020-06-19T03:55:12.000Z');
console.log(dDate.utcOffset(-7*60).format()); //2020-06-18T20:55:12-07:00
I used moment.js in the past. I tried Date-fnd for 24 hours. And finally, I moved to Day.js. It's new (start in late 2018) but it's growing so quick (take a look at this link and put the duration on 5 years). The great thing about it is that "IT ALWAYS DOES WHAT IT SAYS". Moment and Date-fns don't. (not always). It uses a wrapper and so you never work with the Date object directly. It solves difficulties and problems. It's immutable and always returns a new object and you can chain functions. Day.js has the smallest size (2kB).The documentation is awesome and you can up and running very fast. (It's more understandable that the way other libraries work.)
Here I have to say that Dayjs performance is not is good as Moment in calculations but is way better (than especially moment) in parsing and formating.
I strongly suggest you read this article: Why you shouldn't use Moment.js
Edit(1): As #GetSet mentioned in comments for OP that may need a solution in Moment.js I added it to the answer.
Edit(2): Adding the reason why you can't achieve your result the way OP solving it.
new Date() depends on local computer date setup - if any user has wrong date on his local computer - your system will take wrong dates from those users.
If you working with dates on background (storing in database or any other manipulations) - generate it on background (php, java etc.) and than send it to you html/javascript files.
you can use Date().toLocalString() method
// example:
var d = new Date().toLocalString("en-US", {
month: "long",
day: "2-digit",
year: "numeric",
});
for more information see:
https://www.w3schools.com/jsref/jsref_tolocalestring.asp
There are a couple of things it is vitally important to point out here.
There is no one US timezone, there are quite a few, for example America/Los_Angeles, America/Denver, America/Chicago, America/New_York, see the IANA Timezone list for all of them.
Please don't convert from one timezone to another using a fixed offset, this is really fragile. You wouldn't believe how many bugs I've seen in my career (from others, and yes, from myself!) due to this one mistake. Many timezones use Daylight Saving Time, so the UTC offset of the timezone varies by the date. For example, the Pacific Timezone currently varies between UTC-08:00 and UTC-07:00.
I would suggest using Moment Timezone to convert from one timezone to another.
For example:
const dateString = `2020-06-19T03:55:12.000Z`;
const timezones = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles"];
console.log(`Time in UTC:`, moment(dateString).toISOString());
// Show the time in each timezone
timezones.forEach(timezone => {
let timeLocal = moment.tz(dateString, timezone);
console.log(`Time in ${timezone}:`, timeLocal.format('YYYY-MM-DD[T]HH:mm:ss.SSSZ'))
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.js">
</script>

Converting UTC milliseconds to Central Time in javascript

We have a bunch of systems events that are stored in a database with a milliseconds timestamp in UTC. In order for me to get the JSON I need, I just need to send a request like this....
http://xxx.xxx.xxx/gimmeJson?starttime=MILLISECONDS&endtime=MILLISECONDS
So when an event happened at 11:00pm CST it has been converted to the UTC millisecond equivalent and stored.
I am having a big issue wrapping my head around milliseconds because I'm thinking about it like timezones.
I saw a SO question similar to this here: How do I convert UTC/ GMT datetime to CST in Javascript? (not local, CST always) and it was close but not quite there.
If timestamps are stored in UTC milliseconds, how can I query them for their Central time equivalent? By that I mean my boss wants a report of all events that happened in the central timezone but I have to query a database that has these timestamps stored as UTC milliseconds.
Ultimately I have to come up with ** some ** number to send on a URL for UTC MILLISECONDS that is the equivalent of say "September 24, 12:00:00 Central". What compounds this issue is that the web service is fairly new and has been shown to be a bit buggy so I need to make sure I have this right.
// construct a moment object with Central time input
var m = moment('2015-01-01 00:00:00').format('x');
// convert using the TZDB identifier for GMT
m.tz('Europe/London');
// format output however you desire
var s = m.format("x");
Can someone confirm I am on the right track?
Many, many thanks in advance.
There's no such thing as milliseconds timestamp in UTC or any other timezone. Millisecond timestamps are always from 1970-01-01T00:00:00.000Z; they are zone agnostic.
In order to get the timestamp for the zone you want, simple create a Date instance and use the Date.prototype.getTime method
var cstTime = new Date('2016-09-24T12:00:00-06:00');
console.log('CST in ISO 8601:', cstTime.toISOString());
console.log('CST timestamp:', cstTime.getTime());
var localTime = new Date();
console.log('Local time in ISO 8601:', localTime.toISOString());
console.log('Local timestamp:', localTime.getTime());

Moment.js local relative time

I have dates in my database set to Europe/London time. I am using Moment.js to show relative time e.g. "3 minutes ago". This works fine for me as I am in the same timezone, but for example, someone who is PST timezone would see "in 8 hours". How can I fix this?
My current code is like this:
$('time').text( moment( '2016-01-22 18:00:00' ).fromNow() );
To echo Jon's answer, moment's relative time functionality is strictly UTC based, so the behavior you describe won't actually happen, unless you are interpreting the original timestamp in local time.
It's hard to say if you're doing that or not, as you didn't give a sample value of the input string.
If your times are indeed UTC based, but that's not reflected in the input string, then use moment.utc instead of just moment.
And no, London is not the same as UTC.
I believe that the best approach is to store the date in UTC and then convert this to the local time zone for display. Note that this is not necessarily the same as London time because UTC does away with daylight savings time nonsense. You can do everything that you need with the date class provided the time stamp stored in the database does not have to deal with the vagaries of time zone and DST. The date class maintains its own epoch internally as milliseconds elapsed since midnight 1 January 1970 UTC. You can evaluate the difference between two Date objects as follows:
var agora = Date.now();
var stored = ... // the date that was stored in your database
var diff_msec = agora.getTime() - stored.getTime();
Knowing that the difference and that its units are milliseconds, you can convert the difference to whatever units are best for presentation.

Get local time representation of Date in arbitrary timezone in arbitrary day - considering Daylight Savings Time

For sure, there is a lot of questions about Date objects and timezones but many of them are about converting the current time to another timezone, and others are not very clear about what they want to do.
I want to display the day, hour, minute etc. in an arbitrary timezone, in an arbitrary day. For example, I would like a function f(t, s) that:
given the timestamp 1357041600 (which is 2013/1/1 12:00:00 UTC) and the string "America/Los Angeles", would satisfy the comparison below:
f(1357041600, "America/Los Angeles") == "2013/01/01 04:00:00"
given the timestamp 1372680000 (2013/07/01 12:00:00 UTC), would satisfy the comparison below:
f(1357041600, "America/Los Angeles") == "2013/07/01 05:00:00"
will always behave this way even if the timezone in the browser is, let us say "Europe/London" or "America/São Paulo".
will always behave this way even if the time in the browser is, let us say 2014/02/05 19:32, or 2002/08/04 07:12; and
as a final restriction, will not request anything from the server side (because I'm almost doing it myself :) )
Is it even possible?
given the timestamp 1357041600 (which is 2013/1/1 12:00:00 UTC)
That appears to be seconds since the UNIX epoch (1970-01-01T00:00:00Z). Javascript uses the same epoch, but in milliseconds so to create a suitable date object:
var d = new Date(timestamp * 1000);
That will create a Date object with a suitable time value. You then need to determine the time zone offset using something like the IANA time zone database. That can be applied to the Date object using UTC methods. E.g. resolve the offset to minutes, then use:
d.setUTCMinutes(d.getUTCMinutes() + offset)
UTC methods can then be used to get the adjusted date and time values to create a string in whatever format you require:
var dateString = d.getUTCFullYear() + '/' + pad(d.getUTCMonth() + 1) + '/' ...
where pad is a function to add a leading zero to single digit values. Using UTC methods avoids any impact of local time zone offsets and daylight saving variances.
There are also libraries like timezone.js that can be used to determine the offset, however I have not used them so no endorsement is implied.
For JavaScript runtime environments that support the ECMAScript Internationalization API, and adhere to its recommendation of supporting the IANA time zone database, you can simply do this:
new Date(1357041600000).toLocaleString("en-US", {timeZone: "America/Los_Angeles"})
For other environments, a library is required. There are several listed here.

JS Dates only with UTC timezone

Is there some way to tell Javascript that it should never use anything but the UTC timezone?
When I create a new Date object, it gets my browsers timezone, but this will muck up when transporting via JSON.
All dates and times in the app are naive and has no use for the users timezone. So creating and working with only UTC times would be just fine, but no matter what I do, I just get what my date would look like in UTC and thats just not good enough.
I am using Bakcbone and DateJS if that makes any difference.
Any ideas on this?
Instead of transporting the string representation of the date, new Date().milliseconds. This is the UNIX time, i.e.
Integer value representing the number of milliseconds since 1 January
1970 00:00:00 UTC.
and therefore independent of the timezone.
Alternatively, construct the date string yourself, but use the getUTC* methods:
var d = new Date();
alert("It's " + d.getUTCHours() + ':' + d.getUTCSeconds());
I ended up just using .toString() and sending that along with the JSON post. Seemed like the simplest thing to do.

Categories