Initializing time with its own timezone - javascript

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.

Related

Local time zone not displayed while formatting OffsetDataTime using moment js [duplicate]

What is the best way to get client's timezone and convert it to some other timezone when using moment.js and moment-timezone.js
I want to find out what is clients timezone and later convert his date and time into some other timezone.
Does anybody has experience with this?
When using moment.js, use:
var tz = moment.tz.guess();
It will return an IANA time zone identifier, such as America/Los_Angeles for the US Pacific time zone.
It is documented here.
Internally, it first tries to get the time zone from the browser using the following call:
Intl.DateTimeFormat().resolvedOptions().timeZone
If you are targeting only modern browsers that support this function, and you don't need Moment-Timezone for anything else, then you can just call that directly.
If Moment-Timezone doesn't get a valid result from that function, or if that function doesn't exist, then it will "guess" the time zone by testing several different dates and times against the Date object to see how it behaves. The guess is usually a good enough approximation, but not guaranteed to exactly match the time zone setting of the computer.
var timedifference = new Date().getTimezoneOffset();
This returns the difference from the clients timezone from UTC time.
You can then play around with it as you like.
All current answers provide the offset differece at current time, not at a given date.
moment(date).utcOffset() returns the time difference in minutes between browser time and UTC at the date passed as argument (or today, if no date passed).
Here's a function to parse correct offset at the picked date:
function getUtcOffset(date) {
return moment(date)
.subtract(
moment(date).utcOffset(),
'minutes')
.utc()
}
Using Moment library, see their website -> https://momentjs.com/timezone/docs/#/using-timezones/converting-to-zone/
i notice they also user their own library in their website, so you can have a try using the browser console before installing it
moment().tz(String);
The moment#tz mutator will change the time zone and update the offset.
moment("2013-11-18").tz("America/Toronto").format('Z'); // -05:00
moment("2013-11-18").tz("Europe/Berlin").format('Z'); // +01:00
This information is used consistently in other operations, like calculating the start of the day.
var m = moment.tz("2013-11-18 11:55", "America/Toronto");
m.format(); // 2013-11-18T11:55:00-05:00
m.startOf("day").format(); // 2013-11-18T00:00:00-05:00
m.tz("Europe/Berlin").format(); // 2013-11-18T06:00:00+01:00
m.startOf("day").format(); // 2013-11-18T00:00:00+01:00
Without an argument, moment#tz returns:
the time zone name assigned to the moment instance or
undefined if a time zone has not been set.
var m = moment.tz("2013-11-18 11:55", "America/Toronto");
m.tz(); // America/Toronto
var m = moment.tz("2013-11-18 11:55");
m.tz() === undefined; // true
You can also get your wanted time using the following JS code:
new Date(`${post.data.created_at} GMT+0200`)
In this example, my received dates were in GMT+0200 timezone. Instead of it can be every single timezone. And the returned data will be the date in your timezone. Hope this will help anyone to save time
if the user's timezone is all you wanted then
const localtz = moment.tz.guess() // returns user's timezone
Additionally if you wanted to use it then the best way to convert a timestamp to user's timezone is
const time = moment.tz(response.timestamp)
const localtz = moment.tz.guess() // user's timezone
const date = time.clone().tz(localtz) // convert time to user's timezone
here localtz is the user's timezone and using it we can convert the timestamp to user's local time
First, you can find out the clients time zone using the following
let zoneVal = moment().tz(Intl.DateTimeFormat().resolvedOptions().timeZone).format('Z')
it will return you the GMT zone format for example +5:30 (colombo/srilanka & Delhi/India) or +6:00(Dhaka Bangladesh) depending on the region you are in.
secondly,
if you want to find out the time of a particular time zone , then do the following
moment.tz("Asia/Dhaka").format()
which will return you the time zone value in ISO format of Dhaka.
Using moment timezone you can get easily your local date-time
moment().utcOffset(0, true).format()

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.

Get timezone from users browser using moment(timezone).js

