JavaScript中将字符串转换为日期

941

在JavaScript中,如何将字符串转换为日期对象?

var st = "date in some format"
var dt = new Date();

var dt_st = // st in Date format, same as dt.

3
可能是重复的问题:将Java日期字符串转换为JavaScript日期,还有更多相关内容请查看这里 - Felix Kling
3
现在我有点困惑了,你需要的是“时间 -> 字符串”还是“字符串 -> 时间”? - Felix Kling
13
考虑使用 http://momentjs.com/。 - hanshenrik
如果您有一个UNIX时间戳或类似的数字,如1644861097000,请参阅在JavaScript中将Unix时间戳转换为时间。如果您想要将日期格式化为字符串,请参阅如何格式化JavaScript日期 - Sebastian Simon
2
Moment.js现在已经被有效地弃用。 - Liam
显示剩余5条评论
35个回答

1069

最佳的字符串格式用于字符串解析是日期ISO格式,结合JavaScript Date对象构造函数。

ISO格式示例:YYYY-MM-DDYYYY-MM-DDTHH:MM:SS

但是!仅仅使用“ISO格式”本身并不可靠。字符串有时会被解析为UTC时间,有时会被解析为本地时间(根据浏览器供应商和版本)。最佳实践应始终将日期存储为UTC并进行计算。

要将日期解析为UTC,请附加一个Z——例如:new Date('2011-04-11T10:20:30Z')

要在UTC中显示日期,请使用.toUTCString()
要在用户本地时间中显示日期,请使用.toString()

更多信息请参见MDN | Date此答案

为了与旧版Internet Explorer兼容(IE版本低于9不支持Date构造函数中的ISO格式),您应该将日期时间字符串表示分割为其各个部分,然后可以使用构造函数使用日期时间部分,例如:new Date('2011', '04' - 1, '11', '11', '51', '00')。请注意,月份的数字必须减1。


替代方法-使用适当的库:

您还可以利用Moment.js库,该库允许使用指定的时区解析日期。


我也不得不使用“拆分字符串”的方法来解决保罗·汤布林提出的相同的“Nan”问题,这是为了在Safari中使用。new Date('2011-04-11 11:51:00')会返回“无效日期”。 - Amos
2
@Amos:注意字母"T",它分隔了日期和时间。如果您编写 new Date('2011-04-11T11:51:00'),则创建的日期是有效的。 - Pavel Hodek
@Pavel Hodek 当然可以。我遇到了同样的问题https://dev59.com/amMl5IYBdhLWcg3w_rKD,因为它取决于一天中的时间和客户端位置,你可能会发现代码对你来说工作正常,但对其他用户来说却不正确。 - Roman Podlinov
5
让 Date 解析字符串是创建 Date 对象的最糟糕的方式。最好手动解析字符串并调用 Date 构造函数。一些浏览器会将没有时区的 ISO 字符串视为 UTC,而其他浏览器则视为本地时间。 - RobG
8
@Ben Taliadoros: 是的,在所有常见的浏览器中,new Date('1970-30-02')是无效日期,因为一年中没有30个月。你不能溢出月份,但当你溢出天数时,在_Chrome_和_Firefox_中会解析成一个有效日期:new Date('1970-02-30') 然后与 new Date('1970-03-02') 相同。 - Pavel Hodek
显示剩余17条评论

432

很不幸,我发现

var mydate = new Date('2014-04-03');
console.log(mydate.toDateString());

返回 "Wed Apr 02 2014"。我知道这听起来很疯狂,但对于某些用户而言确实发生了这种情况。

防弹解决方案如下:

var parts ='2014-04-03'.split('-');
// Please pay attention to the month (parts[1]); JavaScript counts months from 0:
// January - 0, February - 1, etc.
var mydate = new Date(parts[0], parts[1] - 1, parts[2]); 
console.log(mydate.toDateString());


