I want to know each and every country's Date, Time, Month, Year, Day, Hours and Minutes, using only Vanilla JavaScript. Given that I know country's name, its country code(like 'IN' for India) and Timezone Number(eg: 19800 for Delhi), which I got from OpenWeatherAPI. Please help me how can I achieve this.
i think the toLocaleDateString might help , it accepts two argument , first one is locales and the second one is options that have some timeZone stuff
read the documentations for more info
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString
You can get the current time for a given UTC offset by adding this to the current UTC time. We can do this using the Date constructor and the various getUTC..() functions to get the time components.
We have to be careful with using fixed UTC offsets for many locations such as New York. The UTC offset will vary due to Daylight Saving Time, so we have to use the right UTC offset for a given moment in time.
So, when you get a time back from an API with a UTC Offset (or Timezone Number), you should not make the assumption that the UTC offset is fixed for that location.
function getTimeComponentsFromUTCOffset(timeMillis, utcOffsetSeconds) {
const d = new Date(timeMillis + utcOffsetSeconds * 1000);
return {
year: d.getUTCFullYear(),
month: d.getUTCMonth() + 1,
day: d.getUTCDate(),
hour: d.getUTCHours(),
minute: d.getUTCMinutes(),
second: d.getUTCSeconds()
};
}
// NB: timeZoneNumber or UTC offset will vary according to local DST rules...
const inputs = [
{ timeZoneNumber: +28800, location: 'Perth' },
{ timeZoneNumber: +19800, location: 'Delhi' },
{ timeZoneNumber: +3600, location: 'London' },
{ timeZoneNumber: -14400, location: 'New York' },
]
console.log('Location'.padEnd(12), 'Year ', 'Month ', 'Day ', 'Hour ', 'Minute', 'Second');
for(let input of inputs) {
let time = getTimeComponentsFromUTCOffset(Date.now(), input.timeZoneNumber);
console.log(input.location.padEnd(12), ...Object.values(time).map(s => (s + '').padStart(2, '0').padEnd(6)));
}
.as-console-wrapper { max-height: 100% !important; }
Related
Here is cutoffDate is passed as an argument to this method.
Sample value for cutoffDate = "2020-04-19 23:59:59"
If cutoffDate is past, as per the current time in Denver, return true
If cutoffDate is future, as per the current time in Denver, return false
let cutoffDate = "2020-04-19 23:59:59";
const currentDatetime = new Date(
new Date().toLocaleString("en-US", {
timeZone: "America/Denver",
})
);
const cutoffDateTime = new Date(cutoffDate);
console.log(currentDatetime + '\n' + cutoffDateTime);
console.log(currentDatetime < cutoffDateTime);
This method returns incorrect result, in some cases. This method is working correctly as expected in some cases and not working as expected in some cases.
Observation: As per logs, it tends to fail in IOS (iPhone). (in some cases)
As per my understanding, above code should function correctly always. But, I am unable to determine why it is failing in some cases.
What you're trying to do seems valid, however the way you're doing it is prone to failure.
"2020-04-19 23:59:59" is not a format supported by ECMA-262 so parsing is implementation dependent. Apple devices until very recently treated it as an invalid date, so this method will fail for any device running an earlier OS.
A better way is to manually parse the string to remove issues associated with the built–in parser. Similarly for the return value from toLocaleString.
The following manually parses the timestamp, then uses Intl.DateTimeFormat with formatToParts to get the date and time values for any IANA representative location. It uses Date.UTC to generate time values to compare and avoid local DST issues.
Note that if the input timestamp represents a date and time that doesn't exist in the location (i.e. it's in the period when clocks are advanced going into DST) or exists twice (i.e. it's in the period when clocks are wound back going out of DST) then results may or may not be "correct". However, this is an issue for any system comparing such dates and times.
// Return true if current time is before timestamp at loc
function nowIsBeforeDateAtLoc(ts, loc = 'UTC') {
// Get time value for timestamp parsed as UTC
let [Y,M,D,H,m,s] = ts.split(/\D/);
let tsTV = Date.UTC(Y,M-1,D,H,m,s);
// Get current date and time values for loc
let {year, month, day, hour, minute, second} = new Intl.DateTimeFormat('en', {
year:'numeric',
month:'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
hour12: false,
timeZone: loc
}).formatToParts(new Date()).reduce((acc, part) => {
acc[part.type] = part.value;
return acc;
}, Object.create(null));
// Get UTC time value for loc
let locTV = Date.UTC(year, month-1, day, hour, minute, second);
// Debug
// Parsed timestamp
console.log('Cutoff: ' + new Date(tsTV).toISOString().slice(0,-1));
// Current date and time at loc
console.log('Now ' + loc + ' : ' + new Date(locTV).toISOString().slice(0,-1));
return locTV < tsTV;
}
// Example
let cutoffTime = "2020-04-19 23:59:59";
//
console.log('Now is before cutoff at loc? ' + nowIsBeforeDateAtLoc(cutoffTime, 'America/Denver'));
You could also use a library to parse the timestamp for a particular location then compare it to "now", which might be simpler. See this answer to How to initialize a JavaScript Date to a particular time zone.
Title says it all. Is there a way to convert a time zone by city to a time zone by region?
Ideally without a hardcoded map, but with built in Date functions?
examples:
America/New_York => Eastern
America/Chicago => Eastern
America/Los_Angeles => Pacific
I can already get the offset and local time from the time zones I have now. I just want to see if there's a way to get the "parent" time zone for ui/orgnaization purposes.
I'd suggest looking at DateTimeFormat, you can use this to format the timezone in various ways, using the timeZoneName option.
We can wrap this up in a getAlernativeName() function.
function getAlternativeName(timeZone) {
const opts = { timeZoneName: 'longGeneric', timeZone};
return Intl.DateTimeFormat('en-EN', opts).format(Date.now()).split(',')[1];
}
let inputs = ['America/New_York', 'America/Louisville', 'America/Chicago', 'America/Denver' , 'America/Los_Angeles', 'Europe/Berlin']
console.log('Timezone'.padEnd(20, ' ') + ' Alternative Name')
inputs.forEach(input => {
console.log(input.padEnd(20, ' ') + getAlternativeName(input))
})
.as-console-wrapper { max-height: 100% !important; }
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?
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
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:
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.
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>
You can use something like this:
const actualDate = new Date()
actualDate.toLocaleString('en-US', { timeZone: 'America/New_York' })
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"))
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
I'm trying to calculate the datetime in UTC, i have the bellow code and using Luxon
weeklyDish.orderBeforeTime = timeZoneToUTC(
"Europe/Amsterdam",
year,
month,
day,
hours
);
function timeZoneToUTC(timezone, year, month, day, hours) {
const dateObj = `${year}-${month}-${day} ${hours}:00`;
const datetime = DateTime.fromFormat(dateObj, "yyyy-M-d H:mm", {
zone: timezone,
});
return datetime.toUTC().toString();
}
The code above always return the wrong hour.
How can I get the year, month, hour and return a UTC string to save in the DB?
I'm going to be migrating data that has date as string (example: "2020-12-13"), how can I convert it to UTC date and subtract days correctly?
You need to show an example to demonstrate your issue. The following shows use of Luxon's UTC and setZone methods that both seem to correctly convert a date set for "Europe/Amsterdam".
Note that the string passed to DateTime.fromISO must form a valid ISO 8601 timestamp like YYYY-MM-DDTHH.
let DateTime = luxon.DateTime;
let [tz, y, m, d, h] = ["Europe/Amsterdam", '2020', '11', '30', '12'];
let date = DateTime.fromISO(`${y}-${m}-${d}T${h}`, { zone: "Europe/Amsterdam" });
console.log(tz + '\n' + date.toString());
let dateUTC = date.setZone('UTC');
console.log('setZone to UTC\n' + dateUTC.toString());
let dateUTC2 = date.toUTC();
console.log('toUTC method\n' + dateUTC2.toString());
<script src="https://cdn.jsdelivr.net/npm/luxon#1.25.0/build/global/luxon.min.js"></script>
PS Amsterdam standard time is +1, daylight saving time is +2.
If the date is already parsed, you can use the date constructor directly. However, the constructor depends on the local timezone, luckily you can use Date.UTC instead.
The tricky part is about the timezone, which is not supported in the constructor, but it's a simple addition anyway.
So I'd wager something like so should work:
function timeZoneToUTC(timezone, year, month, day, hours) {
return new Date(Date.UTC(year, month - 1, day, hours + timezone));
}
Note: the month parameter is an index (0-based), so if you have 1=January, you need to decrease your month by one (as in my example).
Edit: uh, apparently, Date.UTC returns a timestamp, so you need to use the constructor anyway.
I found many solution that gives Timezone name from offset value. But I have Timezone name and I want offset value for that. I tried setTimezone('Asia/Kolkata'), but I think their is no method like setTimezone.
example:
Asia/Kolkata should give me -330 ( offset )
This has got the be the easiest way to accomplish this task with modern JavaScript.
Note: Keep in mind that the offset is dependent on whether Daylight Savings Time (DST) is active.
/* #return A timezone offset in minutes */
const getOffset = (timeZone = 'UTC', date = new Date()) => {
const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
const tzDate = new Date(date.toLocaleString('en-US', { timeZone }));
return (tzDate.getTime() - utcDate.getTime()) / 6e4;
}
console.log(`No arguments: ${getOffset()}`); // 0
{
console.log('! Test Case #1 >> Now');
console.log(`Asia/Colombo : ${getOffset('Asia/Colombo')}`); // 330
console.log(`America/New_York : ${getOffset('America/New_York')}`); // -240
}
{
console.log('! Test Case #2 >> DST : off');
const date = new Date(2021, 0, 1);
console.log(`Asia/Colombo : ${getOffset('Asia/Colombo', date)}`); // 330
console.log(`America/New_York : ${getOffset('America/New_York', date)}`); // -300
}
{
console.log('! Test Case #3 >> DST : on');
const date = new Date(2021, 5, 1);
console.log(`Asia/Colombo : ${getOffset('Asia/Colombo', date)}`); // 330
console.log(`America/New_York : ${getOffset('America/New_York', date)}`); // -240
}
.as-console-wrapper { top: 0; max-height: 100% !important; }
I came across this same issue, and this is the solution I came up with, if you can get an IANA tz database name like the one you mentioned:
const myTimezoneName = "Asia/Colombo";
// Generating the formatted text
// Setting the timeZoneName to longOffset will convert PDT to GMT-07:00
const options = {timeZone: myTimezoneName, timeZoneName: "longOffset"};
const dateText = Intl.DateTimeFormat([], options).format(new Date);
// Scraping the numbers we want from the text
// The default value '+0' is needed when the timezone is missing the number part. Ex. Africa/Bamako --> GMT
let timezoneString = dateText.split(" ")[1].slice(3) || '+0';
// Getting the offset
let timezoneOffset = parseInt(timezoneString.split(':')[0])*60;
// Checking for a minutes offset and adding if appropriate
if (timezoneString.includes(":")) {
timezoneOffset = timezoneOffset + parseInt(timezoneString.split(':')[1]);
}
It's not a very nice solution, but it does the job without importing anything. It relies on the output format of the Intl.DateTimeFormat being consistent, which it should be, but that's a potential caveat.
You can't get it by name alone. You would also need to know the specific time. Asia/Kolkata may be fixed to a single offset, but many time zones alternate between standard time and daylight saving time, so you can't just get the offset, you can only get an offset.
For how to do it in JavaScript, see this answer.
Using countries and timezones npm package:
import {getTimezone} from 'countries-and-timezones';
const australianTimezone = 'Australia/Melbourne';
console.log(getTimezone(australianTimezone));
Prints to the console:
{
name: 'Australia/Melbourne',
country: 'AU',
utcOffset: 600,
utcOffsetStr: '+10:00',
dstOffset: 660,
dstOffsetStr: '+11:00',
aliasOf: null
}
From there, you can use the utcOffset or dstOffset depending on if it is daylight savings time.