Is it Possible in javascript to restrict date to specific Timezone [duplicate] - javascript

I know I can get the local timezone offset via new Date().getTimeZoneOffset(). But where did Javascript get that information? Is there a way I can set it, so that all future Date objects have the offset I want? I tried searching the DOM in Firebug, but couldn't find anything.
What I am trying to accomplish is converting epoch times to readable format, but it needs to be in US/Central, no matter what the browser's OS setting. Because I am using US/Central, it's not a fixed difference from GMT. So instead of a bunch of super nasty conversion steps, why can't I just tell Javascript that I'm actually in US/Central?

Currently, Moment-Timezone enables us to set the "browser's" default timezone by using moment.tz.setDefault().
You'll have to use moment() instead of Date(), but this is still a nice upgrade over the weird JS Date object.

I know I can get the local timezone offset via new Date().getTimeZoneOffset(). But where did Javascript get that information?
An implementation of ECMAScript is expected to determine the local time zone adjustment.
Is there a way I can set it, so that all future Date objects have the offset I want?
No.
So instead of a bunch of super nasty conversion steps, why can't I just tell Javascript that I'm actually in US/Central?
Have you considered using a library?

I realize this is an old post, but momentJS is a powerful javascript library to manipulate date/time objects

Output format
If you are concerned about the output format, you always need to format you Date object prior to outputting it if you need it in a local timezone (e.g. using Intl) or you a library like dayjs or moment.
Create a new Date object from a date with a non-UTC timezone
You can set an offset in pure JS: new Date('2022-10-29T12:50:00.000+02:00') will contain 2022-10-29T10:50:00.000Z. You just have to always specify the timezone offset in /^[+-][0-2]\d:[0-5]\d$/ format.
console.log(new Date('2022-10-29T12:50:00.000+02:00').toISOString())
// Output
// 2022-10-29T10:50:00.000Z
Get timezone offset string from timezone offset number
Now, if you want to get an offset in that format from (new Date()).getTimezoneOffset() (e.g. -120), you need to
const tzOffsetNumber = (new Date()).getTimezoneOffset()
const tzOffsetString = `${tzOffsetNumber > 0 ? '+' : '-'}${Math.floor(Math.abs(tzOffsetNumber) / 60).toString().padStart(2, '0')}:${(Math.abs(tzOffsetNumber) % 60).toString().padStart(2, '0')}`
Get timezone offset string from IANA timezone
// Note: We need to specify a date in order to also consider DST settings.
const date = new Date()
const ianaTimezone = 'Europe/Bratislava'
const tzOffsetString = new Intl.DateTimeFormat('en', {timeZone: ianaTimezone, timeZoneName: 'longOffset'}).format(date).match(/[\d+:-]+$/)?.[0]

Related

Initializing time with its own timezone

I'm quite new (and confused) with time in JavaScript..
I currently have time data to work with, and they are in the format of DD-MMM-YYYY, meaning it would be 23-Feb-2021. This time is already in its own timezone, GMT-10. I'm trying to initialize it as GMT-10 so that I could get its appropriate epoch time.
I've done this:
date = new Date("23-Feb-2021") // This results in 2021-02-23T00:00:00.000Z
But what I'm trying to achieve is to get the time to be 2021-02-23T10:00:00.000Z, which I could then do a getTime() to get its epoch in ms. I understand I could probably hard code to +10 to the time I have, but the data I work with might vary so I'd like to figure a way to initialize the date with a specific timezone.
EDIT:
Here's an example of an outcome I'd want:
date = ("23-Feb-2021")
date = moment(date).format(); // 2021-02-23T00:00:00+00:00
date = date.replace("+00","+10");
date = new Date(msg.date); // 2021-02-22T14:00:00.000Z
date = date.getTime(); // 1614002400000 (2021-02-22T14:00:00.000Z)
In the end, 2021-02-22T14:00:00.000Z is what I'm trying to get, without having to iterate it a bunch of times like above and adding +10
You can add the timezone offset to your input string, and use an explicit string format to parse it:
let date = "23-Feb-2021"
date = moment(date + "-10:00", "D-MMM-YYYYZ")
console.log(date.format()) // 2021-02-23T11:00:00+01:00 (if local is GMT+1)
console.log(date.utc().format()) // 2021-02-23T10:00:00+00:00
It seems you're already using moment.js, so add moment–timezone so you can parse timestamps in whatever IANA timezone you want. You can either choose a location with the offset rules you want (e.g. Pacific/Honolulu or Pacific/Tahiti for -10) or just a fixed offset like etc/GMT+10.
You can then format the value in any timezone, as UTC, or as a time value, e.g.
// Timestamp
let d = "23-Feb-2021";
// Parse in specific IANA timezone
let m = moment.tz(d, 'D-MMM-YYYY', 'Pacific/Honolulu');
// Trigger UTC mode
m.utc()
// Show result
console.log(m.format())
// Get time value (ms since epoch)
console.log(m.valueOf());
// Parse using generic timezone/fixed offset
let g = moment.tz(d, 'D-MMM-YYYY', 'etc/GMT+10');
console.log(g.utc().format());
// Display timestamp for another timezone
console.log(moment.tz(g, 'Asia/Riyadh').format());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data-10-year-range.js"></script>
Note that for fixed offset timezones like etc/GMT+10, the sign is the opposite of the common offset (e.g. etc/GMT+10 is UTC-10) to be consistent with POSIX notation. However, moment.tz only has limited POSIX support in that it only recognises one hour offsets, not the full POSIX timezone notation, so you can't do say "etc/GMT-530" instead of Asia/Kolkata.