73
完全不疯狂,这种调整很可能是由于DST的引入所致。以“yyyy-MM-dd”格式的日期被解析为UTC时间,并且toString返回本地时间,因此根据用户所在的时区,它肯定会返回不同的结果。如果总是想要将时间作为UTC时间,则应使用toUTCString - James
4
由于JavaScript中月份是从0开始计算的:1月为0,2月为1,依此类推。 - Roman Podlinov
1
这个回答表明例子中的行为是错误的。根据规范: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date (参见:datestring),例子输出的值将是正确的。 - James Ross
22
一个巧妙的解包参数的方法是 var [YYYY, MM, DD] = '2014-04-03'.split('-') - molexi
@Smartens 非常流畅! - Alex Lacayo
显示剩余4条评论

165
var st = "26.04.2013";
var pattern = /(\d{2})\.(\d{2})\.(\d{4})/;
var dt = new Date(st.replace(pattern,'$3-$2-$1'));

输出结果将是:

dt => Date {Fri Apr 26 2013}

7
很遗憾,这个解决方案存在问题。详细信息请参见:https://dev59.com/amMl5IYBdhLWcg3w_rKD - Roman Podlinov
输出未知,因为您的代码既没有将任何内容转换为字符串,也没有输出任何内容。 - Robert Siemer
这将实际返回 Fri Apr 25 - Daniel Lefebvre

94
function stringToDate(_date,_format,_delimiter)
{
            var formatLowerCase=_format.toLowerCase();
            var formatItems=formatLowerCase.split(_delimiter);
            var dateItems=_date.split(_delimiter);
            var monthIndex=formatItems.indexOf("mm");
            var dayIndex=formatItems.indexOf("dd");
            var yearIndex=formatItems.indexOf("yyyy");
            var month=parseInt(dateItems[monthIndex]);
            month-=1;
            var formatedDate = new Date(dateItems[yearIndex],month,dateItems[dayIndex]);
            return formatedDate;
}

stringToDate("17/9/2014","dd/MM/yyyy","/");
stringToDate("9/17/2014","mm/dd/yyyy","/")
stringToDate("9-17-2014","mm-dd-yyyy","-")

3
处理日期时需要考虑各种格式,不仅限于美国格式。 - Mark Jones
4
@MarkJones 不要相信.indexOf()方法,因为它没有polyfils就不兼容跨浏览器。相反,使用更兼容的.match().test()原生JS方法。 - Alexander Dixon
2
在函数开头添加 var _delimiter = _format.match(/\W/g)[0];,就可以自动获取分隔符并省略第三个参数。 - campsjos
这个日期格式是错误的。这是因为mm代表分钟而不是月份...在你的格式中使用MM。 - vin shaba

51

建议:我建议使用一个包含大量日期格式的日期包,因为时区和日期格式管理确实是一个很大的问题,moment.js解决了许多格式。你可以轻松地将日期从简单字符串解析为日期,但我认为支持所有日期格式和变化是一项艰巨的工作。

更新:Moment已被弃用,Moment的一个好替代品是datefns https://date-fns.org/


