JS Dates only with UTC timezone - javascript

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.

Related

Avoid timezone correction for JavaScript Date

I have a JavaScript function that takes a number (1-31), creates a Date and sends it to a server via an AJAX request:
sendDate(d) {
let date = new Date(this.year, this.month, d);
htmx.ajax("GET", "/some/url", { values: { "date": date.toISOString() } });
}
The problem is, that JavaScript is doing some timezone correction which has the effect, that if I create a date like new Date(2022, 09, 14) I get a date Wed Sep 14 2022 00:00:00 GMT+0200 (Central European Summer Time) which when converted to ISO format becomes 2022-09-13T22:00:00.000Z, ie. the previous day.
I know I can use .toLocaleDateString(), but I would like to stick to the ISO-format and I would also like to avoid hacky solutions such as always creating the date with some specified time at the middle of the day or whatever.
Is there a simple way to create a regular date object and pass it on to a server without timezone shenanigans?
Values passed to the Date constructor are treated as local, toISOString uses UTC. Unfortunately ECMAScript doesn't have a timezone–free, date–only form.
If you want to use toISOString to format the timestamp, then one solution is to parse the values as UTC initially, e.g.
sendDate(d) {
let date = new Date(Date.UTC(this.year, this.month, d));
htmx.ajax("GET", "/some/url", { values: { "date": date.toISOString() } });
}
Example:
let d = new Date()
let year = d.getFullYear();
let month = d.getMonth()
let day = d.getDate();
let date = new Date(Date.UTC(year, month, day))
// Always shows the current local date as 00:00:00Z
console.log( date.toISOString() );
You should also trim the Z from the end since the timestamp really is local.
There’s a way to do that: store the date as the UNIX timestamp. I do it this way and when it’s needed, I pass the timestamp from server to client and convert it into local date.
That said, I don’t think it’s a good idea to build the date on client and pass it to the server, since it could be modified on client. I believe it’s mostly done this way (and that’s also how it’s done in my projects): on the server side, you check the current timestamp (at the time request is sent) and do with it whatever you want.
It appears that you allow your user to pick a date. It would be a good approach to convert it then to timestamp and pass it to the server.
How would you do that? If I return date.getTime() and then parse it (in python) with datetime.fromtimestamp(int(request.GET['date']) / 1000) I still get the same timezone issue...
You won't have any issues in this case - apart from the fact your server just could happen to have a different local time. A time-zone independent solution would have to use utcfromtimestamp instead of fromtimestamp.
Either way, the timestamp itself can't have any timezone problems by definition.
See RobG's Answer... using the new Date(Date.UTC(year, month, day)) formatting is much better.

Convert string to new Date object in UTC timeZONE

Can anyone let me know how to convert a string to a date Object with UTC time zone in ExtJs?
String is "2015-10-07T23:59:00". I would like to get the same in Date Object without changing the timezone.
First of all, your date string does not have a timezone.
When you make a JavaScript date object from a string, there are two possible outcomes you could expect:
You may want the date to be 23:59 Local (23:59 CEST in my case).
In this case, you want to use new Date("2015-10-07 23:59:00") with plain javascript (note the missing T), or Ext.Date.parse("2015-10-07T23:59:00","c");.
You may want the date to be 23:59 UTC (e.g. 01:59 CEST).
In this case, you want to use new Date("2015-10-07T23:59:00").
Of course, whenever you output the date, you have to get the date in the correct time zone as well. The console/toString will usually show it in local time. JavaScript does provide getUTC... methods if you require other time zones.
You see, using Time Zones with JavaScript is a painful experience. I would recommend to try moment.js if you need full time zone support.
You can use Ext.Date.parse.It gives Date Object as output.It syntax is:
Ext.Date.parse( String input, String format, [Boolean strict] )
For Example:
Ext.Date.parse("2015-10-07T23:59:00", "Y-m-dTH:i:s");
try
var millisFromEpoch = Date.parse('2015-10-07T23:59:00');
it will parse date in GMT timezone, Ext.date.parse use the current timezone instead

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.