Working with different timezones in Javascript

I am working on a cloud based application which deals extensively with date and time values, for users across the world.
Consider a scenario, in JavaScript, where my machine is in India (GMT+05:30), and I have to display a clock running in California's timezone (GMT-08:00).
In this case I have to get a new date object,
let india_date = new Date()
add it's time zone offset value,
let uts_ms = india_date.getTime() + india_date.getTimezoneOffset()
add california's timezone offset value,
let california_ms = utc_ms + getCaliforniaTimezoneOffsetMS()
and finally the date object.
let california_date: Date = new Date(california_ms)
Is there any way to directly deal with these kinds of time zones without having to convert the values again and again?
First, let's talk about the code in your question.
let india_date = new Date()
You have named this variable india_date, but the Date object will only reflect India if the code is run on a computer set to India's time zone. If it is run on a computer with a different time zone, it will reflect that time zone instead. Keep in mind that internally, the Date object only tracks a UTC based timestamp. The local time zone is applied when functions and properties that need local time are called - not when the Date object is created.
add it's timezone offset value
let uts_ms = india_date.getTime() + india_date.getTimezoneOffset()
This approach is incorrect. getTime() already returns a UTC based timestamp. You don't need to add your local offset. (also, the abbreviation is UTC, not UTS.)
Now add california's timezone offset value
let california_ms = utc_ms + getCaliforniaTimezoneOffsetMS()
Again, adding an offset is incorrect. Also, unlike India, California observes daylight saving time, so part of the year the offset will be 480 (UTC-8), and part of the year the offset will be 420 (UTC-7). Any function such as your getCaliforniatimezoneOffsetMS would need to have the timestamp passed in as a parameter to be effective.
and finally the date object
let california_date: Date = new Date(california_ms)
When the Date constructor is passed a numeric timestamp, it must be in terms of UTC. Passing it this california_ms timestamp is actually just picking a different point in time. You can't change the Date object's behavior to get it to use a different time zone just by adding or subtracting an offset. It will still use the local time zone of where it runs, for any function that requires a local time, such as .toString() and others.
There is only one scenario where this sort of adjustment makes sense, which is a technique known as "epoch shifting". The timestamp is adjusted to shift the base epoch away from the normal 1970-01-01T00:00:00Z, thus allowing one to take advantage of the Date object's UTC functions (such as getUTCHours and others). The catch is: once shifted, you can't ever use any of the local time functions on that Date object, or pass it to anything else that expects the Date object to be a normal one. Epoch shifting done right is what powers libraries like Moment.js. Here is another example of epoch shifting done correctly.
But in your example, you are shifting (twice in error) and then using the Date object as if it were normal and not shifted. This can only lead to errors, evident by the time zone shown in toString output, and will arise mathematically near any DST transitions of the local time zone and the intended target time zone. In general, you don't want to take this approach.
Instead, read my answer on How to initialize a JavaScript Date to a particular time zone. Your options are listed there. Thanks.
JavaScript Date objects store date and time in UTC but the toString() method is automatically called when the date is represented as a text value which displays the date and time in the browser's local time zone. So, when you want to convert a datetime to a time zone other than your local time, you are really converting from UTC to that time zone (not from your local time zone to another time zone).
If your use case is limited to specific browsers and you are flexible on formatting (since browsers may differ in how they display date string formats), then you may be able to use toLocaleString(), but browsers like Edge, Android webview, etc do not fully support the locales and options parameters.
Following example sets both the locale and timezone to output the date in a local format that may vary from browser to browser.
const dt = new Date();
const kolkata = dt.toLocaleString('en-IN', { timeZone: 'Asia/Kolkata' });
const la = dt.toLocaleString('en-US', { timeZone: 'America/Los_Angeles' });
console.log('Kolkata:', kolkata);
// example output: Kolkata: 19/3/2019, 7:36:26 pm
console.log('Los Angeles:', la);
// example output: Los Angeles: 3/19/2019, 7:06:26 AM
You could also use Moment.js and Moment Timezone to convert date and time to a time zone other than your local time zone. For example:
const dt = moment();
const kolkata = dt.tz('Asia/Kolkata').format();
const la = dt.tz('America/Los_Angeles').format();
console.log(kolkata);
// example output: 2019-03-19T19:37:11+05:30
console.log(la);
// example output: 2019-03-19T07:07:11-07:00
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data.min.js"></script>
Well, you really do kind of have to convert anytime you want to change the display, but it's not as bad as you think.
First, store all time as UTC. Probably using the milliseconds format, e.g. Date.UTC().
Second, do all manipulation / comparison using that stored info.
Third, if your cloud-based application has an API that API should only talk in terms of UTC as well, though you could provide the ISO string if you prefer that to the MS, or if you expect clients to handle that better.
Fourth and finally, only in the UI should you do the final conversion to the local date/time string, either with the method you're describing or using a library such as momentjs
new Date creates a Date object with a time value that is UTC. If you can guarantee support for the timeZone option of toLocaleString (e.g. corporate environment with a controlled SOE), you can use it to construct a timestamp in any time zone and any format, but it can be a bit tedious. Support on the general web may be lacking. A library would be preferred in that case if you need it to work reliably.
E.g. to get values for California, you can use toLocaleString and "America/Los_Angeles" for the timeZone option:
var d = new Date();
// Use the default implementation format
console.log(d.toLocaleString(undefined, {timeZone:'America/Los_Angeles'}));
// Customised format
var weekday = d.toLocaleString(undefined, {weekday:'long', timeZone:'America/Los_Angeles'});
var day = d.toLocaleString(undefined, {day:'numeric', timeZone:'America/Los_Angeles'});
var month = d.toLocaleString(undefined, {month:'long', timeZone:'America/Los_Angeles'});
var year = d.toLocaleString(undefined, {year:'numeric', timeZone:'America/Los_Angeles'});
var hour = d.toLocaleString(undefined, {hour:'numeric',hour12: false, timeZone:'America/Los_Angeles'});
var minute = d.toLocaleString(undefined, {minute:'2-digit', timeZone:'America/Los_Angeles'});
var ap = hour > 11? 'pm' : 'am';
hour = ('0' + (hour % 12 || 12)).slice(-2);
console.log(`The time in Los Angeles is ${hour}:${minute} ${ap} on ${weekday}, ${day} ${month}, ${year}`);
Getting the timezone name is a little more difficult, it's difficult to get it without other information.

