So I'd like to pass in a dynamic value into toLocaleTimeString. The way the time is formatted is going to change based on the user location. For example time for a user in the UK should be something like 18:00:00, while for someone in America it would be 6:00:00 PM.
The only problem I'm having is doing a dynamic mapping of timezone to which locale to pass in (i.e. "en-GB", "en-US", etc). How do I do this?
I'm using momenttimezone and tzlookup to get the user timezone:
let timezone = tzlookup(userLatitude, userLongitude)
var date = new Date()
var localHour = date.toLocaleTimeString("xx-XX") // How do I dynamically set xx-XX to what it's supposed to be based on the user location?
Any help is much appreciated!
Time zones and locales are two orthogonal concepts. You should not make any assumptions that bind them together. In many cases, they can be quite different. For example, if I am an English speaking American visiting Japan, my device will likely have a time zone of Asia/Tokyo and a locale of en-US.
As for toLocaleTimeString (and toLocaleDateString, toLocaleString, Intl.DateTimeFormat, etc.) the default value of undefined will automatically use the user's current locale.
In other words:
// this uses the current locale and current time zone
date.toLocaleString()
// this uses a specific locale and current time zone
date.toLocaleString('en-US')
// this uses the current locale and a specific time zone
date.toLocaleString(undefined, {timeZone: 'Asia/Tokyo'})
// this uses a specific locale and a specific time zone
date.toLocaleString('en-US', {timeZone: 'Asia/Tokyo'})
In your example, if you want to display a time in the UK time zone (the mainland, not a dependency or overseas territory), then you can use the time zone Europe/London. Your call to tzlookup should be returning that. You should not choose a locale. Let the user's browser set that according to their preferences.
const timezone = tzlookup(userLatitude, userLongitude)
const date = new Date()
const localHour = date.toLocaleTimeString(undefined, {timeZone: timezone})
You should not need moment or moment-timezone for this operation.
Related
I'm working on a web application that supports link sharing. This link contains the clients selected dates (start and end date) from a date selector react component. As the user changes the selected dates they are accurately represented in the URL ready to be shared with other uses. When another user clicks on this link it should open the same web application except the default selected dates inside the date selector component will be parsed from the URL instead (if they exist otherwise uses the default).
This works exceptionally well when the links are shared between two people in the same time zone. However, if I send my link to someone in a different time-zone the selected dates for them are not the same as mine.
Currently when writing the local dates to the URL I am doing the following steps:
url.set("startDate", dates[0].toISOString());
url.set("endDate", dates[1].toISOString());
where date[0] and date[1] are date objects in the current users local time-zone.
When I parse the URL I do the following:
var startDate = new Date(url.get("startDate") ?? "");
var endDate = new Date(url.get("endDate") ?? "");
if (startDate.toString() === "Invalid Date") {
startDate = defaultStartDate; // user local time ( uses new Date() )
}
if (endDate.toString() === "Invalid Date") {
endDate = defaultEndDate; // user local time ( uses new Date() )
}
For example, I have two brokers running one in Eastern Standard and another in Pacific Standard. If I select 06/01/2021 and 06/05/2021 in Eastern Standard the link that is constructed looks like the following:
startDate=2021-06-01T04%3A00%3A00.000Z&endDate=2021-06-06T03%3A59%3A59.999Z
and when parsed by the user in Pacific Standard the resulting selected dates are:
05/31/2021 and 06/05/2021.
After some further debugging I believe this issue is occurring because the time set by default is 00:00:00 for start date and 23:59:59 for the end date. So when converting from EST -> PST new Date() is subtracting 4 hours from both dates (as it should). However, I need these to be the same dates across multiple time zones.
Given the strings are generated by toISOString, the resulting timestamp will be parsed to exactly the same time value by the built-in parser regardless of the user's system offset or settings.
The difference you see is from generating a local date and time from the time value based on different system settings. Given the same input timestamp, both systems should display exactly the same output timestamp if displayed for the same location, e.g. the following parses the timestamp in the OP, then presents the equivalent time in EDT and PDT respectively.
let s = '2021-06-01T04:00:00.000Z';
let startDate = new Date(s);
console.log(startDate.toLocaleString('en', {
timeZone: 'America/New_York',
timeZoneName: 'short'
}));
console.log(startDate.toLocaleString('en', {
timeZone: 'America/Los_Angeles',
timeZoneName: 'short'
}));
If you want the receiver to see the same date and time as the sender, then include the sender's IANA representative location (such as 'America/New_York' or encoded as 'America%2FNew_York') in the URL. But that doesn't change the generated time value, only the timestamp displayed by the various toString* methods.
How we can get all of the default browser/system/country settings using javascript or any other js library?
Like what is the default timezone format of the browser?
(UTC+05:30 or UTC+01:00, etc)
What is the default Date format according to timezone? ('DD/MM/YYYY' or
'MM/DD/YYYY' or 'YYYY/MM/DD')
What is the default Time format according to a browser? ('AM/PM' or '24 Hour')
Default language of browser?
If we do navigator.language using javascript we get "en-GB" but can we get a full form? like English, Spanish, Sweedish or etc
Default temperature unit? (Celsius or Fahrenheit)
Like what is the default timezone format of the browser? (UTC+05:30 or UTC+01:00, etc)
Timezone is a preference, there is no default. Be careful about what you assume
To get the timezone offset, which is the number of minutes you need to subtract from UTC, use the following. This will usually be a negative number for users in Asia and Australia, and usually a positive number for users in the Americas.
new Date().getTimezoneOffset()
If you want to know the timezone, you can get it with
Intl.DateTimeFormat().resolvedOptions().timeZone
// => "Atlantic/Reykjavik"
// => "Americas/New_York"
// => "Asia/Shanghai"
Be careful if you translate this to a 3 character abbreviation. "Americas/New_York" could be "EST" or "EDT" depending on the time of year. "CST" could be China standard time, or Cuba standard time, or Central Australia standard time, or Central America standard time.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl
Other than temperature unit (which the browser knows nothing about), the IETF language setting (in this case "en-GB") tells the browser how to format outputs when using .toLocaleString(). A date object will be printed with the TZ offset, the same date with .toLocalDateString() will give the date in proper locale 'DD/MM/YYYY' , and the same date with .toLocaleTimeString() will give the time with 'AM/PM or 24h' representation.
const date = new Date();
console.log(date.toString());
console.log(date.toUTCString());
console.log(date.toLocaleString());
console.log(date.toLocaleDateString());
console.log(date.toLocaleTimeString());
// Get TZ for instance
const tz = date.toString().match(/GMT(-|\+)[0-9]{4}.*/)[0];
console.log(tz);
I have to publish an online program for an international conference. Rather than just showing the date and time of each event according to our timezone (UTC+11), I want the page to display them according to the user's timezone. When the page loads it should show what the server thinks the user's timezone is, but give the user the opportunity to override it, using a dropdown.
I have managed to get this to work:
<script>
function convertTZ(date, tzString) {
return new Date((typeof date === "string" ? new Date(date) : date).toLocaleString("en-US", {timeZone: tzString}));
}
</script>
<body onload = "document.getElementById('datetime').innerHTML = convertTZ('2021/01/09 11:00:00 +1100','Europe/Paris')">
<p id="datetime"></p>
</body>
But how to I get the user’s timezone string and allow the user to override this?
I also will need to extract just the date + time without the timezone info (eg "GMT+1100 (Australian Eastern Daylight Time)") but hopefully I can work that out myself.
(I am very much a JavaScript beginner.)
Any help would be greatly appreciated, particularly if someone knows of something that already exists, which I could adapt. Thanks.
A few things:
You should specify the time of the event in ISO 8601 format: 2021-01-09T11:00:00+11:00.
Or rather, more accurately stated, it should be in the ECMAScript Date Time String Format, such that it is understood unambiguously by all implementations.
2021-01-09T11:00:00+11:00 is compliant with both.
2021/01/09 11:00:00 +1100 is not compliant, and thus would be considered non-standard, implementation-specific, and possibly fail in some browsers.
To use the user's time zone, do not specify a timeZone option to toLocaleString. The default is the user's time zone already.
You should also not supply a locale (en-US), as the formatting of toLocaleString will use the user's locale settings by default. If you want to supply other options, you can pass undefined for the locale to keep the user's default locale intact.
You might want to include the timeZoneName option (either long or short) to display a human-readable time zone description in the output. That will make it clearer for your user to understand the context of the information being displayed.
In the end, you probably want something similar to:
function loadDateTime() {
const eventTime = new Date("2021-01-09T11:00:00+11:00");
const display = eventTime.toLocaleString(undefined, { timeZoneName: 'long' });
document.getElementById('datetime').innerHTML = display;
}
<body onload="loadDateTime()">
<p id="datetime"></p>
</body>
For me, it outputs: 1/8/2021, 4:00:00 PM Pacific Standard Time. You will get a different result depending on your locale and time zone.
I've got a form where I input an event that starts at a certain time. Let's say 9am.
To assign a date/time object I'm using MomentJs. The issue comes when displaying it in different time-zones.
In London will show up 9am as intended - in Kiev will show 11am.
How can I make MomentJS and the browser ignore which timezone is relevant for the user, and just displaying the time I'm giving?
Here's my code:
<p>
Start time:
{moment(event.startDate).format("HH:mm")}
</p>
Assuming you have stored the date as utc (which in this case you probably should have), you could use the following:
moment.utc(event.startDate).format("HH:mm")
Let me provide an alternative answer in Vanilla JavaScript. If you want to make it timezone 'neutral', you can first convert it to UTC using toISOString().
const current = new Date();
const utcCurrent = current.toISOString();
console.log(utcCurrent);
If you want to convert it to a specific timezone, such as London, you can use toLocaleString(). Do take note of the browser support for the timezone though.
const londonTime = new Date().toLocaleString('en-US', { timeZone: 'Europe/London' })
console.log(londonTime);
What you want is a normalized Datetime. This can get a little confusing since the concept of timezones is a rather arbitrary construct.
I like to think of Datetime values as "absolute" and "relative". An "absolute" Datetime is one that is true regardless of which timezone you're in. The most common example of these are UTC(+000) and UNIX Time (also known as Unix epoch, POSIX Time or Unix Timestampe).
UTC is pretty obvious. Its the current time at +000 timezone. UNIX time is a bit more interesting. It represents the number of seconds that have elapsed since January 1, 1970.
You should always store data, in both client and backend, as an "absolute" time. My preference is UNIX time since its represented as a single integer (nice and clean).
moment.js does this for you. When you instantiate your moment object, you can use:
var date = moment.utc(utcString)
or for Unix Time
var date = moment.unix(unixInt)
You can then use this object to display the date in any form you wish:
console.log(date.tz.("America/Toronto"))
The only way I could solve this is by removing the timezone and milliseconds info from the string. I used date-fns lib but I imagine moment will work the same way.
import { format } from 'date-fns'
const myDateTimeString = '2022-02-22T19:55:00.000+01:00'
const dateTimeWithoutTimezone = myDateTimeString.slice(0, 16) // <- 2022-02-22T19:55
format(new Date(dateTimeWithoutTimezone), 'HH:mm')
I have a requirement, where I need to show a user's time in their local time zone. This needs to be done using date-fns.
The following code checks the current time and then given a timezone converts it into local time as per the time zone.
const { formatToTimeZone } = require('date-fns-timezone')
let date = new Date()
const format = 'D.M.YYYY HH:mm:ss [GMT]Z (z)'
const output = formatToTimeZone(date, format, { timeZone: 'Asia/Calcutta' })
However, how do I guess the user's timezone on the fly?
In moment.js, you can get it with moment.tz.guess(). But how can I do it without moment.js and by using date-fns?
https://runkit.com/embed/835tsn9a87so
UPDATE: I will be using this inside a VueJS application. So, if there are any other related solutions, those are welcomed as well. Thanks.
To get the user's IANA time zone identifier, most modern browsers now support the following:
Intl.DateTimeFormat().resolvedOptions().timeZone
That said, the usual reason you would need to use formatToTimeZone from date-fns-timezone is when you need to use a different time zone other than the user's local zone. Otherwise, you can usually just use the format function from date-fns.
However, in your case, you are also trying to use the z format specifier to display the user's time zone abbreviation. This isn't provided by date-fns directly, so if that is critical then you will indeed need to get the user's time zone with the Intl api shown above and use formatToTimeZone.
Do keep in mind though that these abbreviations are whatever the IANA data has recorded, which are in English only, and it doesn't have abbreviations for every time zone. For those that don't, you will see a numeric value instead, such as -02.
Also, many abbreviations can be ambiguous (such as the I in IST possibly meaning India, Israel, or Ireland, and many others...). Thus, in most cases, if you don't need the abbreviation, you're often better off without it.
Just solved a similar problem myself. The trick is to use the format function from date-fns-tz instead of the one from date-fns.
import { format } from "date-fns";
console.log(format(new Date(), "yyyy-MM-dd HH:mm z"));
// 2021-11-29 13:55 GMT-8
import { format } from "date-fns-tz";
console.log(format(new Date(), "yyyy-MM-dd HH:mm z"));
// 2021-11-29 13:55 PST
See documentation here:
https://date-fns.org/v2.27.0/docs/Time-Zones