使用JavaScript/MomentJS显示一致的时间,而不考虑时区
使用存储为时间戳(从历元开始的毫秒)的日期时出现问题,其中我有事件的时间戳和时区,但JavaScript/MomentJS显示的时间偏移量似乎不正确 为简洁起见,以下是我拥有的对象类型:使用JavaScript/MomentJS显示一致的时间,而不考虑时区,javascript,timezone,momentjs,Javascript,Timezone,Momentjs,使用存储为时间戳(从历元开始的毫秒)的日期时出现问题,其中我有事件的时间戳和时区,但JavaScript/MomentJS显示的时间偏移量似乎不正确 为简洁起见,以下是我拥有的对象类型: { "name" : "Something happening", "timezone" : "America/Los_Angeles", "start" : 1586631607338 } 上述活动于年月日(“start”)在加利福尼亚州洛杉矶举行。
{
"name" : "Something happening",
"timezone" : "America/Los_Angeles",
"start" : 1586631607338
}
上述活动于年月日(“start
”)在加利福尼亚州洛杉矶举行。该事件在东部夏时制通过浏览器保存到数据库中。因此,在创建此事件的浏览器中,时间是正确的
当浏览器的时区更改(从EDT更改为PDT)时,上述事件的时间现在提前3小时
这是不准确的,事件需要显示事件开始的正确时间,在本例中,该时间应为3:00 PM
,但显示为12:00 PM
基本上,如果用户在LA,他们将看到此事件的开始时间为12:00 PM
,但作者将开始时间定义为3:00 PM
使用MomentJS,将每个事件的日期转换为UTC时间戳并写入数据库
在创作方面,我们有代码,基本上可以:
// event.startTime is an instance of a JS Date object
var startTime = moment(event.startTime.getTime()).utc().valueOf();
// startTime is now a UTC time stamp
startTime
与事件的时区一起写入数据库
在前端/显示器上,我们执行以下操作:
var startTime = moment.tz(event.startTime, event.timezone);
// startTime is now a MomentJS object, which we then use format()
在作者方面,他们为下午3:00创建了一个事件,它显示在他们的事件详细信息屏幕中,从下午3:00开始
但洛杉矶的用户将看到此事件在下午12:00开始
目标是将此事件显示为从下午3:00开始,无论用户在哪里,因为事件的日期应为:
太平洋时间下午3:00-5:00,但内容为:太平洋时间下午12:00-2:00
我的理解是,存储带有时区的UTC时间戳意味着可以避免这个确切的问题,但某些地方出了问题。任何指导都将不胜感激。时刻(event.startTime.getTime()).utc().valueOf()
将等于event.startTime.getTime()
,因为Date
对象的getTime
函数返回Unix时间戳(以毫秒为单位),Unix时间戳始终基于utc。从瞬间的本地模式切换到UTC模式不会改变底层的时间戳,因此您在这里做的并不多
让我们看看您在这里应用的各种上下文中给出的时间戳:
moment.utc(1586631607338).format() //=> "2020-04-11T19:00:07Z"
moment.tz(1586631607338, 'America/New_York').format() //=> "2020-04-11T15:00:07-04:00"
moment.tz(1586631607338, 'America/Los_Angeles').format() //=> "2020-04-11T12:00:07-07:00"
如您所见,此UTC时间戳表示东部时间的下午3点,太平洋时间的中午。(您的时间戳中还有一个额外的7338
毫秒,您可能需要四舍五入。)
如果您希望时间戳表示当天太平洋时间的下午3点,则时间戳应为1586642407338
:
moment.utc(1586642407338).format() //=> "2020-04-11T22:00:07Z"
moment.tz(1586642407338, 'America/New_York').format() //=> "2020-04-11T18:00:07-04:00"
moment.tz(1586642407338, 'America/Los_Angeles').format() //=> "2020-04-11T15:00:07-07:00"
在我看来,您遇到的问题是,您从浏览器的本地时间生成的Date
对象开始。可能是某个日期/时间选取者。由于这个问题,许多选择器被编写为返回ISO 8601字符串,而不是Date
对象。您还会发现,内置于HTML5的
和
浏览器中的对象也使用字符串,而不是日期
对象。还有一些选择器是基于时刻的,并且具有时区设置,所以您在这方面有选择
但是,如果您不想更改选择器,那么您可以通过调整时区来作弊:
var startTime = moment(event.startTime).tz(event.timezone, true).valueOf();
这里的关键部分是传递给tz
实例函数的keepTime
参数的true
标志。它提供与utcOffset
实例函数中类似的行为,但使用命名时区而不是固定偏移量。该报告描述如下:
utcOffset
函数有一个可选的第二个参数,该参数接受
一个布尔值,指示是否保留一天中的现有时间
- 传递
(默认值)将在Universal中保持相同的瞬间 时间,但当地时间会改变false
- 传递
将保持相同的本地时间,但代价是 在世界时间中选择一个不同的点true
tz
函数中有关于这一点的说明,但它的工作方式是相同的,将有助于为您的场景创建正确的时间戳
这种“作弊”方式的缺点是,用户将无法选择在其本地时区中属于DST间隔的时间,即使该时间在事件的时区中有效。例如,2020-03-08的凌晨2点在美国/纽约
中无效,但在美国/菲尼克斯
中完全正常。不使用Date
对象的选择器将允许这样做,但以我上面描述的方式“欺骗”将不允许这样做。时刻(event.startTime.getTime()).utc().valueOf()
将等于event.startTime.getTime()
因为Date
对象的getTime
函数返回Unix时间戳(以毫秒为单位),并且Unix时间戳始终基于UTC。从瞬间的本地模式切换到UTC模式不会改变底层的时间戳,因此您在这里做的并不多
让我们看看您在这里应用的各种上下文中给出的时间戳:
moment.utc(1586631607338).format() //=> "2020-04-11T19:00:07Z"
moment.tz(1586631607338, 'America/New_York').format() //=> "2020-04-11T15:00:07-04:00"
moment.tz(1586631607338, 'America/Los_Angeles').format() //=> "2020-04-11T12:00:07-07:00"
如您所见,此UTC时间戳表示东部时间的下午3点,太平洋时间的中午。(您的时间戳中还有一个额外的7338
毫秒,您可能需要四舍五入。)
如果您希望时间戳表示当天太平洋时间的下午3点,则时间戳应为1586642407338
:
moment.utc(1586642407338).format() //=> "2020-04-11T22:00:07Z"
moment.tz(1586642407338, 'America/New_York').format() //=> "2020-04-11T18:00:07-04:00"
moment.tz(1586642407338, 'America/Los_Angeles').format() //=> "2020-04-11T15:00:07-07:00"
在我看来,您遇到的问题是,您从浏览器的本地时间生成的Date
对象开始。可能来自日期/时间选择器o