Ignore timezone offset while converting date - javascript

I have a WCF REST service that returns date in below format:
/Date(1401993000000+0530)/
The value of this date on the server is
6/6/2014 12:00:00 AM
I want to parse this in my javascript code in UTC value.
I tried manually removing the "+0530" string and parsing it to date but it gives "Invalid Date".
I also tried adding the timezone offset as per this post but it gives incorrect value.
How can I parse this?
This format is commonly referred to as an "ASP.NET JSON Date" - because it first emerged from the JavaScriptSerializer and DataContractJsonSerializer classes used in ASP.NET and other parts of .NET. However, it was heavily criticized, and ultimately deprecated in favor of the standard ISO 8601 format, which is the default in the Json.Net library used in most modern .NET code. You'll still see it in WCF, and in older versions of ASP.NET MVC.
This format has two main variations:
/Date(1401993000000)/ - A timestamp alone
/Date(1401993000000+0530)/ - A timestamp with an offset
You will occasionally see the forward slashes escaped with backslashes, as in \/Date(1401993000000)\/, depending on how it was generated. This should be tolerated by parsers, but should not be depended upon.
In both formats shown, the timestamp portion is intended to represent the number of milliseconds since the Unix Epoch, which is 1970-01-01 00:00:00.000 UTC.
I say "intended", because it is possible in .NET to have a DateTime with DateTimeKind.Unspecified, which can't possibly be mapped back to UTC. In this case, the serializer will act as if it had DateTimeKind.Local. The output will then reflect the value adjusted to UTC in the computer's local time zone, along with the computer's UTC offset for that point in time. Ideally, you should not rely on this behavior, as you will get different results from computers in different time zones.
When an offset is present in the output string, it is in +HHmm/-HHmm format, with positive values falling East of GMT - the same direction as the ISO 8601 standard. However, unlike ISO 8601, the value portion is not adjusted for that offset. It remains UTC-based.
In other words:
/Date(1401993000000)/ = 2014-06-05T18:30:00Z
/Date(1401993000000+0530)/ = 2014-06-05T18:30:00Z + +0530 = 2014-06-06T00:00:00+05:30
Because of this, the offset portion is extraneous when using this value to create a JavaScript Date object - since a Date object wraps a timestamp in UTC, and has no provision for retaining a provided offset.
You can certainly break out the string into its parts and use them yourself,
but instead consider using Moment.js for parsing this string. It understands the format natively, and can give you back an object that retains knowledge of the offset.
var m = moment.parseZone("/Date(1401993000000+0530)/");
m.format() // "2014-06-06T00:00:00+05:30"
If you were looking for a Date object, you can certainly call m.toDate(). The resulting Date object will have the same UTC timestamp, but due to how the Date object works, any local-time functions will only use the offset of the host environment.
In other words, with output of a Date object, the +0530 part of your input becomes useless. You might have well have parsed /Date(1401993000000)/.
You can use Moment JS, one of the better ways to play with datetime in JavaSCript. Lot of functions
https://momentjs.com/timezone/
See the edited message, without momentjs:
var data = [ {"id":1,"start":"/Date(1401993000000+0530)/"} ];
var myDate = new Date(data[0].start.match(/\d+/)[0] * 1);
myDate = new Date(myDate.getTime() + myDate.getTimezoneOffset() * 60 * 1000);
alert(myDate);

