在特定时区格式化日期

IT技术 javascript timezone momentjs
2021-01-15 01:25:45

我正在使用Moment.js在我的网络应用程序中解析和格式化日期。作为 JSON 对象的一部分,我的后端服务器将日期作为 UTC 纪元(Unix 偏移量)的毫秒数发送。

解析特定时区中的日期很容易——只需在解析之前将 RFC 822 时区标识符附加到字符串的末尾:

// response varies according to your timezone
const m1 = moment('3/11/2012 13:00').utc().format("MM/DD HH:mm")

// problem solved, always "03/11 17:00"
const m2 = moment('3/11/2012 13:00 -0400').utc().format("MM/DD HH:mm")

console.log({ m1, m2 })
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

但是如何在特定时区格式化日期

无论浏览器的当前时间如何,我都希望获得一致的结果,但我不想以 UTC 显示日期。

6个回答

正如Manto's answer所指出.utcOffset()是 Moment 2.9.0 的首选方法。此函数使用与 UTC 的实际偏移量,而不是反向偏移量(例如,在 DST 期间,纽约为 -240)。像 "+0400" 这样的偏移字符串和以前一样工作:

// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')

在 Moment.js 2.9.0不推荐使用较旧.zone()的 setter它接受含有时区标识符的字符串(例如,“-0400”或“-04:00”为-4小时),或者表示分钟数后面UTC(例如,240为纽约DST期间)。

// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')

要使用命名时区而不是数字偏移量,请包括Moment Timezone.tz()改用:

// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')
.utcOffset() 会自动管理夏令时吗?比如当我在冬天设置 UTC +1 CET 时,它会在夏令时下注 UTC +2 CEST 吗?因为这使它可用与否!
2021-03-16 01:25:45
请注意,如果时区由于夏令时而具有不同的偏移量,则使用偏移量将无法按预期工作。
2021-03-20 01:25:45
@haemseutcOffset()没有关系与DST或时区规则。它只是查看您已经构建的那一刻,并从 UTC 获取/设置分钟数。如果要处理已知时区的 DST 和其他规则,请使用具有命名时区(“America/Phoenix”)的 Moment Timezone 库。
2021-03-22 01:25:45
@ebi 默认情况下它已经使用浏览器的时区。访问浏览器的时区偏移量,请.zone()用作 getter,它从 UTC 返回分钟(例如,在标准时间为纽约返回 300)。
2021-03-25 01:25:45
@EricCope 不,不完全是。可以使用.tz("America/Phoenix"),如果你有momentjs.com/timezone为好,但是。我已经用一个例子更新了答案。
2021-03-25 01:25:45

几个答案已经提到时刻时区是命名时区的方式。我只是想澄清一些让我感到困惑的关于这个库的事情。这两种说法有区别:

moment.tz(date, format, timezone)

moment(date, format).tz(timezone)

假设传入的日期中未指定时区:

第一个代码接收日期并假设时区是传入的时区。第二个代码将接收日期,假设浏览器中的时区,然后根据传入的时区更改时间和时区。

例子:

moment.tz('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss', 'UTC').format() // "2018-07-17T19:00:00Z"

moment('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss').tz('UTC').format() // "2018-07-18T00:00:00Z"

我的时区是 UTC +5。因此,在第一种情况下,它不会更改,而是将日期和时间设置为具有 UTC 时区。

在第二种情况下,它假设传入的日期是 -5,然后将其转换为 UTC,这就是为什么它会吐出日期“2018-07-18T00:00:00Z”

注意:格式参数非常重要。如果省略 moment 可能会回退到 Date 类,这会导致不可预测的行为


假设时区在传入的日期中指定:

在这种情况下,它们的行为相同


尽管现在我明白为什么它会这样工作,但我认为这是一个非常令人困惑的功能,值得解释。

您是否安装了时刻时区?
2021-03-22 01:25:45
moment(...).tz 不是函数
2021-03-23 01:25:45
感谢您澄清这一点 - 我在设置与用户浏览器时区不同的时区时遇到了问题,这正是问题所在。
2021-03-25 01:25:45
这是救命稻草!
2021-04-11 01:25:45
有没有办法在不格式化的情况下恢复解析和转换的时刻?例如,如果我想以不同的方式格式化而不重新解析它。
2021-04-12 01:25:45

使用时刻时区

moment(date).tz('Europe/Berlin').format(format)

在能够访问特定时区之前,您需要像这样加载它(或使用此处描述的替代方法

moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')
我不认为当提出问题时 moment tz 可用,但我确实认为这可能是要走的路。我目前正在处理一个类似的问题,所有时间戳在 MySQL 中都存储为 UTC,但要在依赖于用户配置的特定区域而不是客户端的时区中查看。
2021-04-11 01:25:45

.zone() 已被弃用,您应该使用 utcOffset 代替:

// for a timezone that is +7 UTC hours
moment(1369266934311).utcOffset(420).format('YYYY-MM-DD HH:mm')

我在 Moment.js 上遇到了同样的问题。我已经安装了moment-timezone,但问题没有解决。然后,我做了这里暴露的事情,设置时区,它就像一个魅力:

moment(new Date({your_date})).zone("+08:00")

非常感谢!

你不应该使用new Date()构造函数。Moment 提供了解析日期所需的一切。请参阅解析文档。
2021-03-19 01:25:45
是的,但如果我不这样做,我会收到来自 Moment 的警告,它已被弃用
2021-04-09 01:25:45
警告意味着 Moment 正在内部回退到您正在做的事情(new Date()内部使用),但这在不同浏览器之间不一致的相反,您应该使用提供预期格式作为第二个参数。例子:moment("12-25-1995", "MM-DD-YYYY")
2021-04-11 01:25:45