4

Is there a way to get a time that is local to a specified timezone in JavaScript? Basically, I'm looking for a way to say, what is the ISO time string of 2pm in New York?

I have a hack to do so, where the date is a parse-able date string, and tz is a timezone identifier, such as America/New_York.

function getDateInTZ(date, tz) {
  const formatter = new Intl.DateTimeFormat([], {
    year: "numeric",
    month: "numeric",
    day: "numeric",
    hour: "numeric",
    minute: "numeric",
    second: "numeric",
    fractionalSecondDigits: 3,
    timeZone: tz,
  });
  const localDate = new Date(date);
  const localDateAtTZ = new Date(formatter.format(localDate));
  const tzOffset = localDate.getTime() - localDateAtTZ.getTime();
  return new Date(localDate.getTime() + tzOffset);
}

and it has the following behavior

getDateInTz("2021-07-01 20:05", "America/Chicago").toISOString(); // 2021-07-02T01:05:00.000Z
getDateInTz(new Date("2021-12-05 20:05"), "America/Chicago").toISOString(); // 2021-12-06T02:05:00.000Z

getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 2021-12-06T02:05:00.000Z if local time is NY
getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 2021-12-06T07:05:00.000Z if local time is UTC

While the above solution works in Chrome, it doesn't work on Firefox because FF is unable to do Date.parse on the output of formatter.format(). Which leads me to think that it's not a correct solution.

Has anyone run into this requirement before, and have a good solution for it?

Tri Nguyen
  • 9,950
  • 8
  • 40
  • 72
  • Perhaps you really want a vanilla JS solution? Though, I'd highly recommend https://www.npmjs.com/package/moment-timezone – FishSaidNo Oct 26 '21 at 01:28
  • @FishSaidNo do you have the code that uses moment-timezone that does what I am mentioning? – Tri Nguyen Oct 27 '21 at 13:46
  • Have a look at this https://stackoverflow.com/questions/66630818/convert-date-to-another-timezone-in-javascript-and-print-with-correct-timezone – Corrl Nov 01 '21 at 15:54

5 Answers5

1

As far as I know this is not possible without the help of a library like luxon or day.js

In luxon this would be the way to go

let local = luxon.DateTime.local();  // 2021-10-31T20:26:15.093+01:00
let localInCT = local.setZone("America/Chicago"); //2021-10-31T14:26:15.093-05:00

Have a look at this project using these methods

Corrl
  • 6,206
  • 1
  • 10
  • 36
1

We're limited by the JavaScript native Date object here.

The internal state of a Date object is the number of milliseconds that have elapsed since 1970-01-01 00:00 UTC, and no timezone is stored in the Date object.

So, we can create Dates somewhat equivalent to ones created in another timezone, but they won't behave exactly the same:

  • The timezone offset for Date.toString() will show the local client timezone (e.g. GMT+0000) rather than the offset in the desired timezone.

  • DST rules may not work as expected. We can get the equivalent date for say America/New_York, but DST transitions will obey the local timezone rules and not the New York rules.

Having said that, a variant of the approach you're using will give what I would call equivalent dates in the desired timezone.

How we do this:

  1. First use Date.toLocaleString() to format an ISO timestamp in the desired timezone. We use a hack to do this, passing the 'sv' locale to the function. This will create an ISO timestamp, e.g. yyyy-MM-dd HH:mm:ss.

  2. Pass this timestamp to the Date() constructor.

TLDR: This can't really be done. But for some contexts and use cases we can approximate the desired behaviour. I would recommend using a library like luxon for this purpose.

Example below:

function getDateInTimezone(date, timeZone) {
    // Using a locale of 'sv' formats as an ISO date, e.g. yyyy-MM-dd HH:mm.
    const timeInTimeZone = date.toLocaleString('sv', { timeZone } );
    // Pass this to the Date constructor
    return new Date(timeInTimeZone);
}

const localTime = new Date();
const timeZoneList = ['Asia/Tokyo', 'Europe/Berlin','America/Los_Angeles'];

console.log(`Local Time: ${localTime.toLocaleTimeString()}`);
for(let timeZone of timeZoneList) {
    const dt = getDateInTimezone(localTime, timeZone);
    console.log(`Time (${timeZone}): ${dt.toLocaleTimeString()}`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }

Timezones in luxon are a lot easier to handle, also when we call .toString() on a Luxon DateTime, we get the correct UTC offset.

const { DateTime } = luxon;
const localTime = DateTime.now();
const timeZoneList = ['Asia/Tokyo', 'Europe/Berlin','America/Los_Angeles'];

console.log(`Local Time: ${localTime.toFormat('HH:mm:ssZZ')}`);
for(let zone of timeZoneList) {
    const dt = DateTime.fromMillis(Date.now(), { zone });
    console.log(`Time (${zone}): ${dt.toFormat(' HH:mm:ssZZ')}`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.0.2/luxon.min.js" integrity="sha512-frUCURIeB0OKMPgmDEwT3rC4NH2a4gn06N3Iw6T1z0WfrQZd7gNfJFbHrNsZP38PVXOp6nUiFtBqVvmCj+ARhw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
0

You can use something like this:

const actualDate = new Date()
actualDate.toLocaleString('en-US', { timeZone: 'America/New_York' })
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Maik Hasler Oct 20 '21 at 06:15
  • This is not what I'm asking. What you're doing is displaying the date object (in your example, current time) in a different time zone. What I'm asking for is to get a specific time at that time zone. – Tri Nguyen Oct 21 '21 at 02:41
0

Does this solve your question?

function getDateInTZ(date, tz) {
  return new Date(date).toLocaleString('en-US', { timeZone: tz })
}

console.log(getDateInTZ("2021-07-01 20:05", "Asia/Kolkata"))
console.log(getDateInTZ("2021-07-01 20:05", "America/Chicago"))
console.log(getDateInTZ("2021-12-06T02:05:00.000Z", "America/New_York"))
Alpesh Patil
  • 1,672
  • 12
  • 15
  • Thanks for the suggestion, but this doesn't answer my question. First, I need the function to return a Date object, not a string. And second, it doesn't actually do what I need. ``` // expected getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 2021-12-06T02:05:00.000Z if local time is NY //actual getDateInTZ("2021-12-06T02:05:00.000Z", "America/New_York") '12/5/2021, 9:05:00 PM' ``` – Tri Nguyen Oct 31 '21 at 02:21
-1
let date = new Date();
let time = date.toLocaleTimeString([], { hour12: true }) 

if we are using hour12 true it will return the time in 12h format else it will return the time in 24h format make sure we are using TZ on .env file it always been a good practice and helps to erase all the extra code.

you can simply use

TZ=America/New_York
Tanjin Alam
  • 1,728
  • 13
  • 15