How Do I calculate the difference of 2 time zones in JavaScript? - javascript

For example, the difference in Eastern and Central is 1. My solution below feels hacky. Is there a easier / better way?
var diff = (parseInt(moment().tz("America/New_York").format("ZZ")) - parseInt(moment().tz("America/Chicago").format("ZZ"))) / 100;
My example is using the Momentjs library.

It's impossible to calculate the difference between two arbitrary time zones. You can only calculate a difference for a specific moment in time.
It's currently 4 hours difference between London and New York (writing this on Mar 25, 2015).
But it was 5 hours difference a few weeks ago, and it will be 5 a few weeks from now.
Each time zone switches offsets for daylight saving time at a different point in time.
This is true in the general case between two time zones. However some time zones either switch exactly at the same time, or don't switch at all.
There is always one hour between London and Paris, because they switch at the same moment in time.
There are always 3 hours between Arizona and Hawaii, because neither have DST.
Keep in mind that in the United States, each time zone that uses DST actually switches at a different moment in time. They all switch at 2:00 AM in their local time, but not at the same universal moment in time.
So between Chicago and New York, there is usually 1 hour apart
But for two brief periods each year they are either 2 hours apart, or have the same exact time.
See also "Time Zone != Offset" in the timezone tag wiki.
Now with regard to moment-timezone, you said in comments:
The web server is in the Eastern time zone; we're in Central. I need the difference in the user's timezone and the server.
The time zone of the web server is irrelevant. You should be able to host from anywhere in the world without affecting your application. If you can't, then you're doing it wrong.
You can get the current time difference between your time zone (US Central time) and the user's. You don't even need to know the user's exact time zone for this, if the code is running in the browser:
var now = moment();
var localOffset = now.utcOffset();
now.tz("America/Chicago"); // your time zone, not necessarily the server's
var centralOffset = now.utcOffset();
var diffInMinutes = localOffset - centralOffset;
If instead the code was running on the server (in a node.js app), then you would need to know the user's time zone. Just change the first line like this:
var now = moment.tz("America/New_York"); // their time zone
Updated answer:
This can be done without Moment, in environments that support the ECMAScript Internationalization API and have fully implemented IANA time zone support. This is most browsers these days.
function getTimeZoneOffset(date, timeZone) {
// Abuse the Intl API to get a local ISO 8601 string for a given time zone.
let iso = date.toLocaleString('en-CA', { timeZone, hour12: false }).replace(', ', 'T');
// Include the milliseconds from the original timestamp
iso += '.' + date.getMilliseconds().toString().padStart(3, '0');
// Lie to the Date object constructor that it's a UTC time.
const lie = new Date(iso + 'Z');
// Return the difference in timestamps, as minutes
// Positive values are West of GMT, opposite of ISO 8601
// this matches the output of `Date.getTimeZoneOffset`
return -(lie - date) / 60 / 1000;
}
Example usage:
getTimeZoneOffset(new Date(2020, 3, 13), 'America/New_York') //=> 240
getTimeZoneOffset(new Date(2020, 3, 13), 'Asia/Shanghai') //=> -480
If you want the difference between them, you can simply subtract the results.
Node.js
The above function works in Node.js where the full-icu internationalization support is installed (which is the default for Node 13 and newer). If you have an older version with either system-icu or small-icu, you can use this modified function. It will work in browsers and full-icu environments also, but is a bit larger. (I have tested this on Node 8.17.0 on Linux, and Node 12.13.1 on Windows.)
function getTimeZoneOffset(date, timeZone) {
// Abuse the Intl API to get a local ISO 8601 string for a given time zone.
const options = {timeZone, calendar: 'iso8601', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false};
const dateTimeFormat = new Intl.DateTimeFormat(undefined, options);
const parts = dateTimeFormat.formatToParts(date);
const map = new Map(parts.map(x => [x.type, x.value]));
const year = map.get('year');
const month = map.get('month');
const day = map.get('day');
const hour = `${map.get('hour') % 24}`.padStart(2, "0"); // Sometimes hour value comes as 24
const minute = map.get('minute');
const second = map.get('second');
const ms = date.getMilliseconds().toString().padStart(3, '0');
const iso = `${year}-${month}-${day}T${hour}:${minute}:${second}.${ms}`;
// Lie to the Date object constructor that it's a UTC time.
const lie = new Date(iso + 'Z');
// Return the difference in timestamps, as minutes
// Positive values are West of GMT, opposite of ISO 8601
// this matches the output of `Date.getTimeZoneOffset`
return -(lie - date) / 60 / 1000;
}
Note that either way, we must go through Intl to have the time zone applied properly.

The difference between two timezones can only be measured w.r.t particular time because of things like Daylight saving time (dst).
But, for a particular date, below code should work.
function getOffsetBetweenTimezonesForDate(date, timezone1, timezone2) {
const timezone1Date = convertDateToAnotherTimeZone(date, timezone1);
const timezone2Date = convertDateToAnotherTimeZone(date, timezone2);
return timezone1Date.getTime() - timezone2Date.getTime();
}
function convertDateToAnotherTimeZone(date, timezone) {
const dateString = date.toLocaleString('en-US', {
timeZone: timezone
});
return new Date(dateString);
}
The offset/difference is in milli sec
Then all you have to do is:
const offset = getOffsetBetweenTimezonesForDate(date, 'America/New_York', 'America/Chicago');

An easy way using toLocalString to get the difference with GMT of the timezones. Then you only need to substract.
var d = new Date();
var a = d.toLocaleString("en-US", { timeZone: 'Asia/Tokyo', timeZoneName: "short" }).split(/GMT/g)[1];
var b = d.toLocaleString("en-US", { timeZone: 'America/Montreal', timeZoneName: "short" }).split(/GMT/g)[1];
var diff = a - b;

Related

How to new Date() with localTime? [duplicate]

