提问人:coding.... 提问时间:11/8/2023 最后编辑:coding.... 更新时间:11/9/2023 访问量:88
如何根据时区获取时差?
How to get time difference based on timezone?
问:
我需要获取位于 anather 国家/地区的其他用户的时差(以小时和分钟为单位)。这是我所做的。
const timeZone = "Asia/tokyo"; // Time zone can be changed
let arr: any = new Date().toLocaleString("en-US", {
timeZone: timeZone,
dateStyle: "full",
timeStyle: "full",
});
let currentTime = new Date();
需要获取 currentHour 和 arr 之间的差异
答:
-1赞
Jaromanda X
11/8/2023
#1
首先,使用语言环境进行“计算”......它输出,使其易于操作en-CA
yyyy-mm-dd hh:mm:ss
其次,根据需要添加 24 小时时间hour12: false
然后你可以
const minutesToHHMM = (m) => {
const s = m < 0 ? '-' : '';
m = Math.abs(m);
const mm = (m % 60).toString().padStart(2, 0);
const hh = Math.floor(m / 60);
return `${s}${hh}:${mm}`;
}
const timeZone = 'Australia/Eucla'; // odd timezone to always show minutes in difference
const date = new Date();
date.setMilliseconds(0); // remove millisecond since we are not creating the "other" time with milliseconds
const other = new Date(...date
.toLocaleString('en-CA', {
timeZone,
hour12: false,
})
.replaceAll('-',':') // convert yyyy-mm-dd to yyyy:mm:dd
.replaceAll(', ', ':') // add ':' between date and time
.split(':') // split all the values
.map((v,i) => v - (i===1)) // subtract one from month
);
console.log("other time", other.toLocaleString());
console.log("local time", date.toLocaleString());
console.log("difference", minutesToHHMM((other-date)/60000));
我的打字稿不优雅......但
const minutesToHHMM = (m:number) => {
const s = m < 0 ? '-' : '';
m = Math.abs(m);
const mm = (m % 60).toString().padStart(2, "0");
const hh = Math.floor(m / 60);
return `${s}${hh}:${mm}`;
}
const timeZone = 'Australia/Eucla'; // odd timezone to always show minutes in difference
const date = new Date();
date.setMilliseconds(0); // remove millisecond since we are not creating the "other" time with milliseconds
const other = new Date(...(date
.toLocaleString('en-CA', {
timeZone,
hour12: false,
})
.replaceAll('-',':') // convert yyyy-mm-dd to yyyy:mm:dd
.replaceAll(', ', ':') // add ':' between date and time
.split(':') // split all the values
.map(Number)
.map((v:number, i:number) => v - ((i===1) ? 1 : 0)) as []) // subtract 1 from month
);
console.log("other time", other.toLocaleString());
console.log("local time", date.toLocaleString());
console.log("difference", minutesToHHMM((+other - +date)/60000));
在 TS Playground 上尝试过,似乎有效
评论
0赞
coding....
11/8/2023
兄弟,我们怎么能在这里传播日期。我收到类似 spread 参数必须具有元组类型或传递给 rest 参数的错误。打字稿有问题吗?
1赞
RobG
11/8/2023
最好使用 formatToParts,以便直接获取零件。不确定这是否适用于 DST 边界。
1赞
Matt Johnson-Pint
11/9/2023
@JaromandaX - 这是一个良好的开端,但通过测试,您会发现边缘情况存在错误。具体而言,由于它是通过将离散数值传递给构造函数创建的,因此它将受到本地时区的 DST 规则的影响。因此,如果它位于本地区域的过渡期内,即使它是“其他”区域中的有效时间,也可能被视为不明确或无效。像 Luxon 这样的库从这种方法开始,但认为这只是一种猜测。然后他们围绕结果进行一些测试以巩固答案。other
Date
1赞
Matt Johnson-Pint
11/9/2023
不幸的是,今天没有一种简单的方法可以在 JS 中实现这一点,而不使用像 Luxon 这样的库(或等效的复杂代码)。当它准备好时,Temporal 应该会让它变得简单得多。
1赞
RobG
11/9/2023
@JaromandaX,正如 Matt 所说,您传递的是离散值,因此可能会传递一个日期和时间,该日期和时间要么不存在,因为它处于“风向前进”小时,要么在“风向”小时内存在两次。此外,离散值可能位于边界的错误一侧。
0赞
RobG
11/9/2023
#2
像 Jaromanda X 这样的解决方案(下面使用 Intl.DateTimeFormat.formatToParts 复制)是可以的,但最好传递实际的 Date 对象而不是日期和时间值。
我认为获得实际偏移量之间的差异(见下文)更优雅。
function msToHMS(ms) {
let sign = ms < 0? '-' : '+';
ms = Math.abs(ms);
let z = n => (n < 10? '0':'') + n;
let hr = (ms / 3.6e6) | 0;
let min = ((ms % 3.6e6) / 6e4) | 0;
let sec = ((ms % 6e4) / 1e3) | 0;
return `${sign}${z(hr)}:${z(min)}:${z(sec)}`;
}
function getTZDiff(tz, d = new Date()) {
let tv = d - (d % 1e3);
let {year, month, day, hour, minute, second} = new Intl.DateTimeFormat('en', {
year:'numeric', month:'numeric', day:'numeric',
hour:'numeric', minute:'numeric', second:'numeric',
timeZone: tz,
hour12: false
}).formatToParts(d).reduce((acc,part) => {
acc[part.type] = part.value;
return acc;
}, Object.create(null)
);
return msToHMS(new Date(year, month-1, day, hour, minute, second) - tv);
}
console.log(getTZDiff('America/New_York', new Date(2023,3,2,1,30)));
使用时区偏移:
/* Return offset at loc for date
* @param {string} loc - IANA representative location
* @param {Date} date to get offset for
* @returns {string} offset as ±hh:mm
*/
function getOffsetForLoc(loc, d = new Date()) {
let offset = d.toLocaleString('en',{
timeZoneName:'longOffset', timeZone: loc
}).match(/[+|-][^+-]+$/);
return offset[0];
}
/* Convert offset in ±hh:mm:ss format to seconds
* @param {string} offset - ±hh:mm:ss format
* @returns {number} offset in seconds
*/
function offsetToSecs(offset) {
let sign = offset[0] == '-' ? -1 : 1;
let [hr, min, sec] = offset.match(/\d+/g);
return sign * (hr*3600 + min*60 + (sec||0)*1);
}
/* Convert secons to time in ±hh:mm:ss format
* @param {number} secs - seconds to convert
* @returns {string} equivalent in ±hh:mm:ss format
*/
function secsToHMS(secs) {
let sign = secs < 0? '-' : '+';
secs = Math.abs(secs);
let z = n => (n < 10? '0':'') + n;
let hr = (secs / 3600) | 0;
let min = ((secs % 3600) / 60) | 0;
let sec = secs % 60;
return `${sign}${z(hr)}:${z(min)}:${z(sec)}`;
}
// Get diference in offset between two locations.
// Add difference to loc1 to get time in loc2
function getOffsetDifference(loc1, loc2, d = new Date()) {
let off1 = offsetToSecs(getOffsetForLoc(loc1, d));
let off2 = offsetToSecs(getOffsetForLoc(loc2, d));
return secsToHMS(off2 - off1);
}
// Examples
let yourLoc = new Intl.DateTimeFormat().resolvedOptions().timeZone;
let cha = 'Pacific/Chatham';
console.log(
`You : ${yourLoc} ${getOffsetForLoc(yourLoc)}` +
`\nOther: ${cha} ${getOffsetForLoc(cha)}` +
`\nDiff : ${getOffsetDifference(yourLoc, cha)}` +
` (i.e. You + Diff == Other)` +
`\nRev : ${getOffsetDifference(cha, yourLoc)}` +
` (i.e. Other + Rev == You)`
);
评论
Asia/Calcutta
UTC+5:30
Australia/Eucla