我想在我的Node.js后端应用程序中使用UTC日期,但是,我需要能够在本地/用户指定的时区中设置时间(小时和分钟)。
我正在寻找一个解决方案,无论是在纯JS或使用dayjs
。我不是在moment
中寻找解决方案。
看起来使用dayjs
我可以很容易地解决这个问题,但是,我找不到完成这个问题的方法。
我可以通过使用dayjs.utc()
或dayjs.tz(someDate, 'Etc/UTC')
来使用UTC时区。
当使用dayjs.utc()
时,我不能为 * 任何东西 * 使用/指定其他时区,因此我找不到一种方法来告诉dayjs
我想在特定(非UTC)时区中设置小时/分钟。
当使用dayjs.tz()
时,我仍然不能定义我想要设置为特定日期的时间的时区。
纯JS格式的示例
我的区域设置时区是Europe/Slovakia
(CEST = UTC+02,带DST; CET = UTC+1,不带DST),但是,我希望它适用于任何时区。
// Expected outcome
// old: 2022-10-29T10:00:00.000Z
// new time: 10h 15m CEST
// new: 2022-10-29T08:15:00.000Z
// Plain JS
const now = new Date('2022-10-29T10:00:00.000Z')
const hours = 10
const minutes = 15
now.setHours(10)
now.setMinutes(15)
// As my default timezone is `Europe/Bratislava`, it seems to work as expected
console.log(now)
// Output: 2022-10-29T08:15:00.000Z
// However, it won't work with timezones other than my local timezone
(几乎)解决方案
我刚刚创建了下面的函数。我认为当返回的日期(年、月和日值)与本地日期不同时,可能会有问题(请参见下面return
之前的代码注解)。有人能修复这个问题吗?
您是否发现此函数中存在任何其他问题/错误?:)
**已更新:**请参阅my answer与更新得代码.
/**
* Set timezoned time to a date object
*
* @param {Date} arg1.date Date
* @param {Object} arg1.time Time
* @param {string} arg1.timezone Timezone of the time
* @return {Date} Date updated with timezoned time
*/
function setLocalTime({date, time, timezone} = {
date: new Date(),
time: {hour: 0, minute: 0, second: 0, millisecond: 0},
timezone: 'Europe/Bratislava'
}) {
const defaultTime = {hour: 0, minute: 0, second: 0, millisecond: 0}
const defaultTimeKeys = Object.keys(defaultTime)
// src: https://stackoverflow.com/a/44118363/3408342
if (!Intl || !Intl.DateTimeFormat().resolvedOptions().timeZone) {
throw new Error('`Intl` API is not available or it does not contain a list of timezone identifiers in this environment')
}
if (!(date instanceof Date)) {
throw Error('`date` must be a `Date` object.')
}
try {
Intl.DateTimeFormat(undefined, {timeZone: timezone})
} catch (e) {
throw Error('`timezone` must be a valid IANA timezone.')
}
if (
typeof time !== 'undefined'
&& typeof time !== 'object'
&& time instanceof Object
&& Object.keys(time).every(v => defaultTimeKeys.indexOf(v) !== -1)
) {
throw Error('`time` must be an object of `{hour: number, minute: number, second: number, millisecond: number}` format, where numbers should be valid time values.')
}
time = Object.assign({}, defaultTime, time)
const userTimezoneOffsetHours = new Intl
.DateTimeFormat('en', {timeZone: timezone, timeZoneName: 'longOffset'})
.format(date)
.match(/[\d:+-]+$/)?.[0]
// TODO: This might cause an issue when the `date` date in UTC is different from `date` date in user-defined timezone, e.g. `2022-10-28T22:00:00.000Z` → [UTC] `2022-10-28`, [UTC+02] `2022-10-29`.
return new Date(`${date.getUTCFullYear()}-${(date.getUTCMonth() + 1).toString().padStart(2, '0')}-${date.getUTCDate().toString().padStart(2, '0')}T${time.hour.toString().padStart(2, '0')}:${time.minute.toString().padStart(2, '0')}:${time.second.toString().padStart(2, '0')}.${time.millisecond.toString().padStart(3, '0')}${userTimezoneOffsetHours}`)
}
setLocalTime()
// Output
// 2022-10-28T22:00:00.000Z
setLocalTime({date: new Date(2022, 0, 1)})
// Output
// 2021-12-30T22:00:00.000Z
setLocalTime({date: new Date(2022, 0, 1), timezone: 'America/Toronto', time: {hour: 4, minute: 45}})
// Output
// 2021-12-31T02:45:00.000Z
2条答案
按热度按时间x6492ojm1#
在JavaScript中,
Date
对象通常需要本地(浏览器)时间的时间定义,并以UTC时间存储。您可以使用.setUTC<time part>()
方法显式设置UTC时区的时间。您可以使用.setUTCHours()
函数(参数为hours-2
)设置GMT+2时区的时间hours
。.setUTCMinutes()
和setMinutes()
方法在大多数情况下会得到相同的结果。一个值得注意的例外是时区“亚洲/加尔各答”将应用30分钟的偏移。fcipmucu2#
我创建了下面的函数。它可以与我的测试一起工作,但是,如果你发现了问题,我希望听到它。)