I have date time in a particular timezone as a string and I want to convert this to the local time. But, I don't know how to set the timezone in the Date object.
For example, I have Feb 28 2013 7:00 PM ET, then I can
var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);
As far as I know, I can either set the UTC time or local time. But, how do I set time in another timezone?
I tried to use the add/subtract the offset from UTC but I don't know how to counter daylight savings. Am not sure if I am heading the right direction.
How can I go about converting time from a different timezone to local time in javascript?
Background
JavaScript's Date object tracks time in UTC internally, but typically accepts input and produces output in the local time of the computer it's running on. It has very few facilities for working with time in other time zones.
The internal representation of a Date object is a single number, representing the number of milliseconds that have elapsed since 1970-01-01 00:00:00 UTC, without regard to leap seconds.
There is no time zone or string format stored in the Date object itself.
When various functions of the Date object are used, the computer's local time zone is applied to the internal representation. If the function produces a string, then the computer's locale information may be taken into consideration to determine how to produce that string. The details vary per function, and some are implementation-specific.
The only operations the Date object can do with non-local time zones are:
It can parse a string containing a numeric UTC offset from any time zone. It uses this to adjust the value being parsed, and stores the UTC equivalent. The original local time and offset are not retained in the resulting Date object. For example:
var d = new Date("2020-04-13T00:00:00.000+08:00");
d.toISOString() //=> "2020-04-12T16:00:00.000Z"
d.valueOf() //=> 1586707200000 (this is what is actually stored in the object)
In environments that have implemented the ECMASCript Internationalization API (aka "Intl"), a Date object can produce a locale-specific string adjusted to a given time zone identifier. This is accomplished via the timeZone option to toLocaleString and its variations. Most implementations will support IANA time zone identifiers, such as 'America/New_York'. For example:
var d = new Date("2020-04-13T00:00:00.000+08:00");
d.toLocaleString('en-US', { timeZone: 'America/New_York' })
//=> "4/12/2020, 12:00:00 PM"
// (midnight in China on Apring 13th is noon in New York on April 12th)
Most modern environments support the full set of IANA time zone identifiers (see the compatibility table here). However, keep in mind that the only identifier required to be supported by Intl is 'UTC', thus you should check carefully if you need to support older browsers or atypical environments (for example, lightweight IoT devices).
Libraries
There are several libraries that can be used to work with time zones. Though they still cannot make the Date object behave any differently, they typically implement the standard IANA timezone database and provide functions for using it in JavaScript. Modern libraries use the time zone data supplied by the Intl API, but older libraries typically have overhead, especially if you are running in a web browser, as the database can get a bit large. Some of these libraries also allow you to selectively reduce the data set, either by which time zones are supported and/or by the range of dates you can work with.
Here are the libraries to consider:
Intl-based Libraries
New development should choose from one of these implementations, which rely on the Intl API for their time zone data:
Luxon (successor of Moment.js)
date-fns-tz (extension for date-fns)
Day.js (when using its Timezone plugin)
Non-Intl Libraries
These libraries are maintained, but carry the burden of packaging their own time zone data, which can be quite large.
js-joda/timezone (extension for js-joda)
moment-timezone* (extension for Moment.js)
date-fns-timezone (extension for older 1.x of date-fns)
BigEasy/TimeZone
tz.js
* While Moment and Moment-Timezone were previously recommended, the Moment team now prefers users chose Luxon for new development.
Discontinued Libraries
These libraries have been officially discontinued and should no longer be used.
WallTime-js
TimeZoneJS
Future Proposals
The TC39 Temporal Proposal aims to provide a new set of standard objects for working with dates and times in the JavaScript language itself. This will include support for a time zone aware object.
Common Errors
There are several approaches that are often tried, which are in error and should usually be avoided.
Re-Parsing
new Date(new Date().toLocaleString('en', {timeZone: 'America/New_York'}))
The above approach correctly uses the Intl API to create a string in a specific time zone, but then it incorrectly passes that string back into the Date constructor. In this case, parsing will be implementation-specific, and may fail entirely. If successful, it is likely that the resulting Date object now represents the wrong instant in time, as the computer's local time zone would be applied during parsing.
Epoch Shifting
var d = new Date();
d.setTime(d.getTime() + someOffset * 60000);
The above approach attempts to manipulate the Date object's time zone by shifting the Unix timestamp by some other time zone offset. However, since the Date object only tracks time in UTC, it actually just makes the Date object represent a different point in time.
The same approach is sometimes used directly on the constructor, and is also invalid.
Epoch Shifting is sometimes used internally in date libraries as a shortcut to avoid writing calendar arithmetic. When doing so, any access to non-UTC properties must be avoided. For example, once shifted, a call to getUTCHours would be acceptable, but a call to getHours would be invalid because it uses the local time zone.
It is called "epoch shifting", because when used correctly, the Unix Epoch (1970-01-01T00:00:00.000Z) is now no longer correlated to a timestamp of 0 but has shifted to a different timestamp by the amount of the offset.
If you're not authoring a date library, you should not be epoch shifting.
For more details about epoch shifting, watch this video clip from Greg Miller at CppCon 2015. The video is about time_t in C++, but the explanation and problems are identical. (For JavaScript folks, every time you hear Greg mention time_t, just think "Date object".)
Trying to make a "UTC Date"
var d = new Date();
var utcDate = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()));
In this example, both d and utcDate are identical. The work to construct utcDate was redundant, because d is already in terms of UTC. Examining the output of toISOString, getTime, or valueOf functions will show identical values for both variables.
A similar approach seen is:
var d = new Date();
var utcDate = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
This is approach passes UTC values into the Date constructor where local time values are expected. The resulting Date object now represents a completely different point in time. It is essentially the same result as epoch shifting described earlier, and thus should be avoided.
The correct way to get a UTC-based Date object is simply new Date(). If you need a string representation that is in UTC, then use new Date().toISOString().
As Matt Johnson said
If you can limit your usage to modern web browsers, you can now do the
following without any special libraries:
new Date().toLocaleString("en-US", {timeZone: "America/New_York"})
This isn't a comprehensive solution, but it works for many scenarios
that require only output conversion (from UTC or local time to a
specific time zone, but not the other direction).
So although the browser can not read IANA timezones when creating a date, or has any methods to change the timezones on an existing Date object, there seems to be a hack around it:
function changeTimezone(date, ianatz) {
// suppose the date is 12:00 UTC
var invdate = new Date(date.toLocaleString('en-US', {
timeZone: ianatz
}));
// then invdate will be 07:00 in Toronto
// and the diff is 5 hours
var diff = date.getTime() - invdate.getTime();
// so 12:00 in Toronto is 17:00 UTC
return new Date(date.getTime() - diff); // needs to substract
}
// E.g.
var here = new Date();
var there = changeTimezone(here, "America/Toronto");
console.log(`Here: ${here.toString()}\nToronto: ${there.toString()}`);
This should solve your problem, please feel free to offer fixes. This method will account also for daylight saving time for the given date.
dateWithTimeZone = (timeZone, year, month, day, hour, minute, second) => {
let date = new Date(Date.UTC(year, month, day, hour, minute, second));
let utcDate = new Date(date.toLocaleString('en-US', { timeZone: "UTC" }));
let tzDate = new Date(date.toLocaleString('en-US', { timeZone: timeZone }));
let offset = utcDate.getTime() - tzDate.getTime();
date.setTime( date.getTime() + offset );
return date;
};
How to use with timezone and local time:
dateWithTimeZone("America/Los_Angeles",2019,8,8,0,0,0)
You can specify a time zone offset on new Date(), for example:
new Date('Feb 28 2013 19:00:00 EST')
or
new Date('Feb 28 2013 19:00:00 GMT-0500')
Since Date store UTC time ( i.e. getTime returns in UTC ), javascript will them convert the time into UTC, and when you call things like toString javascript will convert the UTC time into browser's local timezone and return the string in local timezone, i.e. If I'm using UTC+8:
> new Date('Feb 28 2013 19:00:00 GMT-0500').toString()
< "Fri Mar 01 2013 08:00:00 GMT+0800 (CST)"
Also you can use normal getHours/Minute/Second method:
> new Date('Feb 28 2013 19:00:00 GMT-0500').getHours()
< 8
( This 8 means after the time is converted into my local time - UTC+8, the hours number is 8. )
I found the most supported way to do this, without worrying about a third party library, was by using getTimezoneOffset to calculate the appropriate timestamp, or update the time then use the normal methods to get the necessary date and time.
var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);
// ET timezone offset in hours.
var timezone = -5;
// Timezone offset in minutes + the desired offset in minutes, converted to ms.
// This offset should be the same for ALL date calculations, so you should only need to calculate it once.
var offset = (mydate.getTimezoneOffset() + (timezone * 60)) * 60 * 1000;
// Use the timestamp and offset as necessary to calculate min/sec etc, i.e. for countdowns.
var timestamp = mydate.getTime() + offset,
seconds = Math.floor(timestamp / 1000) % 60,
minutes = Math.floor(timestamp / 1000 / 60) % 60,
hours = Math.floor(timestamp / 1000 / 60 / 60);
// Or update the timestamp to reflect the timezone offset.
mydate.setTime(mydate.getTime() + offset);
// Then Output dates and times using the normal methods.
var date = mydate.getDate(),
hour = mydate.getHours();
EDIT
I was previously using UTC methods when performing the date transformations, which was incorrect. With adding the offset to the time, using the local get functions will return the desired results.
For Ionic users, I had hell with this because .toISOString() has to be used with the html template.
This will grab the current date, but of course can be added to previous answers for a selected date.
I got it fixed using this:
date = new Date();
public currentDate: any = new Date(this.date.getTime() - this.date.getTimezoneOffset()*60000).toISOString();
The *60000 is indicating the UTC -6 which is CST so whatever TimeZone is needed, the number and difference can be changed.
I ran into a similar problem with unit tests (specifically in jest when the unit tests run locally to create the snapshots and then the CI server runs in (potentially) a different timezone causing the snapshot comparison to fail). I mocked our Date and some of the supporting methods like so:
describe('...', () => {
let originalDate;
beforeEach(() => {
originalDate = Date;
Date = jest.fn(
(d) => {
let newD;
if (d) {
newD = (new originalDate(d));
} else {
newD = (new originalDate('2017-05-29T10:00:00z'));
}
newD.toLocaleString = () => {
return (new originalDate(newD.valueOf())).toLocaleString("en-US", {timeZone: "America/New_York"});
};
newD.toLocaleDateString = () => {
return (new originalDate(newD.valueOf())).toLocaleDateString("en-US", {timeZone: "America/New_York"});
};
newD.toLocaleTimeString = () => {
return (new originalDate(newD.valueOf())).toLocaleTimeString("en-US", {timeZone: "America/New_York"});
};
return newD;
}
);
Date.now = () => { return (Date()); };
});
afterEach(() => {
Date = originalDate;
});
});
I had the same problem but we can use the time zone we want
we use .toLocaleDateString()
eg:
var day=new Date();
const options= {day:'numeric', month:'long', year:"numeric", timeZone:"Asia/Kolkata"};
const today=day.toLocaleDateString("en-IN", options);
console.log(today);
I ran into this issue running a GCP Cloud Function. Of course it works on a local machine, but running in the cloud makes the OS default (local) for new Date() irrelevant. In my case, an api call from the cloud required Eastern Standard Time, in ISO format (without the "Z") with offset as "-0500" or "-0400" depending on DST, for example:
2021-12-01T00:00:00.000-0500
Again, this is not a browser formatting issue, so I am forced into this format for the api call to work correctly.
Using #chickens code as a start, this is what worked:
var date = new Date();
var now_utc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),
date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
var dt = new Date(now_utc);
let utcDate = new Date(dt.toLocaleString('en-US', { timeZone: "UTC" }));
let tzDate = new Date(dt.toLocaleString('en-US', { timeZone: "America/New_York" }));
let offset1 = utcDate.getTime() - tzDate.getTime();
let offset2 = offset1/60000;
let o1 = Math.abs(offset2);
console.log(offset2)
var offsetValue1 = (offset2 < 0 ? "+" : "-") + ("00" + Math.floor(o1 / 60)).slice(-2) + ("00" + (o1 % 60)).slice(-2);
console.log(offsetValue1)
dt.setTime(dt.getTime() - offset1);
console.log(dt.toISOString());
console.log(dt.toISOString().slice(0,-1)+offsetValue1);
Try using ctoc from npm.
https://www.npmjs.com/package/ctoc_timezone
It has got simple functionality to change timezones (most timezones around 400) and all custom formats u want it to display.
Building on the answers above, I am using this native one liner to convert the long timezone string to the three letter string:
var longTz = 'America/Los_Angeles';
var shortTz = new Date().
toLocaleString("en", {timeZoneName: "short", timeZone: longTz}).
split(' ').
pop();
This will give PDT or PST depending on the date provided. In my particular use case, developing on Salesforce (Aura/Lightning), we are able to get the user timezone in the long format from the backend.
Thanks to #commonpike answer, I wrote a function which takes an ISO String date such as 2020-10-10T08:00:00.000 as input and send an object which contains 2 main properties.
The first one is fromUtc is a Date corresponding to the timeZone entered as parameter.
The second one is toUtc which lets you to format a Date stemming from fromUtc.
const timeZoneTransformer = (stringDate, timeZone = "Europe/Paris") => {
const now = new Date();
const serverDate = new Date(stringDate);
const utcDate = new Date(
Date.UTC(
serverDate.getFullYear(),
serverDate.getMonth(),
serverDate.getDate(),
serverDate.getHours(),
serverDate.getMinutes(),
serverDate.getSeconds()
)
);
const invdate = new Date(
serverDate.toLocaleString("en-US", {
timeZone,
})
);
const diff = now.getTime() - invdate.getTime();
const adjustedDate = new Date(now.getTime() - diff);
return {
toUtc: utcDate,
fromUtc: adjustedDate,
};
};
const fromUtc = timeZoneTransformer("2020-10-10T08:00:00.000").fromUtc;
console.log(fromUtc);
const toUtc = timeZoneTransformer(fromUtc).toUtc;
console.log(toUtc);
Try: date-from-timezone, it resolves expected date with help of natively available Intl.DateTimeFormat.
I used that method in one of my projects for few years already, but it's now I decided to publish it as small OS project :)
Try something like this,
public static getTimezoneOffset(timeZone: string, date = new Date()): number {
const localDate = date.toLocaleString('fr', { timeZone, timeZoneName: 'long' });
const tz = localDate.split(' ');
const TZ = localDate.replace(tz[0], '').replace(tz[1], '').replace(' ', '');
const dateString = date.toString();
const offset = (Date.parse(`${dateString} UTC`) - Date.parse(`${dateString}${TZ}`)) / (3600 * 1000);
return offset;
}
I'm not sure why all these answers are so complicated. Just use YYYY-MM-DD ZZZ when creating a date-only date in the local / desired time zone.
Create a local date:
var myDate = new Date('2022-11-29 CST')
The date will be stored in storage as UTC, great.
Get the date out of storage and display it as local:
myDate.toLocaleDateString()
11/29/2022
I know its 3 years too late, but maybe it can help someone else because I haven't found anything like that except for the moment-timezone library, which is not exactly the same as what he's asking for here.
I've done something similar for german timezone,
this is a little complex because of daylight saving time and leap years where you have 366 days.
it might need a little work with the "isDaylightSavingTimeInGermany" function while different timezones change on different times the daylight saving time.
anyway, check out this page:
https://github.com/zerkotin/german-timezone-converter/wiki
the main methods are:
convertLocalDateToGermanTimezone
convertGermanDateToLocalTimezone
I've put an effort into documenting it, so it won't be so confusing.
There are several working answers here, but somehow a lot of them seemed to get you to the string, but not back to a date object you started with, so here's my simple non-function take on how to change timezone on JS date:
var TZ='Australia/Brisbane'; //Target timezone from server
var date = new Date(); //Init this to a time if you don't want current time
date=new Date(Date.parse(date.toLocaleString("en-US", {timeZone: TZ})));
//Just a clarification on what happens
// 1) First new Date() gives you a Date object at current time in the clients browser local timezone
// 2) .toLocaleString takes that time, and returns a string if time in the target timezone
// 3) Date.parse converts that new string to a Unix epoch number
// 4) new Date() converts the Unix epoch into a Date object in the new TimeZone.
// Now I can use my usual getHours and other Date functions as required.
Hope that helps others (if you get to this bottom answer!)
Simple with Node.JS support
Pass in the amount of hours your timezone is offset from UTC
function initDateInTimezone(offsetHours) {
const timezoneOffsetInMS = offsetHours * 60 * 60000;
let d = new Date().getTimezoneOffset() * 60000 + timezoneOffsetInMS;
const date = new Date(new Date().getTime() - d);
return date
}
//For Mumbai time difference is 5.5 hrs so
city_time_diff=5.5; //change according to your city
let time_now = Date.now();
time_now = time_now + (3600000 * city_time_diff); //Add our city time (in msec);
let new_date = new Date(time_now);
console.log("My city time is: ", new_date);
Was facing the same issue, used this one
Console.log(Date.parse("Jun 13, 2018 10:50:39 GMT+1"));
It will return milliseconds to which u can check have +100 timzone intialize British time
Hope it helps!!