moment.js (http://momentjs.com/) 是一个完整且功能齐全的日期包,支持ISO 8601字符串

你可以添加一个字符串日期和格式。

moment("12-25-1995", "MM-DD-YYYY");

你可以检查一个日期是否有效。

moment("not a real date").isValid(); //Returns false

一些显示示例

let dt = moment("02-01-2019", "MM-DD-YYYY");
console.log(dt.fromNow()+' |'+dt.format('LL')) 
// output: "3 months ago | February 1, 2019"

请参阅文档http://momentjs.com/docs/#/parsing/string-format/


1
一些显示示例 let dt = moment("02-01-2019", "MM-DD-YYYY");console.log(dt.fromNow()+' | '+dt.format('LL')) 的输出结果为:"3个月前 | 2019年2月1日"。 - CPHPython
Moment.js 并未被弃用。从答案中的链接可以看到:“我们现在普遍认为 Moment 是一个处于维护模式下的传统项目。它并没有死亡,但确实已经完成了它的使命”。 - RobG

33

将其作为参数传递给 Date():

var st = "date in some format"
var dt = new Date(st);

你可以使用以下方式访问日期、月份和年份:dt.getMonth()


27
我运行了 console.log(new Date('30-08-2018')),结果显示日期无效。 - Dwigh
11
这个答案忽略了此问题的多重复杂性。例如,如果我在我的电脑上(位于英国)对一个日期 01/02/2020 进行操作,它会返回2月1日,而如果在美国进行相同的操作,它将返回1月2日。你几乎永远不应该使用这种天真的实现。请改用moment - Liam

29

对于那些寻找小巧聪明解决方案的人:

String.prototype.toDate = function(format)
{
  var normalized      = this.replace(/[^a-zA-Z0-9]/g, '-');
  var normalizedFormat= format.toLowerCase().replace(/[^a-zA-Z0-9]/g, '-');
  var formatItems     = normalizedFormat.split('-');
  var dateItems       = normalized.split('-');

  var monthIndex  = formatItems.indexOf("mm");
  var dayIndex    = formatItems.indexOf("dd");
  var yearIndex   = formatItems.indexOf("yyyy");
  var hourIndex     = formatItems.indexOf("hh");
  var minutesIndex  = formatItems.indexOf("ii");
  var secondsIndex  = formatItems.indexOf("ss");

  var today = new Date();

  var year  = yearIndex>-1  ? dateItems[yearIndex]    : today.getFullYear();
  var month = monthIndex>-1 ? dateItems[monthIndex]-1 : today.getMonth()-1;
  var day   = dayIndex>-1   ? dateItems[dayIndex]     : today.getDate();

  var hour    = hourIndex>-1      ? dateItems[hourIndex]    : today.getHours();
  var minute  = minutesIndex>-1   ? dateItems[minutesIndex] : today.getMinutes();
  var second  = secondsIndex>-1   ? dateItems[secondsIndex] : today.getSeconds();

  return new Date(year,month,day,hour,minute,second);
};

例子:

"22/03/2016 14:03:01".toDate("dd/mm/yyyy hh:ii:ss");
"2016-03-29 18:30:00".toDate("yyyy-mm-dd hh:ii:ss");

2
不要随意更改String.prototype,这可能会导致非常难以发现的错误。 - Julian Knight
2
确实,在 String.prototype 上胡乱搞并不是个好主意,但是这种基础对我帮助很大。我把它封装成一个函数来使用。 - andre.hey

29
如果您能使用极好的 luxon 库,您可以轻松地解析您的日期,例如:
var luxonDate = DateTime.fromISO("2014-09-15T09:00:00");

并可以通过访问JS日期对象

luxonDate().toJSDate();

旧答案使用了MomentJS

var momentDate = moment("2014-09-15 09:00:00");
momentDate ().toDate();

5
请注意,Moment.js可以在没有Node的情况下正常工作。 - shaheer
在我的安卓和IOS设备上使用这段代码时出现了NaN错误,但在桌面上却可以正常工作。以下是我之前使用的代码:var dateTimeOfTimeIn = new Date(year + "-" + month + "-" + day + "T" + data.timeIn);通过使用这种方法和moment库,我的问题得到了解决,现在我的代码在所有设备上都可以正常工作! - Mehdi
moment现已被弃用。 - Liam

28

不,除非您确信输入始终以Date可以正确解析的格式提供,否则这是一个可怕的想法。 它会在世界各地出现问题。 - Julian Knight
1
@JulianKnight - 我真的说过“假设它是在正确的格式下”。不,它不会在世界各地出现问题,哈哈。 - user578895
6
那么你并没有真正回答这个问题。请将你的回答与被接受的答案进行比较。你的回答在许多情况下都会出错。那 new Date("3/2/20") 会产生什么结果呢?你认为它对我来说会产生相同的答案吗?除非我们在同一个国家,否则几乎肯定不会。就像我说的那样,这是个糟糕的想法。讽刺并不能使它变得正确。 - Julian Knight
1
@JulianKnight -- 以正确的格式。你的例子和new Date('a tomato')一样没有有效性。ISO 8601是一个正确的格式。3/2/20不是。 - user578895
抱歉,但那是一个非常没有帮助性的回复。当然,在许多情况下ISO格式是最好的方法,但这并不总是可行的。如果这是关于来自网站的输入怎么办?你会让全世界的人都使用ISO日期格式吗?“正确”的格式取决于上下文而不是对世界的某种技术观点。 - Julian Knight

20

new Date(2000, 10, 1)将会返回 "Wed Nov 01 2000 00:00:00 GMT+0100 (CET)"。

注意,月份中的0代表一月。


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