While working on multiple timezones, I have a case where I create shifts in multiple timezones, now users apply for those shifts.
It's highly time-sensitive. Now what I want to take input of which timezone the shift is in (example Australia/Sydney)
Solution : Now while before saving it into the database I am converting the timezone to UTCoffset meaning in example Australia/Sydney timezone I am setting offset with - example Australia offset is 600 then -600 setting the offer and storing into the db.
const getUTCOffset = timezone => Intl.DateTimeFormat([], {timeZone: timezone, timeZoneName: 'shortOffset'}).formatToParts().find(o => o.type === 'timeZoneName').value.match(/\-?\d+/)[0]*60;
(getUTCOffset('Australia/Sydney'))
Is there anything I am missing here? What could be the optimal solution for this?
I think what you're missing is that offsets change from time to time due to historic changes and daylight saving. You are much better off to store the IANA location and calculate the offset as required.
If you want to get the offset for a location in minutes (which is convenient) then consider:
function getOffsetInMinutes(loc, date = new Date()) {
let [year, sign, hr, min] = date.toLocaleString('en', {
year:'numeric',
timeZone:loc,
timeZoneName:'longOffset'
}).match(/\d+|\+|\-/g);
return (sign == '+'? 1 : -1) * (hr*60 + min*1);
}
['Asia/Kolkata',
'Australia/Sydney',
'America/New_York'
].forEach(
loc => console.log(loc + ': ' + getOffsetInMinutes(loc))
);
For browsers that don't support the newer timeZoneName option values (like Safari ), you can use a function that uses the value "short" instead. The following returns the offset as ±HH:mm, it's not hard to modify to return minutes as above.
// Return offset on date for loc in ±HH:mm format
function getTimezoneOffset(loc, date=new Date()) {
// Try English to get offset. If get abbreviation, use French
let offset;
['en','fr'].some(lang => {
// Get parts - can't get just timeZoneName, must get one other part at least
let parts = new Intl.DateTimeFormat(lang, {
minute: 'numeric',
timeZone: loc,
timeZoneName:'short'
}).formatToParts(date);
// Get offset from parts
let tzName = parts.filter(part => part.type == 'timeZoneName' && part.value);
// timeZoneName starting with GMT or UTC is offset - keep and stop looping
// Otherwise it's an abbreviation, keep looping
if (/^(GMT|UTC)/.test(tzName[0].value)) {
offset = tzName[0].value.replace(/GMT|UTC/,'') || '+0';
return true;
}
});
// Format offset as ±HH:mm
// Normalise minus sign as ASCII minus (charCode 45)
let sign = offset[0] == '\x2b'? '\x2b' : '\x2d';
let [h, m] = offset.substring(1).split(':');
return sign + h.padStart(2, '0') + ':' + (m || '00');
}
['Asia/Kolkata','Australia/Sydney','America/New_York'].forEach(
loc => console.log(loc + ': ' + getTimezoneOffset(loc))
);