Adding dynamic date to a static webpage

I want my static webpage timezone needs to be relative to CST, so if client(CST) open this file it should show CST date and Myself(IST) if I open this also it should show only the CST, could anyone please help me on this
HTML file-
<span id="spanDate"></span>
JS file-
var months = ['January','February','March','April','May','June','July',
'August','September','October','November','December'];
const weekday = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
var tomorrow = new Date();
document.getElementById("spanDate").innerHTML = months[tomorrow.getMonth()] + " " +
tomorrow.getDate()+ ", " + tomorrow.getFullYear();
You shouldn't try to assemble a date string yourself. Both the names of the month, as well as the typical arrangement of the year, month, and day parts are very locale-specific. Instead, use toLocaleString, which has options to control output, including which time zone to use.
I'll assume by "CST" you meant the "Central Standard Time" in the US. If you actually meant "China Standard Time", or "Cuba Standard Time", you'll need to change the time zone ID in the code below, to the desired IANA time zone identifier.
Also, your code used the word "tomorrow", so I presume you want tomorrow's date - but you were only getting today's date. If you need today's date, you can take out the second step in the code below.
// Get the current point in time
const timestamp = new Date();
// advance by 24 hours, to get to tomorrow
timestamp.setTime(timestamp.getTime() + (24 * 60 * 60 * 1000));
// format and output the result
const locale = undefined; // use the user's current locale (language/region)
document.getElementById("spanDate").innerHTML = timestamp.toLocaleString(locale, {
timeZone: 'America/Chicago', // use the US Central Time Zone
year: 'numeric', // include the year as a number
month: 'long', // include the month as the long name
day: 'numeric' // include the day as a number
});
<span id="spanDate"></span>
Also, note that while advancing by 24 hours to get tomorrow's date is the easiest approach, there are some edge cases near daylight saving time transitions in certain time zones where it could be a bit off (due to having 23 or 25 hours on such days, etc.). Working around that is currently quite complicated unless you use a library like Luxon. But if you don't require such precision, then 24 hours is fine.

