Moment.js 转换为日期对象

908

我使用 Moment.js 无法将一个正确的 moment 对象转换为带有时区的日期对象。我无法获取正确的日期。

示例:

var oldDate = new Date(),
    momentObj = moment(oldDate).tz("MST7MDT"),
    newDate = momentObj.toDate();
console.log("start date " + oldDate)
console.log("Format from moment with offset " + momentObj.format())
console.log("Format from moment without offset " + momentObj.utc().format())
console.log("(Date object) Time with offset " + newDate)
console.log("(Date object) Time without offset "+ moment.utc(newDate).toDate())

1
你期望得到什么输出,实际得到了什么输出? - Felix Kling
4
4行代码让我输出如下:<code>(日期对象)带偏移的时间Thu Aug 01 2013 15:23:49 GMT+0300(芬兰(夏季))</code>,但时区必须为MST7MDT。 - vadim.zhiltsov
这个可以把 Wednesday 24th 2019, 12:47:48 am 转换成 2019-04-23T19:17:48.000Z 吗?@vadim.zhiltsov - Anupam Maurya
1
日期对象没有时区,它们只是相对于1970-01-01T00:00:00Z的偏移量。因此,当您调用toDate时,返回的对象已经失去了您使用.tz("MST7MDT")附加到moment对象的时区信息。这就是为什么存在像moment.tz这样的库,以补充内置日期对象的基本功能,该对象仅理解UTC和主机时区。 - RobG
11个回答

1608

13
@Spencer - 是的,它回答了标题,并且"toDate"确实是从"moment"获取"Date"对象的方法。但问题正文中的代码涉及时区转换 - 而Date无法完成此操作。除非Mountain时间确实是用户的时区,否则我不确定这是否回答了问题。 - Matt Johnson-Pint
4
这取决于你看问题的哪个方面。大多数人搜索谷歌并发现这个标题与他们的问题相符,并投赞成票回答标题,而不是问题的内容。这可能解释了为什么这个回答获得了最多的赞成票,尽管从技术上讲它并没有帮助到原帖作者。 - Spencer
21
这实际上是正确答案吗?问题是如何将 moment 对象转换为带有时区的 JavaScript 日期,但在转换为 JavaScript 日期对象时仍会返回本地时区。请问有其他方法可以解决这个问题吗? - Unspeakable
3
@gtzinos,你所链接和提到的是一个不同的问题和场景,例如将字符串传递到moment构造函数moment("12/12/2011")中,这就是你会得到那个消息的地方。这与从moment转换为日期对象moment().toDate()无关。 - btbJosh
2
这不是正确的答案。问题明确涉及“时区”。toDate()将更改原始的moment对象的时区,并将其匹配到机器的时区。这意味着原始日期/时间将始终被更改并显示在用户自己的时区中,这给所有moment用户带来了麻烦。 - saran3h
显示剩余2条评论

66
只要使用你想要的某些地区数据初始化 moment-timezone,你的代码就可以正常工作。
你正确地将moment对象转换为时区,这反映在 momentObj.format() 的第二行输出中。
切换到UTC不仅仅会丢弃偏移量,还会返回到UTC时区。如果你打算这样做,根本不需要原始的 .tz() 调用,而是可以直接使用 moment.utc()
也许你只是想更改输出格式字符串?如果是这样,只需向 format 方法指定所需的参数即可:
momentObj.format("YYYY-MM-DD HH:mm:ss")

关于你代码的最后两行 - 当你使用toDate()返回一个Date对象时,你正在放弃moment.js的行为并回到JavaScript的行为。一个JavaScript Date对象将始终以运行它的计算机的本地时区打印。这是moment.js无法改变的。
还有一些小事情:
- 虽然moment构造函数可以接受Date对象,但最好不要使用它。对于"现在",不要使用moment(new Date()),而是使用moment()。两者都可以工作,但这是不必要的冗余。如果你要从一个字符串解析,直接将字符串传递给moment。不要先尝试解析为Date。你会发现moment的解析器更可靠。 - 像MST7MDT这样的时区存在于向后兼容性原因。它们源自POSIX风格的时区,仅有少数时区在TZDB数据中。除非绝对必要,否则应该使用诸如America/Denver这样的键。

谢谢Matt!你的回答很有用。正如你提到的使用America/Denver而不是MST7MDT,是否有可用于这些映射的地图?我正在使用许多这样的时区,例如CET,EET,EST5EDT,CST6CDT,PST8PDT。 - monish001
能否将例如:"10:20 AM" (从moment().format('hh:mm A')获取的字符串时间)转换为Date对象? - ram
2
@ram - 1)如果你有时间,只需使用.toDate()。2)不要使用注释来提出新问题。这就是大型"提问"按钮的作用。 - Matt Johnson-Pint
这是我需要使用日期的内容。我还需要更改时区,谢谢。 - rfgonzalezweb

30