What is the best way to get client's timezone and convert it to some other timezone when using moment.js and moment-timezone.js
I want to find out what is clients timezone and later convert his date and time into some other timezone.
Does anybody has experience with this?
When using moment.js, use:
var tz = moment.tz.guess();
It will return an IANA time zone identifier, such as America/Los_Angeles for the US Pacific time zone.
It is documented here.
Internally, it first tries to get the time zone from the browser using the following call:
Intl.DateTimeFormat().resolvedOptions().timeZone
If you are targeting only modern browsers that support this function, and you don't need Moment-Timezone for anything else, then you can just call that directly.
If Moment-Timezone doesn't get a valid result from that function, or if that function doesn't exist, then it will "guess" the time zone by testing several different dates and times against the Date object to see how it behaves. The guess is usually a good enough approximation, but not guaranteed to exactly match the time zone setting of the computer.
var timedifference = new Date().getTimezoneOffset();
This returns the difference from the clients timezone from UTC time.
You can then play around with it as you like.
All current answers provide the offset differece at current time, not at a given date.
moment(date).utcOffset() returns the time difference in minutes between browser time and UTC at the date passed as argument (or today, if no date passed).
Here's a function to parse correct offset at the picked date:
function getUtcOffset(date) {
return moment(date)
.subtract(
moment(date).utcOffset(),
'minutes')
.utc()
}
Using Moment library, see their website -> https://momentjs.com/timezone/docs/#/using-timezones/converting-to-zone/
i notice they also user their own library in their website, so you can have a try using the browser console before installing it
moment().tz(String);
The moment#tz mutator will change the time zone and update the offset.
moment("2013-11-18").tz("America/Toronto").format('Z'); // -05:00
moment("2013-11-18").tz("Europe/Berlin").format('Z'); // +01:00
This information is used consistently in other operations, like calculating the start of the day.
var m = moment.tz("2013-11-18 11:55", "America/Toronto");
m.format(); // 2013-11-18T11:55:00-05:00
m.startOf("day").format(); // 2013-11-18T00:00:00-05:00
m.tz("Europe/Berlin").format(); // 2013-11-18T06:00:00+01:00
m.startOf("day").format(); // 2013-11-18T00:00:00+01:00
Without an argument, moment#tz returns:
the time zone name assigned to the moment instance or
undefined if a time zone has not been set.
var m = moment.tz("2013-11-18 11:55", "America/Toronto");
m.tz(); // America/Toronto
var m = moment.tz("2013-11-18 11:55");
m.tz() === undefined; // true
You can also get your wanted time using the following JS code:
new Date(`${post.data.created_at} GMT+0200`)
In this example, my received dates were in GMT+0200 timezone. Instead of it can be every single timezone. And the returned data will be the date in your timezone. Hope this will help anyone to save time
if the user's timezone is all you wanted then
const localtz = moment.tz.guess() // returns user's timezone
Additionally if you wanted to use it then the best way to convert a timestamp to user's timezone is
const time = moment.tz(response.timestamp)
const localtz = moment.tz.guess() // user's timezone
const date = time.clone().tz(localtz) // convert time to user's timezone
here localtz is the user's timezone and using it we can convert the timestamp to user's local time
First, you can find out the clients time zone using the following
let zoneVal = moment().tz(Intl.DateTimeFormat().resolvedOptions().timeZone).format('Z')
it will return you the GMT zone format for example +5:30 (colombo/srilanka & Delhi/India) or +6:00(Dhaka Bangladesh) depending on the region you are in.
secondly,
if you want to find out the time of a particular time zone , then do the following
moment.tz("Asia/Dhaka").format()
which will return you the time zone value in ISO format of Dhaka.
Using moment timezone you can get easily your local date-time
moment().utcOffset(0, true).format()

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.

parsing a UTC ISO date to a local time date in javascript/jquery

I have tried to search for the answer already, and although I find answers that are very similar, I don't think they are exactly what I am looking for. Please forgive me if this is already answered elsewhere.
I am trying to parse an ISO date in javascript so that I can compare it to the client system date and display information depending on if the ISO date is before or after the client system date.
This was fine until I needed to support IE8 and now I am stuck.
I have created a function because I have three different dates that I need to do this to.
for example, my ISO date is: 2015-12-22T11:59 in UTC time.
but once my date is parsed, the full date is 11:59 in local time, no matter which time zone i test, it's always 11.59 in THAT time zone.
I know that the function I have created currently doesn't do anything with timezone, this is where I am stuck. I don't know what to add to get my end date to change as a reflection of the timezone of the clients machine.
any help or advice would be greatly appreciated.
I am not able to use something like moments.js because I have an upload restriction.
Jquery is available though. or plain javascript.
<script>
function setSaleContent() {
//creating a new date object that takes the clients current system time. so we can compare it to the dates stored in our array
var currentDate = new Date();
console.log(currentDate + " this is the clients date ");
//These variables actually come from an external array object, but I'm putting them in here like this for this example.
var destinations = {
freedate: "2015-12-16T11:59",
courierdate: "2015-12-22T11:59",
nextdaydate: "2015-12-23T11:59",
}
//fetch all the ISO dates from the array.
var freeDateISO = destinations["freedate"];
var courierDateISO = destinations["courierdate"];
var nextdayDateISO = destinations["nextdaydate"];
//I am creating this reusable function to split up my ISO date for the sake of IE8.. and create it into a date format that can be compared against another date. I know that this isn't doing anything with my timezone and that is where my problem lies.
function parseDate(str) {
var parts = /^(\d{4}).(\d{2}).(\d{2}).(\d{2}):(\d{2})/.exec(str);
if (parts) {
return new Date(parts[1], parts[2] - 1, parts[3], parts[4], parts[5]);
}
return new Date();
}
//I would like this date to change to reflect the time zone of the clients system time.
//currently returns the date at 11.59 regardless of timezone.
//If i was in GMT i would want it to say 11.59
//If i was in CT time I would like this to say 05.59
//If i was in Perth I would like this to say 19:59
var freeDate = parseDate(freeDateISO);
console.log(freeDate + " this is the converted date for IE")
}
window.onload = setSaleContent;
The simple solution is to append Z to the ISO date to indicate it is in UTC time, such as 2015-12-22T11:59Z.
When JavaScript parses that date as a string, it will then automatically convert the UTC date to the local time zone.
While this is simple enough with a parsing call in the form new Date(str);, it will not play nice with your parse call with numerical arguments targeting IE8 and other old browsers.
A polyfill for parsing ISO dates with timezone exists: Javascript JSON Date parse in IE7/IE8 returns NaN
This can replace your custom parseDate function after some modification to take an input string.
Alternatively, implement your own custom date manipulater to account for the local timezone using the .getTimezoneOffset() method on the newly created date, which gives the time zone offset in minutes, but you will have to come up with a method of utilising the offset such as adjusting hours and minutes, due to the limited methods of the JavaScript date object.

Categories