JavaScript Date() - getting / offsetting multiple timezones

I'm not a noobie to js, but haven't done a ton of work with dates.
I need to get "now" in three GMT time zones (offsets +5:30, +7, +8) and I'm confused as to whether var now = new Date(); would be the local "now" anywhere in the world, or do I need to calculate a separate "now" for each timezone to do my evaluations based on GMT or UTC.
I then need to compare "now" var against a date (November 19, 2019 10:00 AM) in those three timezone. For example,
let now = new Date();
let presale530 = new Date('11-19-2019 10:00 AM GMT+5:30'); // Bangalore
if (now > presale530) {
// start the presale in Bangalore
}
The above needs to happen simultaneously with a different time zone:
let now = new Date();
let presale7 = new Date('11-19-2019 10:00 AM GMT+7'); // Jakarta
if (now > presale7) {
// start the presale in Jakarta
}
new Date() returns the date and time in the timezone specified by the browser. edit: As pointed out by RobG, this is wrong. new Date() returns an object with the actual UTC time. It is the methods like toString() or plain get methods that depends on the browser/system. Each browser behaves differently, some are in the settings, some inherit from the system timezone.
So it depends on your business logic. It seems like you are targeting different locations, so your now will work fine assuming that the user do not tamper with their devices/browsers timezone and let them set to whichever location they are at. If you have some other code to determine their location via ip, then serve the respective code to the area, instead of relying on their browser/system settings, then your now will not be sufficient. Use Date().getTime() instead to get absolute epoch time then format it in the timezone you want.
So it depends whether you trust the user, and if you have a better way to locate the user and serve the appropriate code.
Edit:
After relooking at your question, it seems like you are writing 3 sets of code for 3 separate pages. I assume you have a backend detecting ip and serving 3 different sites, perhaps with different .us, .ca, .cn, etc..
In that case, you would want each site to start the presale at the same time and not depend on the browser/computer setting. That is a business logic you have to clarify. If this is the case, it is best to use getTime() and format it in the timezone you desire for comparison.
I'm confused as to whether var now = new Date(); would be the local "now" anywhere in the world, or do I need to calculate a separate "now" for each timezone to do my evaluations based on GMT or UTC.
Dates are UTC, so "now" will be the same regardless of the local offset with the caveat that the system clocks must be correctly set. The system timezone offset is only used where local values are assumed (plain set methods, parsing strings without an offset, etc.).
Date.prototype.toString returns a string based on the host system timezone offset and the plain get methods return local values.
The getUTC methods return UTC values and should all be the same regardless of host system settings (with the same caveat as above).
However, if you have a string like "November 19, 2019 10:00 AM" without a timezone offset, then you'll have to manually parse and apply the offset (either write your own function or use a library).
E.g. A function to parse a string like "November 19, 2019 10:00 AM" as UTC and apply a timezone offset like +05:30 is:
/* Parse string in format MMMM DD, YYYY hh:mm a as UTC and apply
** a timezone offset in format +/-HH:mm)
**
** #param {string} s - string to parse
** #param {string} offset - +/-HH:mm default '+00:00'
** #returns {Date}
*/
function myParse(s, offset = '+00:00') {
let months = ['jan','feb','mar','apr','may','jun',
'jul','aug','sep','oct','nov','dec'];
let b = s.split(/[ ,:]+/);
let m = months.indexOf(b[0].toLowerCase().substr(0,3));
let hr = +b[3];
let min = +b[4];
let ap = b[5];
hr = (hr % 12) + (ap.toLowerCase() == 'am'? 0 : 12);
// Get hr and min of timezone offset with sign
let c = offset.split(':');
let oSign = c[0] < 0? '-' : '+';
let oHr = +c[0]
let oMin = c[1] * (oSign == '-'? -1 : 1);
// Create date using values as UTC, apply offset
return new Date(Date.UTC(b[2], m, b[1], hr + oHr, min + oMin));
}
// +00:00 - i.e. UTC
console.log(myParse("November 19, 2019 10:00 AM"));
// +05:30
console.log(myParse("November 19, 2019 10:00 AM", '+05:30'));
// -07:00
console.log(myParse("November 19, 2019 12:00 AM", '-07:00'));
// Difference in dates is 12:30, which is the difference in timezone offsets
However, if you have other date arithmetic to perform or different formats to support, a library may help.

Automatical timezone [duplicate]