Converting date from string with offset to different timezone

I'm wondering on the correct way to convert a string date in a non-ISO format to a different offset/timezone.
I am currently given 3 values:
the date in format MM/DD/YYYY (23/11/2016)
the time in 24h format (23:13)
timezone offset (-07:00)
I would like to convert said date to the user's timezone.
I am trying to convert the format to the format accepted by moment timezone's moment.tz() function ('2016-11-23T23:13-07:00') but I am not sure how to do that without splitting the date array and converting it to said date.
Moment's timezone has the tools I need to convert the date afterwards to the local timezone. For example:
moment.tz('2016-11-23T23:13-07:00', moment.tz.guess());
Any thoughts on how to convert 23/11/2016 23:13 with offset -07:00 to the local date preferably using momentJS?
Why not just format as an ISO 8601 string with offset and give that to moment.js?
function customToISOString(date, time, offset){
return date.split(/\D/).reverse().join('-') + 'T' + time + offset;
}
document.write(customToISOString('23/11/2016','23:13','-07:00')); // 2016-11-23T23:13-07:00
Most modern browsers will also parse that, but don't do it as there are still plenty of older browsers around where it will fail.
I like Rob's answer, but I'll also give you it in moment.js.
First, you don't need moment-timezone, and you definitely don't need to guess the time zone id just to convert to that zone. In ISO format, it would just be like this:
var m = moment('2016-11-23T23:13-07:00');
This will read in the offset during parsing, apply it, then convert to the local time zone, returning a moment object in "local mode". This is the default mode, so it just works.
With the requirements you described it would be like this:
// your inputs
var d = "23/11/2016";
var t = "23:13";
var o = "-07:00";
var m = moment(d + ' ' + t + o, 'MM/DD/YYYY HH:mmZ');
Note that I add the space between the date and time just for safety, so there's no risk of mixing the year and the hour components.
Again it will automatically apply the offset and convert to the local time zone, since that's the default behavior. If you want some other behavior, there are ways to do that as well.

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

Categories