格式化特定时区中的日期


177

我正在使用Moment.js解析和格式化Web应用程序中的日期。作为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显示日期。


2
Moment目前尚不支持此功能,但他们正在努力。github.com/timrwood/moment/pull/671

5
这应该工作。如果传递一个包含所需偏移量的时间字符串,则它应保留该偏移量并显示给定的本地时间,而不是自动调整为浏览器本地时间。如果我希望它适应浏览器本地时间,那么我给它一个UTC时间,而不是明确给它一个使用的偏移量。我的意思是...我给它提供了一个明确的偏移量,为什么它基本上会消耗掉它并自己转换为浏览器偏移量。糟糕的设计。
Triynko 2015年

@Triynko偏移量会受到夏令时的影响,因此,它并不总是能按预期工作。
pinkpanther

1
与此相关的是,我想以特定格式打印时间,例如,2018年3月15日,但是找不到格式字符串来执行此操作。DD MMM, YYYY当我像那样使用泛型时,它不起作用moment.tz("2018-02-15T14:20:00.000+0530", "Asia/Bangkok").format("DD MMM, YYYY")。有人可以在文档中指出我,我可以在其中找到使用此api格式化时间的所有键。
pRmdk

@PramodKumar怎么了?那给了"15 Feb, 2018"。您是不是要使用格式字符串DD MMMM, YYYY来获取"15 February, 2018"
quietmint

Answers:


248

正如指出曼托的答案.utcOffset()是作为矩2.9.0的首选方法。此函数使用相对于UTC的实际偏移量,而不是反向偏移量(例如,夏令时期间,纽约为-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()的设置器。它接受含有时区标识符的字符串(例如,“-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时区.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')

我通过“ TypeError:对象240没有方法'format'”错误遇到了麻烦。我意识到区域仅在2.1.0版和更高版本的Moment.js(并且我使用的是旧版本)上作为设置器可用。谢谢!
梅琳达天气

5
@ebi默认情况下,它已经使用浏览器的时区。要访问浏览器的时区偏移量,请.zone()用作吸气剂,它从UTC返回分钟(例如,在标准时间返回纽约的300)。
2013年

1
@EricCope不,不是。您可以使用.tz("America/Phoenix"),如果你有momentjs.com/timezone为好,但是。我用一个例子更新了答案。
2013年

1
请注意,如果由于夏时制而导致时区具有不同的偏移量,则使用偏移量将无法按预期工作。
pinkpanther

1
.utcOffset()是否会自动管理夏令时?例如,当我在冬季设置UTC +1 CET时,是否会在夏令时下注UTC +2 CEST?因为这使它可用或不可用!
haemse

61

使用瞬间时区

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

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

moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')

我不认为在提出问题时可以使用tz矩,但是我确实认为这可能是可行的方法。我目前正在处理一个类似的问题,所有时间戳都存储为MySQL中的UTC,但是要在特定区域中查看,具体取决于用户配置,而不是客户端的时区。
nickdnk

47

已经有几个答案提到了moment-timezone是使用命名时区的方法。我只想澄清一下这个库,这让我很困惑。这两个语句之间存在区别:

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”的原因

注意:format参数确实很重要。如果省略,则可能会回到Date类,这可能会导致无法预期的行为


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

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


即使现在我了解了为什么会这样工作,但我认为这是一个非常令人困惑的功能,值得解释。


1
moment(...)。tz不是函数
K-SO的毒性在增加。

5
您安装了moment-timezone吗?
Nicola Pedretti

有没有一种方法可以将经过解析和转换的时刻恢复为无格式状态?例如,如果我想格式化不同的格式而又不重新解析。
jEremyB

感谢您澄清这一点-在设置与用户浏览器时区不同的时区时遇到了麻烦,这就是确切的问题。
罗宾·沙夫

20

.zone()已被弃用,您应该改用utcOffset:

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

8

我在Moment.js中遇到了同样的问题。我已经安装了moment-timezone,但是问题没有解决。然后,我只做了这里显示的内容,设置了时区,它就像一个魅力一样工作:

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

非常感谢!


16
您不应该使用new Date()构造函数。Moment提供了解析日期所需的一切。请参阅解析文档。
quietmint 2014年

是的,但是,如果我不这样做,我会收到Moment的警告,它已被弃用,诸如此类
facundofarias 2014年

7
警告表示Moment在内部完全恢复了您正在做的事情(new Date()内部使用),但这在浏览器之间不一致。相反,您应该使用提供期望的格式作为第二个参数。例:moment("12-25-1995", "MM-DD-YYYY")
quietmint 2014年

4

只是这个问题,由于我遇到了同样的问题,所以我只发布我得出的结果

解析时,您可以更新偏移量(即,我正在解析数据(1.1.2014),而我只想要2014年1月1日这一日期。在GMT + 1上,我将获得31.12.2013。因此,我首先偏移了该值。

moment(moment.utc('1.1.2014').format());

好吧,这对我在跨时区提供支持很有帮助


-7

你可以试试看

在这里,您可以根据客户端时区(浏览器)获取日期。

moment(new Date().getTime()).zone(new Date().toString().match(/([-\+][0-9]+)\s/)[1]).format('YYYY-MM-DD HH:mm:ss')

正则表达式基本上可以为您提供偏移值。

干杯!!


通常,时刻会为您提供所需的一切。您无需匹配任何自定义项。
Mahesh Samudra
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.