I have date time in a particular timezone as a string and I want to convert this to the local time. But, I don't know how to set the timezone in the Date object.
For example, I have Feb 28 2013 7:00 PM ET, then I can
var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);
As far as I know, I can either set the UTC time or local time. But, how do I set time in another timezone?
I tried to use the add/subtract the offset from UTC but I don't know how to counter daylight savings. Am not sure if I am heading the right direction.
How can I go about converting time from a different timezone to local time in javascript?
Background
JavaScript's Date object tracks time in UTC internally, but typically accepts input and produces output in the local time of the computer it's running on. It has very few facilities for working with time in other time zones.
The internal representation of a Date object is a single number, representing the number of milliseconds that have elapsed since 1970-01-01 00:00:00 UTC, without regard to leap seconds.
There is no time zone or string format stored in the Date object itself.
When various functions of the Date object are used, the computer's local time zone is applied to the internal representation. If the function produces a string, then the computer's locale information may be taken into consideration to determine how to produce that string. The details vary per function, and some are implementation-specific.
The only operations the Date object can do with non-local time zones are:
It can parse a string containing a numeric UTC offset from any time zone. It uses this to adjust the value being parsed, and stores the UTC equivalent. The original local time and offset are not retained in the resulting Date object. For example:
var d = new Date("2020-04-13T00:00:00.000+08:00");
d.toISOString() //=> "2020-04-12T16:00:00.000Z"
d.valueOf() //=> 1586707200000 (this is what is actually stored in the object)
In environments that have implemented the ECMASCript Internationalization API (aka "Intl"), a Date object can produce a locale-specific string adjusted to a given time zone identifier. This is accomplished via the timeZone option to toLocaleString and its variations. Most implementations will support IANA time zone identifiers, such as 'America/New_York'. For example:
var d = new Date("2020-04-13T00:00:00.000+08:00");
d.toLocaleString('en-US', { timeZone: 'America/New_York' })
//=> "4/12/2020, 12:00:00 PM"
// (midnight in China on Apring 13th is noon in New York on April 12th)
Most modern environments support the full set of IANA time zone identifiers (see the compatibility table here). However, keep in mind that the only identifier required to be supported by Intl is 'UTC', thus you should check carefully if you need to support older browsers or atypical environments (for example, lightweight IoT devices).
Libraries
There are several libraries that can be used to work with time zones. Though they still cannot make the Date object behave any differently, they typically implement the standard IANA timezone database and provide functions for using it in JavaScript. Modern libraries use the time zone data supplied by the Intl API, but older libraries typically have overhead, especially if you are running in a web browser, as the database can get a bit large. Some of these libraries also allow you to selectively reduce the data set, either by which time zones are supported and/or by the range of dates you can work with.
Here are the libraries to consider:
Intl-based Libraries
New development should choose from one of these implementations, which rely on the Intl API for their time zone data:
Luxon (successor of Moment.js)
date-fns-tz (extension for date-fns)
Day.js (when using its Timezone plugin)
Non-Intl Libraries
These libraries are maintained, but carry the burden of packaging their own time zone data, which can be quite large.
js-joda/timezone (extension for js-joda)
moment-timezone* (extension for Moment.js)
date-fns-timezone (extension for older 1.x of date-fns)
BigEasy/TimeZone
tz.js
* While Moment and Moment-Timezone were previously recommended, the Moment team now prefers users chose Luxon for new development.
Discontinued Libraries
These libraries have been officially discontinued and should no longer be used.
WallTime-js
TimeZoneJS
Future Proposals
The TC39 Temporal Proposal aims to provide a new set of standard objects for working with dates and times in the JavaScript language itself. This will include support for a time zone aware object.
Common Errors
There are several approaches that are often tried, which are in error and should usually be avoided.
Re-Parsing
new Date(new Date().toLocaleString('en', {timeZone: 'America/New_York'}))
The above approach correctly uses the Intl API to create a string in a specific time zone, but then it incorrectly passes that string back into the Date constructor. In this case, parsing will be implementation-specific, and may fail entirely. If successful, it is likely that the resulting Date object now represents the wrong instant in time, as the computer's local time zone would be applied during parsing.
Epoch Shifting
var d = new Date();
d.setTime(d.getTime() + someOffset * 60000);
The above approach attempts to manipulate the Date object's time zone by shifting the Unix timestamp by some other time zone offset. However, since the Date object only tracks time in UTC, it actually just makes the Date object represent a different point in time.
The same approach is sometimes used directly on the constructor, and is also invalid.
Epoch Shifting is sometimes used internally in date libraries as a shortcut to avoid writing calendar arithmetic. When doing so, any access to non-UTC properties must be avoided. For example, once shifted, a call to getUTCHours would be acceptable, but a call to getHours would be invalid because it uses the local time zone.
It is called "epoch shifting", because when used correctly, the Unix Epoch (1970-01-01T00:00:00.000Z) is now no longer correlated to a timestamp of 0 but has shifted to a different timestamp by the amount of the offset.
If you're not authoring a date library, you should not be epoch shifting.
For more details about epoch shifting, watch this video clip from Greg Miller at CppCon 2015. The video is about time_t in C++, but the explanation and problems are identical. (For JavaScript folks, every time you hear Greg mention time_t, just think "Date object".)
Trying to make a "UTC Date"
var d = new Date();
var utcDate = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()));
In this example, both d and utcDate are identical. The work to construct utcDate was redundant, because d is already in terms of UTC. Examining the output of toISOString, getTime, or valueOf functions will show identical values for both variables.
A similar approach seen is:
var d = new Date();
var utcDate = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
This is approach passes UTC values into the Date constructor where local time values are expected. The resulting Date object now represents a completely different point in time. It is essentially the same result as epoch shifting described earlier, and thus should be avoided.
The correct way to get a UTC-based Date object is simply new Date(). If you need a string representation that is in UTC, then use new Date().toISOString().
As Matt Johnson said
If you can limit your usage to modern web browsers, you can now do the
following without any special libraries:
new Date().toLocaleString("en-US", {timeZone: "America/New_York"})
This isn't a comprehensive solution, but it works for many scenarios
that require only output conversion (from UTC or local time to a
specific time zone, but not the other direction).
So although the browser can not read IANA timezones when creating a date, or has any methods to change the timezones on an existing Date object, there seems to be a hack around it:
function changeTimezone(date, ianatz) {
// suppose the date is 12:00 UTC
var invdate = new Date(date.toLocaleString('en-US', {
timeZone: ianatz
}));
// then invdate will be 07:00 in Toronto
// and the diff is 5 hours
var diff = date.getTime() - invdate.getTime();
// so 12:00 in Toronto is 17:00 UTC
return new Date(date.getTime() - diff); // needs to substract
}
// E.g.
var here = new Date();
var there = changeTimezone(here, "America/Toronto");
console.log(`Here: ${here.toString()}\nToronto: ${there.toString()}`);
This should solve your problem, please feel free to offer fixes. This method will account also for daylight saving time for the given date.
dateWithTimeZone = (timeZone, year, month, day, hour, minute, second) => {
let date = new Date(Date.UTC(year, month, day, hour, minute, second));
let utcDate = new Date(date.toLocaleString('en-US', { timeZone: "UTC" }));
let tzDate = new Date(date.toLocaleString('en-US', { timeZone: timeZone }));
let offset = utcDate.getTime() - tzDate.getTime();
date.setTime( date.getTime() + offset );
return date;
};
How to use with timezone and local time:
dateWithTimeZone("America/Los_Angeles",2019,8,8,0,0,0)
You can specify a time zone offset on new Date(), for example:
new Date('Feb 28 2013 19:00:00 EST')
or
new Date('Feb 28 2013 19:00:00 GMT-0500')
Since Date store UTC time ( i.e. getTime returns in UTC ), javascript will them convert the time into UTC, and when you call things like toString javascript will convert the UTC time into browser's local timezone and return the string in local timezone, i.e. If I'm using UTC+8:
> new Date('Feb 28 2013 19:00:00 GMT-0500').toString()
< "Fri Mar 01 2013 08:00:00 GMT+0800 (CST)"
Also you can use normal getHours/Minute/Second method:
> new Date('Feb 28 2013 19:00:00 GMT-0500').getHours()
< 8
( This 8 means after the time is converted into my local time - UTC+8, the hours number is 8. )
I found the most supported way to do this, without worrying about a third party library, was by using getTimezoneOffset to calculate the appropriate timestamp, or update the time then use the normal methods to get the necessary date and time.
var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);
// ET timezone offset in hours.
var timezone = -5;
// Timezone offset in minutes + the desired offset in minutes, converted to ms.
// This offset should be the same for ALL date calculations, so you should only need to calculate it once.
var offset = (mydate.getTimezoneOffset() + (timezone * 60)) * 60 * 1000;
// Use the timestamp and offset as necessary to calculate min/sec etc, i.e. for countdowns.
var timestamp = mydate.getTime() + offset,
seconds = Math.floor(timestamp / 1000) % 60,
minutes = Math.floor(timestamp / 1000 / 60) % 60,
hours = Math.floor(timestamp / 1000 / 60 / 60);
// Or update the timestamp to reflect the timezone offset.
mydate.setTime(mydate.getTime() + offset);
// Then Output dates and times using the normal methods.
var date = mydate.getDate(),
hour = mydate.getHours();
EDIT
I was previously using UTC methods when performing the date transformations, which was incorrect. With adding the offset to the time, using the local get functions will return the desired results.
For Ionic users, I had hell with this because .toISOString() has to be used with the html template.
This will grab the current date, but of course can be added to previous answers for a selected date.
I got it fixed using this:
date = new Date();
public currentDate: any = new Date(this.date.getTime() - this.date.getTimezoneOffset()*60000).toISOString();
The *60000 is indicating the UTC -6 which is CST so whatever TimeZone is needed, the number and difference can be changed.
I ran into this issue running a GCP Cloud Function. Of course it works on a local machine, but running in the cloud makes the OS default (local) for new Date() irrelevant. In my case, an api call from the cloud required Eastern Standard Time, in ISO format (without the "Z") with offset as "-0500" or "-0400" depending on DST, for example:
2021-12-01T00:00:00.000-0500
Again, this is not a browser formatting issue, so I am forced into this format for the api call to work correctly.
Using #chickens code as a start, this is what worked:
var date = new Date();
var now_utc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),
date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
var dt = new Date(now_utc);
let utcDate = new Date(dt.toLocaleString('en-US', { timeZone: "UTC" }));
let tzDate = new Date(dt.toLocaleString('en-US', { timeZone: "America/New_York" }));
let offset1 = utcDate.getTime() - tzDate.getTime();
let offset2 = offset1/60000;
let o1 = Math.abs(offset2);
console.log(offset2)
var offsetValue1 = (offset2 < 0 ? "+" : "-") + ("00" + Math.floor(o1 / 60)).slice(-2) + ("00" + (o1 % 60)).slice(-2);
console.log(offsetValue1)
dt.setTime(dt.getTime() - offset1);
console.log(dt.toISOString());
console.log(dt.toISOString().slice(0,-1)+offsetValue1);
I ran into a similar problem with unit tests (specifically in jest when the unit tests run locally to create the snapshots and then the CI server runs in (potentially) a different timezone causing the snapshot comparison to fail). I mocked our Date and some of the supporting methods like so:
describe('...', () => {
let originalDate;
beforeEach(() => {
originalDate = Date;
Date = jest.fn(
(d) => {
let newD;
if (d) {
newD = (new originalDate(d));
} else {
newD = (new originalDate('2017-05-29T10:00:00z'));
}
newD.toLocaleString = () => {
return (new originalDate(newD.valueOf())).toLocaleString("en-US", {timeZone: "America/New_York"});
};
newD.toLocaleDateString = () => {
return (new originalDate(newD.valueOf())).toLocaleDateString("en-US", {timeZone: "America/New_York"});
};
newD.toLocaleTimeString = () => {
return (new originalDate(newD.valueOf())).toLocaleTimeString("en-US", {timeZone: "America/New_York"});
};
return newD;
}
);
Date.now = () => { return (Date()); };
});
afterEach(() => {
Date = originalDate;
});
});
I had the same problem but we can use the time zone we want
we use .toLocaleDateString()
eg:
var day=new Date();
const options= {day:'numeric', month:'long', year:"numeric", timeZone:"Asia/Kolkata"};
const today=day.toLocaleDateString("en-IN", options);
console.log(today);
Try using ctoc from npm.
https://www.npmjs.com/package/ctoc_timezone
It has got simple functionality to change timezones (most timezones around 400) and all custom formats u want it to display.
Building on the answers above, I am using this native one liner to convert the long timezone string to the three letter string:
var longTz = 'America/Los_Angeles';
var shortTz = new Date().
toLocaleString("en", {timeZoneName: "short", timeZone: longTz}).
split(' ').
pop();
This will give PDT or PST depending on the date provided. In my particular use case, developing on Salesforce (Aura/Lightning), we are able to get the user timezone in the long format from the backend.
Thanks to #commonpike answer, I wrote a function which takes an ISO String date such as 2020-10-10T08:00:00.000 as input and send an object which contains 2 main properties.
The first one is fromUtc is a Date corresponding to the timeZone entered as parameter.
The second one is toUtc which lets you to format a Date stemming from fromUtc.
const timeZoneTransformer = (stringDate, timeZone = "Europe/Paris") => {
const now = new Date();
const serverDate = new Date(stringDate);
const utcDate = new Date(
Date.UTC(
serverDate.getFullYear(),
serverDate.getMonth(),
serverDate.getDate(),
serverDate.getHours(),
serverDate.getMinutes(),
serverDate.getSeconds()
)
);
const invdate = new Date(
serverDate.toLocaleString("en-US", {
timeZone,
})
);
const diff = now.getTime() - invdate.getTime();
const adjustedDate = new Date(now.getTime() - diff);
return {
toUtc: utcDate,
fromUtc: adjustedDate,
};
};
const fromUtc = timeZoneTransformer("2020-10-10T08:00:00.000").fromUtc;
console.log(fromUtc);
const toUtc = timeZoneTransformer(fromUtc).toUtc;
console.log(toUtc);
Try: date-from-timezone, it resolves expected date with help of natively available Intl.DateTimeFormat.
I used that method in one of my projects for few years already, but it's now I decided to publish it as small OS project :)
Try something like this,
public static getTimezoneOffset(timeZone: string, date = new Date()): number {
const localDate = date.toLocaleString('fr', { timeZone, timeZoneName: 'long' });
const tz = localDate.split(' ');
const TZ = localDate.replace(tz[0], '').replace(tz[1], '').replace(' ', '');
const dateString = date.toString();
const offset = (Date.parse(`${dateString} UTC`) - Date.parse(`${dateString}${TZ}`)) / (3600 * 1000);
return offset;
}
I'm not sure why all these answers are so complicated. Just use YYYY-MM-DD ZZZ when creating a date-only date in the local / desired time zone.
Create a local date:
var myDate = new Date('2022-11-29 CST')
The date will be stored in storage as UTC, great.
Get the date out of storage and display it as local:
myDate.toLocaleDateString()
11/29/2022
I know its 3 years too late, but maybe it can help someone else because I haven't found anything like that except for the moment-timezone library, which is not exactly the same as what he's asking for here.
I've done something similar for german timezone,
this is a little complex because of daylight saving time and leap years where you have 366 days.
it might need a little work with the "isDaylightSavingTimeInGermany" function while different timezones change on different times the daylight saving time.
anyway, check out this page:
https://github.com/zerkotin/german-timezone-converter/wiki
the main methods are:
convertLocalDateToGermanTimezone
convertGermanDateToLocalTimezone
I've put an effort into documenting it, so it won't be so confusing.
There are several working answers here, but somehow a lot of them seemed to get you to the string, but not back to a date object you started with, so here's my simple non-function take on how to change timezone on JS date:
var TZ='Australia/Brisbane'; //Target timezone from server
var date = new Date(); //Init this to a time if you don't want current time
date=new Date(Date.parse(date.toLocaleString("en-US", {timeZone: TZ})));
//Just a clarification on what happens
// 1) First new Date() gives you a Date object at current time in the clients browser local timezone
// 2) .toLocaleString takes that time, and returns a string if time in the target timezone
// 3) Date.parse converts that new string to a Unix epoch number
// 4) new Date() converts the Unix epoch into a Date object in the new TimeZone.
// Now I can use my usual getHours and other Date functions as required.
Hope that helps others (if you get to this bottom answer!)
Simple with Node.JS support
Pass in the amount of hours your timezone is offset from UTC
function initDateInTimezone(offsetHours) {
const timezoneOffsetInMS = offsetHours * 60 * 60000;
let d = new Date().getTimezoneOffset() * 60000 + timezoneOffsetInMS;
const date = new Date(new Date().getTime() - d);
return date
}
//For Mumbai time difference is 5.5 hrs so
city_time_diff=5.5; //change according to your city
let time_now = Date.now();
time_now = time_now + (3600000 * city_time_diff); //Add our city time (in msec);
let new_date = new Date(time_now);
console.log("My city time is: ", new_date);
Was facing the same issue, used this one
Console.log(Date.parse("Jun 13, 2018 10:50:39 GMT+1"));
It will return milliseconds to which u can check have +100 timzone intialize British time
Hope it helps!!