Format date in a specific timezone

I'm using Moment.js to parse and format dates in my web app. As part of a JSON object, my backend server sends dates as a number of milliseconds from the UTC epoch (Unix offset).
Parsing dates in a specific timezone is easy -- just append the RFC 822 timezone identifier to the end of the string before parsing:
// response varies according to your timezone
const m1 = moment('3/11/2012 13:00').utc().format("MM/DD HH:mm")
// problem solved, always "03/11 17:00"
const m2 = moment('3/11/2012 13:00 -0400').utc().format("MM/DD HH:mm")
console.log({ m1, m2 })
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
But how do I format a date in a specifc timezone?
I want consistent results regardless of the browser's current time, but I don't want to display dates in UTC.
As pointed out in Manto's answer, .utcOffset() is the preferred method as of Moment 2.9.0. This function uses the real offset from UTC, not the reverse offset (e.g., -240 for New York during DST). Offset strings like "+0400" work the same as before:
// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')
The older .zone() as a setter was deprecated in Moment.js 2.9.0. It accepted a string containing a timezone identifier (e.g., "-0400" or "-04:00" for -4 hours) or a number representing minutes behind UTC (e.g., 240 for New York during DST).
// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')
To work with named timezones instead of numeric offsets, include Moment Timezone and use .tz() instead:
// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')
A couple of answers already mention that moment-timezone is the way to go with named timezone. I just want to clarify something about this library that was pretty confusing to me. There is a difference between these two statements:
moment.tz(date, format, timezone)
moment(date, format).tz(timezone)
Assuming that a timezone is not specified in the date passed in:
The first code takes in the date and assumes the timezone is the one passed in.
The second one will take date, assume the timezone from the browser and then change the time and timezone according to the timezone passed in.
Example:
moment.tz('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss', 'UTC').format() // "2018-07-17T19:00:00Z"
moment('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss').tz('UTC').format() // "2018-07-18T00:00:00Z"
My timezone is +5 from utc. So in the first case it does not change and it sets the date and time to have utc timezone.
In the second case, it assumes the date passed in is in -5, then turns it into UTC, and that's why it spits out the date "2018-07-18T00:00:00Z"
NOTE: The format parameter is really important. If omitted moment might fall back to the Date class which can unpredictable behaviors
Assuming the timezone is specified in the date passed in:
In this case they both behave equally
Even though now I understand why it works that way, I thought this was a pretty confusing feature and worth explaining.
Use moment-timezone
moment(date).tz('Europe/Berlin').format(format)
Before being able to access a particular timezone, you will need to load it like so (or using alternative methods described here)
moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')
.zone() has been deprecated, and you should use utcOffset instead:
// for a timezone that is +7 UTC hours
moment(1369266934311).utcOffset(420).format('YYYY-MM-DD HH:mm')
I was having the same issue with Moment.js. I've installed moment-timezone, but the issue wasn't resolved. Then, I did just what here it's exposed, set the timezone and it works like a charm:
moment(new Date({your_date})).zone("+08:00")
Thanks a lot!
Just came acreoss this, and since I had the same issue, I'd just post the results I came up with
when parsing, you could update the offset (ie I am parsing a data (1.1.2014) and I only want the date, 1st Jan 2014. On GMT+1 I'd get 31.12.2013. So I offset the value first.
moment(moment.utc('1.1.2014').format());
Well, came in handy for me to support across timezones
B
If you pass the timestamp as the parameter to moment() (e.g if the timezone is Asia/Hong_kong which is +08:00), what I do is:
const localDateTime = moment((item.createdAt.seconds + 8 * 3600) * 1000).format('YYYY-MM-DD HH:mm:ss');
You can Try this ,
Here you can get the date based on the Client Timezone (Browser).
moment(new Date().getTime()).zone(new Date().toString().match(/([-\+][0-9]+)\s/)[1]).format('YYYY-MM-DD HH:mm:ss')
The regex basically gets you the offset value.
Cheers!!

Daylight savings time and JavaScript timezone conversions

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.

Categories