.toDate 对我来说并没有真正起作用,所以我做了以下操作:

futureStartAtDate = new Date(moment().locale("en").add(1, 'd').format("MMM DD, YYYY HH:MM"))

希望这可以帮助到您。


7
这个回答没有回答问题。这段代码是冗长的写法,等价于 moment().add(1, 'd').toDate() - RobG

26

因为 momentjs 无法控制 JavaScript 的 date 对象,所以我找到了解决方法。

const currentTime = new Date();    
const convertTime = moment(currentTime).tz(timezone).format("YYYY-MM-DD HH:mm:ss");
const convertTimeObject = new Date(convertTime);

这将为您提供一个JavaScript日期对象,其中包含转换后的时间


3
Safari不支持格式为“YYYY-MM-DD HH:mm:ss”的日期时间格式,因此结果为null。正确的格式应该是“YYYY-MM-DDTHH:mm:ss”(使用ECMAScript支持的格式,在日期和时间部分之间加上一个"T")。 - RobG

13

这个问题有点晦涩难懂。我将尽最大努力进行解释。首先,您应该了解如何使用moment-timezone。根据此答案 TypeError: moment().tz is not a function,您需要从moment-timezone导入moment,而不是默认的moment(当然,你需要npm install moment-timezone!)。为了清晰起见,

const moment=require('moment-timezone')//import from moment-timezone

为了使用时区功能,请使用 moment.tz("date_string/moment()","time_zone")(有关更多详细信息,请访问https://momentjs.com/timezone/)。此函数将返回一个带有特定时区的 moment 对象。为了清晰起见,

var newYork= moment.tz("2014-06-01 12:00", "America/New_York");/*this code will consider NewYork as the timezone.*/

如果你想将moment对象newYork转换为ISO 8601格式,使用moment的toDate()方法时会得到英国格林威治时间。如需了解更多详情,请参考此文章:https://www.nhc.noaa.gov/aboututc.shtml,其中有关于协调世界时(UTC)的介绍。但是,如果你只想获取本地时间并按照这种格式显示(例如:纽约时区),只需在moment对象中添加方法.utc(true) ,并带上参数true即可。为了清晰明了起见,

newYork.toDate()//will give you the Greenwich ,UK, time.

newYork.utc(true).toDate()//will give you the local time. according to the moment.tz method arg we specified above, it is 12:00.you can ofcourse change this by using moment()

简而言之,moment.tz会考虑您指定的时区并将您的本地时间与格林威治时间进行比较,以提供结果。希望这对您有用。


这是唯一已修正的答案。一个更简单的代码是 moment().tz("Asia/Shanghai").utc(true).toDate()。它将给出日期,例如 2022-03-29T23:09:21.452Z,这是上海当地时间。 - F Bai

9

将任何日期转换为 UTC 时间:

moment( moment().utc().format( "YYYY-MM-DD HH:mm:ss" )).toDate()

这个答案是错误的。它两次应用了时区偏移量:moment().utc() 返回 UTC 的值,然后 .format( "YYYY-MM-DD HH:mm:ss" ) 返回一个已设置为 UTC 但没有时区偏移量的字符串,因此被解析为本地时间。它不匹配默认的 moment 格式,因此被内置解析器解析。它也不匹配任何 ECMAScript 支持的格式,因此解析是依赖于实现的。无论如何,它被解析为本地时间,因此在创建日期的时间值时再次应用时区偏移量。 - RobG

5
let dateVar = moment('any date value');
let newDateVar = dateVar.utc().format();

很好很干净!!!


4

我需要在日期字符串中包含时区信息。最开始,我使用的是moment.tz(dateStr, 'America/New_York').toString();但后来我开始出现了有关将该字符串送回moment的错误。

我尝试了moment.tz(dateStr, 'America/New_York').toDate();但是我失去了所需的时区信息。

唯一能返回一个带有时区且可被输入到moment中的可用日期字符串的解决方案是moment.tz(dateStr, 'America/New_York').format();


4

尝试(无需进行格式化步骤)

new Date(moment())

var d = moment.tz("2019-04-15 12:00", "America/New_York");

console.log( new Date(d) );
console.log( new Date(moment()) );
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data.min.js"></script>


new Date(moment()) 相当于 new Date()。时区仅设置为 d - RobG

2

moment在2018年6月更新了js库。

var newYork    = moment.tz("2014-06-01 12:00", "America/New_York");
var losAngeles = newYork.clone().tz("America/Los_Angeles");
var london     = newYork.clone().tz("Europe/London");

newYork.format();    // 2014-06-01T12:00:00-04:00
losAngeles.format(); // 2014-06-01T09:00:00-07:00
london.format();     // 2014-06-01T17:00:00+01:00

如果你有使用 Angular5+ 的自由,那么最好在那里使用 datePipe 特性而不是在此处使用时区函数。我必须使用 moment.js,因为我的项目仅限于 Angular2。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接