TimeZone specific timestamp conversion using plain JavaScript in Safari [duplicate]

I have date time in a particular timezone as a string and I want to convert this to the local time. But, I don't know how to set the timezone in the Date object.
For example, I have Feb 28 2013 7:00 PM ET, then I can
var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);
As far as I know, I can either set the UTC time or local time. But, how do I set time in another timezone?
I tried to use the add/subtract the offset from UTC but I don't know how to counter daylight savings. Am not sure if I am heading the right direction.
How can I go about converting time from a different timezone to local time in javascript?
Background
JavaScript's Date object tracks time in UTC internally, but typically accepts input and produces output in the local time of the computer it's running on. It has very few facilities for working with time in other time zones.
The internal representation of a Date object is a single number, representing the number of milliseconds that have elapsed since 1970-01-01 00:00:00 UTC, without regard to leap seconds.
There is no time zone or string format stored in the Date object itself.
When various functions of the Date object are used, the computer's local time zone is applied to the internal representation. If the function produces a string, then the computer's locale information may be taken into consideration to determine how to produce that string. The details vary per function, and some are implementation-specific.
The only operations the Date object can do with non-local time zones are:
It can parse a string containing a numeric UTC offset from any time zone. It uses this to adjust the value being parsed, and stores the UTC equivalent. The original local time and offset are not retained in the resulting Date object. For example:
var d = new Date("2020-04-13T00:00:00.000+08:00");
d.toISOString() //=> "2020-04-12T16:00:00.000Z"
d.valueOf() //=> 1586707200000 (this is what is actually stored in the object)
In environments that have implemented the ECMASCript Internationalization API (aka "Intl"), a Date object can produce a locale-specific string adjusted to a given time zone identifier. This is accomplished via the timeZone option to toLocaleString and its variations. Most implementations will support IANA time zone identifiers, such as 'America/New_York'. For example:
var d = new Date("2020-04-13T00:00:00.000+08:00");
d.toLocaleString('en-US', { timeZone: 'America/New_York' })
//=> "4/12/2020, 12:00:00 PM"
// (midnight in China on Apring 13th is noon in New York on April 12th)
Most modern environments support the full set of IANA time zone identifiers (see the compatibility table here). However, keep in mind that the only identifier required to be supported by Intl is 'UTC', thus you should check carefully if you need to support older browsers or atypical environments (for example, lightweight IoT devices).
Libraries
There are several libraries that can be used to work with time zones. Though they still cannot make the Date object behave any differently, they typically implement the standard IANA timezone database and provide functions for using it in JavaScript. Modern libraries use the time zone data supplied by the Intl API, but older libraries typically have overhead, especially if you are running in a web browser, as the database can get a bit large. Some of these libraries also allow you to selectively reduce the data set, either by which time zones are supported and/or by the range of dates you can work with.
Here are the libraries to consider:
Intl-based Libraries
New development should choose from one of these implementations, which rely on the Intl API for their time zone data:
Luxon (successor of Moment.js)
date-fns-tz (extension for date-fns)
Day.js (when using its Timezone plugin)
Non-Intl Libraries
These libraries are maintained, but carry the burden of packaging their own time zone data, which can be quite large.
js-joda/timezone (extension for js-joda)
moment-timezone* (extension for Moment.js)
date-fns-timezone (extension for older 1.x of date-fns)
BigEasy/TimeZone
tz.js
* While Moment and Moment-Timezone were previously recommended, the Moment team now prefers users chose Luxon for new development.
Discontinued Libraries
These libraries have been officially discontinued and should no longer be used.
WallTime-js
TimeZoneJS
Future Proposals
The TC39 Temporal Proposal aims to provide a new set of standard objects for working with dates and times in the JavaScript language itself. This will include support for a time zone aware object.
Common Errors
There are several approaches that are often tried, which are in error and should usually be avoided.
Re-Parsing
new Date(new Date().toLocaleString('en', {timeZone: 'America/New_York'}))
The above approach correctly uses the Intl API to create a string in a specific time zone, but then it incorrectly passes that string back into the Date constructor. In this case, parsing will be implementation-specific, and may fail entirely. If successful, it is likely that the resulting Date object now represents the wrong instant in time, as the computer's local time zone would be applied during parsing.
Epoch Shifting
var d = new Date();
d.setTime(d.getTime() + someOffset * 60000);
The above approach attempts to manipulate the Date object's time zone by shifting the Unix timestamp by some other time zone offset. However, since the Date object only tracks time in UTC, it actually just makes the Date object represent a different point in time.
The same approach is sometimes used directly on the constructor, and is also invalid.
Epoch Shifting is sometimes used internally in date libraries as a shortcut to avoid writing calendar arithmetic. When doing so, any access to non-UTC properties must be avoided. For example, once shifted, a call to getUTCHours would be acceptable, but a call to getHours would be invalid because it uses the local time zone.
It is called "epoch shifting", because when used correctly, the Unix Epoch (1970-01-01T00:00:00.000Z) is now no longer correlated to a timestamp of 0 but has shifted to a different timestamp by the amount of the offset.
If you're not authoring a date library, you should not be epoch shifting.
For more details about epoch shifting, watch this video clip from Greg Miller at CppCon 2015. The video is about time_t in C++, but the explanation and problems are identical. (For JavaScript folks, every time you hear Greg mention time_t, just think "Date object".)
Trying to make a "UTC Date"
var d = new Date();
var utcDate = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()));
In this example, both d and utcDate are identical. The work to construct utcDate was redundant, because d is already in terms of UTC. Examining the output of toISOString, getTime, or valueOf functions will show identical values for both variables.
A similar approach seen is:
var d = new Date();
var utcDate = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
This is approach passes UTC values into the Date constructor where local time values are expected. The resulting Date object now represents a completely different point in time. It is essentially the same result as epoch shifting described earlier, and thus should be avoided.
The correct way to get a UTC-based Date object is simply new Date(). If you need a string representation that is in UTC, then use new Date().toISOString().
As Matt Johnson said
If you can limit your usage to modern web browsers, you can now do the
following without any special libraries:
new Date().toLocaleString("en-US", {timeZone: "America/New_York"})
This isn't a comprehensive solution, but it works for many scenarios
that require only output conversion (from UTC or local time to a
specific time zone, but not the other direction).
So although the browser can not read IANA timezones when creating a date, or has any methods to change the timezones on an existing Date object, there seems to be a hack around it:
function changeTimezone(date, ianatz) {
// suppose the date is 12:00 UTC
var invdate = new Date(date.toLocaleString('en-US', {
timeZone: ianatz
}));
// then invdate will be 07:00 in Toronto
// and the diff is 5 hours
var diff = date.getTime() - invdate.getTime();
// so 12:00 in Toronto is 17:00 UTC
return new Date(date.getTime() - diff); // needs to substract
}
// E.g.
var here = new Date();
var there = changeTimezone(here, "America/Toronto");
console.log(`Here: ${here.toString()}\nToronto: ${there.toString()}`);
This should solve your problem, please feel free to offer fixes. This method will account also for daylight saving time for the given date.
dateWithTimeZone = (timeZone, year, month, day, hour, minute, second) => {
let date = new Date(Date.UTC(year, month, day, hour, minute, second));
let utcDate = new Date(date.toLocaleString('en-US', { timeZone: "UTC" }));
let tzDate = new Date(date.toLocaleString('en-US', { timeZone: timeZone }));
let offset = utcDate.getTime() - tzDate.getTime();
date.setTime( date.getTime() + offset );
return date;
};
How to use with timezone and local time:
dateWithTimeZone("America/Los_Angeles",2019,8,8,0,0,0)
You can specify a time zone offset on new Date(), for example:
new Date('Feb 28 2013 19:00:00 EST')
or
new Date('Feb 28 2013 19:00:00 GMT-0500')
Since Date store UTC time ( i.e. getTime returns in UTC ), javascript will them convert the time into UTC, and when you call things like toString javascript will convert the UTC time into browser's local timezone and return the string in local timezone, i.e. If I'm using UTC+8:
> new Date('Feb 28 2013 19:00:00 GMT-0500').toString()
< "Fri Mar 01 2013 08:00:00 GMT+0800 (CST)"
Also you can use normal getHours/Minute/Second method:
> new Date('Feb 28 2013 19:00:00 GMT-0500').getHours()
< 8
( This 8 means after the time is converted into my local time - UTC+8, the hours number is 8. )
I found the most supported way to do this, without worrying about a third party library, was by using getTimezoneOffset to calculate the appropriate timestamp, or update the time then use the normal methods to get the necessary date and time.
var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);
// ET timezone offset in hours.
var timezone = -5;
// Timezone offset in minutes + the desired offset in minutes, converted to ms.
// This offset should be the same for ALL date calculations, so you should only need to calculate it once.
var offset = (mydate.getTimezoneOffset() + (timezone * 60)) * 60 * 1000;
// Use the timestamp and offset as necessary to calculate min/sec etc, i.e. for countdowns.
var timestamp = mydate.getTime() + offset,
seconds = Math.floor(timestamp / 1000) % 60,
minutes = Math.floor(timestamp / 1000 / 60) % 60,
hours = Math.floor(timestamp / 1000 / 60 / 60);
// Or update the timestamp to reflect the timezone offset.
mydate.setTime(mydate.getTime() + offset);
// Then Output dates and times using the normal methods.
var date = mydate.getDate(),
hour = mydate.getHours();
EDIT
I was previously using UTC methods when performing the date transformations, which was incorrect. With adding the offset to the time, using the local get functions will return the desired results.
For Ionic users, I had hell with this because .toISOString() has to be used with the html template.
This will grab the current date, but of course can be added to previous answers for a selected date.
I got it fixed using this:
date = new Date();
public currentDate: any = new Date(this.date.getTime() - this.date.getTimezoneOffset()*60000).toISOString();
The *60000 is indicating the UTC -6 which is CST so whatever TimeZone is needed, the number and difference can be changed.
I ran into this issue running a GCP Cloud Function. Of course it works on a local machine, but running in the cloud makes the OS default (local) for new Date() irrelevant. In my case, an api call from the cloud required Eastern Standard Time, in ISO format (without the "Z") with offset as "-0500" or "-0400" depending on DST, for example:
2021-12-01T00:00:00.000-0500
Again, this is not a browser formatting issue, so I am forced into this format for the api call to work correctly.
Using #chickens code as a start, this is what worked:
var date = new Date();
var now_utc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),
date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
var dt = new Date(now_utc);
let utcDate = new Date(dt.toLocaleString('en-US', { timeZone: "UTC" }));
let tzDate = new Date(dt.toLocaleString('en-US', { timeZone: "America/New_York" }));
let offset1 = utcDate.getTime() - tzDate.getTime();
let offset2 = offset1/60000;
let o1 = Math.abs(offset2);
console.log(offset2)
var offsetValue1 = (offset2 < 0 ? "+" : "-") + ("00" + Math.floor(o1 / 60)).slice(-2) + ("00" + (o1 % 60)).slice(-2);
console.log(offsetValue1)
dt.setTime(dt.getTime() - offset1);
console.log(dt.toISOString());
console.log(dt.toISOString().slice(0,-1)+offsetValue1);
I ran into a similar problem with unit tests (specifically in jest when the unit tests run locally to create the snapshots and then the CI server runs in (potentially) a different timezone causing the snapshot comparison to fail). I mocked our Date and some of the supporting methods like so:
describe('...', () => {
let originalDate;
beforeEach(() => {
originalDate = Date;
Date = jest.fn(
(d) => {
let newD;
if (d) {
newD = (new originalDate(d));
} else {
newD = (new originalDate('2017-05-29T10:00:00z'));
}
newD.toLocaleString = () => {
return (new originalDate(newD.valueOf())).toLocaleString("en-US", {timeZone: "America/New_York"});
};
newD.toLocaleDateString = () => {
return (new originalDate(newD.valueOf())).toLocaleDateString("en-US", {timeZone: "America/New_York"});
};
newD.toLocaleTimeString = () => {
return (new originalDate(newD.valueOf())).toLocaleTimeString("en-US", {timeZone: "America/New_York"});
};
return newD;
}
);
Date.now = () => { return (Date()); };
});
afterEach(() => {
Date = originalDate;
});
});
I had the same problem but we can use the time zone we want
we use .toLocaleDateString()
eg:
var day=new Date();
const options= {day:'numeric', month:'long', year:"numeric", timeZone:"Asia/Kolkata"};
const today=day.toLocaleDateString("en-IN", options);
console.log(today);
Try using ctoc from npm.
https://www.npmjs.com/package/ctoc_timezone
It has got simple functionality to change timezones (most timezones around 400) and all custom formats u want it to display.
Building on the answers above, I am using this native one liner to convert the long timezone string to the three letter string:
var longTz = 'America/Los_Angeles';
var shortTz = new Date().
toLocaleString("en", {timeZoneName: "short", timeZone: longTz}).
split(' ').
pop();
This will give PDT or PST depending on the date provided. In my particular use case, developing on Salesforce (Aura/Lightning), we are able to get the user timezone in the long format from the backend.
Thanks to #commonpike answer, I wrote a function which takes an ISO String date such as 2020-10-10T08:00:00.000 as input and send an object which contains 2 main properties.
The first one is fromUtc is a Date corresponding to the timeZone entered as parameter.
The second one is toUtc which lets you to format a Date stemming from fromUtc.
const timeZoneTransformer = (stringDate, timeZone = "Europe/Paris") => {
const now = new Date();
const serverDate = new Date(stringDate);
const utcDate = new Date(
Date.UTC(
serverDate.getFullYear(),
serverDate.getMonth(),
serverDate.getDate(),
serverDate.getHours(),
serverDate.getMinutes(),
serverDate.getSeconds()
)
);
const invdate = new Date(
serverDate.toLocaleString("en-US", {
timeZone,
})
);
const diff = now.getTime() - invdate.getTime();
const adjustedDate = new Date(now.getTime() - diff);
return {
toUtc: utcDate,
fromUtc: adjustedDate,
};
};
const fromUtc = timeZoneTransformer("2020-10-10T08:00:00.000").fromUtc;
console.log(fromUtc);
const toUtc = timeZoneTransformer(fromUtc).toUtc;
console.log(toUtc);
Try: date-from-timezone, it resolves expected date with help of natively available Intl.DateTimeFormat.
I used that method in one of my projects for few years already, but it's now I decided to publish it as small OS project :)
Try something like this,
public static getTimezoneOffset(timeZone: string, date = new Date()): number {
const localDate = date.toLocaleString('fr', { timeZone, timeZoneName: 'long' });
const tz = localDate.split(' ');
const TZ = localDate.replace(tz[0], '').replace(tz[1], '').replace(' ', '');
const dateString = date.toString();
const offset = (Date.parse(`${dateString} UTC`) - Date.parse(`${dateString}${TZ}`)) / (3600 * 1000);
return offset;
}
I'm not sure why all these answers are so complicated. Just use YYYY-MM-DD ZZZ when creating a date-only date in the local / desired time zone.
Create a local date:
var myDate = new Date('2022-11-29 CST')
The date will be stored in storage as UTC, great.
Get the date out of storage and display it as local:
myDate.toLocaleDateString()
11/29/2022
I know its 3 years too late, but maybe it can help someone else because I haven't found anything like that except for the moment-timezone library, which is not exactly the same as what he's asking for here.
I've done something similar for german timezone,
this is a little complex because of daylight saving time and leap years where you have 366 days.
it might need a little work with the "isDaylightSavingTimeInGermany" function while different timezones change on different times the daylight saving time.
anyway, check out this page:
https://github.com/zerkotin/german-timezone-converter/wiki
the main methods are:
convertLocalDateToGermanTimezone
convertGermanDateToLocalTimezone
I've put an effort into documenting it, so it won't be so confusing.
There are several working answers here, but somehow a lot of them seemed to get you to the string, but not back to a date object you started with, so here's my simple non-function take on how to change timezone on JS date:
var TZ='Australia/Brisbane'; //Target timezone from server
var date = new Date(); //Init this to a time if you don't want current time
date=new Date(Date.parse(date.toLocaleString("en-US", {timeZone: TZ})));
//Just a clarification on what happens
// 1) First new Date() gives you a Date object at current time in the clients browser local timezone
// 2) .toLocaleString takes that time, and returns a string if time in the target timezone
// 3) Date.parse converts that new string to a Unix epoch number
// 4) new Date() converts the Unix epoch into a Date object in the new TimeZone.
// Now I can use my usual getHours and other Date functions as required.
Hope that helps others (if you get to this bottom answer!)
Simple with Node.JS support
Pass in the amount of hours your timezone is offset from UTC
function initDateInTimezone(offsetHours) {
const timezoneOffsetInMS = offsetHours * 60 * 60000;
let d = new Date().getTimezoneOffset() * 60000 + timezoneOffsetInMS;
const date = new Date(new Date().getTime() - d);
return date
}
//For Mumbai time difference is 5.5 hrs so
city_time_diff=5.5; //change according to your city
let time_now = Date.now();
time_now = time_now + (3600000 * city_time_diff); //Add our city time (in msec);
let new_date = new Date(time_now);
console.log("My city time is: ", new_date);
Was facing the same issue, used this one
Console.log(Date.parse("Jun 13, 2018 10:50:39 GMT+1"));
It will return milliseconds to which u can check have +100 timzone intialize British time
Hope it helps!!

Categories

Resources