如何将ISO日期字符串转换为日期对象?

63

我陷入了一个奇怪的境地,不幸的是,即使我做了一些研究和谷歌搜索,我仍然无法解决这个问题。

我有一个采用ISO格式的日期字符串,例如2014-11-03T19:38:34.203Z,我想使用new Date() 方法将其转换为日期对象。

但当我这样做时,输出结果是:

var isoDate = '2014-11-03T19:38:34.203Z';
console.log(new Date(isoDate)); //output is: Tue Nov 04 2014 01:08:34 GMT+0530 (IST)

我通过的日期是2014年11月3日,输出结果是2014年11月4日,这是因为我们当地时间(IST)的GMT +5.30。

那么,有没有通用的方法可以获取返回2014年11月3日date对象呢?

注意:我对时间戳没有任何问题。我们可以使用setHours()方法将时间字符串更改为零。我想要的唯一的是像new Date()这样具有2014年11月3日日期的date对象。


let date = new Date(isoDate); date = new Date(date.getUTCFullYear(), date.getUTCMonth(), ...); - John
10个回答

54
不要将字符串传递给Date构造函数,因为它在解析字符串方面非常糟糕。例如,IE 8无法解析ISO 8601格式的字符串并返回NaN。编写自己的解析器非常简单:
function parseISOString(s) {
  var b = s.split(/\D+/);
  return new Date(Date.UTC(b[0], --b[1], b[2], b[3], b[4], b[5], b[6]));
}

请注意,如果时间为19:38:34.203 UTC,而您的时区为UTC +0530,则该时区的时间为隔天的01:08:34 am,因此日期会有所不同。例如,对于澳大利亚东海岸但不遵守夏令时(即UTC +10)的人来说,它相当于:

4 November, 2014 05:38:34

编辑

如果你想将其转换为ISO日期格式,可以使用getISO*方法创建适合的格式,例如:

function isoFormatDMY(d) {  
  function pad(n) {return (n<10? '0' :  '') + n}
  return pad(d.getUTCDate()) + '/' + pad(d.getUTCMonth() + 1) + '/' + d.getUTCFullYear();
}

var s = '2014-11-03T19:38:34.203Z';
var date = parseISOString(s);

console.log(isoFormatDMY(date)) // 03/11/2014

或者使用ES5的toISOString函数:

 parseISOString('2014-11-03T19:38:34.203Z').toISOString(); // 2014-11-03T19:38:34.203Z

一个简单的polyfill,用于ES5之前的浏览器:
if (!Date.prototype.toISOString) {

  Date.prototype.toISOString = function() {

    var d = this;

    // Padding functions 
    function pad(n) {return (n<10? '0' :  '') + n}
    function padd(n){return (n<100? '0' : '') + pad(n)}

    return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) +
           'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + 
           pad(d.getUTCSeconds()) + '.' + padd(d.getMilliseconds()) + 'Z';
  }
}

你说得对。但是根据我的需求,我需要显示ISO日期(在我的情况下,是2014年11月3日)。 - Mohit Pandey
3
我们还需要在2019年这样做吗?具体来说是针对Node.js。如果使用“new Date(s)”,应该没问题。 - PathToLife
1
@Pathfinder——是的,不是。ECMA-262支持两种格式,在受控环境下应该可以正常工作,但在其他情况下,请避免使用所有字符串的内置解析器。 - RobG
1
@RobG 我正在使用你在 Stack 上找到的类似脚本:function parseDate(s) { var b = s.split(/\D/); return new Date(b[0], b[1]-1, b[2], b[3], b[4], b[5]);}。我尝试将时间向前调整一个小时以进行时区更改,唯一有效的方法似乎是return new Date(b[0], b[1]-1, b[2], b[3], b[4], 36+b[5]);},因为每个单位增量 before b[5] 等于100秒,所以 3600/100=36。是否有更系统化的方法或者一些更好的参考资料来帮助我理解,而不是通过 trial & error 来推进? - John Galassi
如果你想向前移动1小时,那么Number(b[3]) + 1就可以了。由于你正在使用字符串,所以应该将其转换为数字,以便+是加法而不是连接。36 + b[5]会在b[5]的值之前添加字符串文字“36”。如果它是“00”,那么你将得到“3600”,我猜这会增加一个小时,但对我来说有点笨拙。 - RobG
这里可能是 toIsoString() 的新文档 - ECMA6?-。 - Timo

18

您可以使用“getUTCDate()”来获取实际日期。

var d = new Date('2014-11-03T19:38:34.203Z');
var n = d.getUTCDate();

但它仅返回日期。要获取月份,请使用“getUTCMonth()”,要获取年份,请使用“getUTCFullYear()”。然后将所有内容构建成您的格式。例如:

var n=[];
var d = new Date('2014-11-03T19:38:34.203Z');
var s = d.getUTCDate();
n.push(s);
s=d.getUTCMonth();
n.push(s);
s=d.getUTCFullYear();
n.push(s);

最后将 n 转化为一个对象。


7

我并不关心时间戳/时区,因为我从SQL中仅返回ISO格式的日期。为了避免在转换为Date对象时日期提前一天或推迟一天,可以采用以下方法:

moment(ISOStringHere, 'YYYY-MM-DD HH:mm'); // leaving off Z makes it UTC to match database

这需要使用Moment JS库,该库位于以下位置:

https://momentjs.com/


3
这是一个对于那些需要支持旧浏览器并且能够正确调整日期字符串中的时区的函数。我以RobG的回答为起点,但是不得不进行大量修改,因为它对于带有时区偏移的字符串(例如"-07:00",即不以"Z"结尾的字符串)无法正常工作。
// Parse an ISO date string (i.e. "2019-01-18T00:00:00.000Z",
// "2019-01-17T17:00:00.000-07:00", or "2019-01-18T07:00:00.000+07:00",
// which are the same time) and return a JavaScript Date object with the
// value represented by the string.
function isoStringToDate( isoString ) {

    // Split the string into an array based on the digit groups.
    var dateParts = isoString.split( /\D+/ );

    // Set up a date object with the current time.
    var returnDate = new Date();

    // Manually parse the parts of the string and set each part for the
    // date. Note: Using the UTC versions of these functions is necessary
    // because we're manually adjusting for time zones stored in the
    // string.
    returnDate.setUTCFullYear( parseInt( dateParts[ 0 ] ) );

    // The month numbers are one "off" from what normal humans would expect
    // because January == 0.
    returnDate.setUTCMonth( parseInt( dateParts[ 1 ] ) - 1 );
    returnDate.setUTCDate( parseInt( dateParts[ 2 ] ) );

    // Set the time parts of the date object.
    returnDate.setUTCHours( parseInt( dateParts[ 3 ] ) );
    returnDate.setUTCMinutes( parseInt( dateParts[ 4 ] ) );
    returnDate.setUTCSeconds( parseInt( dateParts[ 5 ] ) );
    returnDate.setUTCMilliseconds( parseInt( dateParts[ 6 ] ) );

    // Track the number of hours we need to adjust the date by based
    // on the timezone.
    var timezoneOffsetHours = 0;

    // If there's a value for either the hours or minutes offset.
    if ( dateParts[ 7 ] || dateParts[ 8 ] ) {

        // Track the number of minutes we need to adjust the date by
        // based on the timezone.
        var timezoneOffsetMinutes = 0;

        // If there's a value for the minutes offset.
        if ( dateParts[ 8 ] ) {

            // Convert the minutes value into an hours value.
            timezoneOffsetMinutes = parseInt( dateParts[ 8 ] ) / 60;
        }

        // Add the hours and minutes values to get the total offset in
        // hours.
        timezoneOffsetHours = parseInt( dateParts[ 7 ] ) + timezoneOffsetMinutes;

        // If the sign for the timezone is a plus to indicate the
        // timezone is ahead of UTC time.
        if ( isoString.substr( -6, 1 ) == "+" ) {

            // Make the offset negative since the hours will need to be
            // subtracted from the date.
            timezoneOffsetHours *= -1;
        }
    }

    // Get the current hours for the date and add the offset to get the
    // correct time adjusted for timezone.
    returnDate.setHours( returnDate.getHours() + timezoneOffsetHours );

    // Return the Date object calculated from the string.
    return returnDate;
}

使用/几个测试:
// All three of these tests output the same date (relative to your
// timezone) as they should, which in my case is:
// "Thu Jan 17 2019 17:00:00 GMT-0700 (Mountain Standard Time)".
console.log( isoStringToDate( "2019-01-18T00:00:00.000Z" ) );
console.log( isoStringToDate( "2019-01-17T17:00:00.000-07:00" ) );
console.log( isoStringToDate( "2019-01-18T07:00:00.000+07:00" ) );

非常完美,先生,谢谢您! - Clément Prévost

2

我最初使用了kevinmicke的优秀答案,但由于我需要用于代码生成器,我很关注代码大小。最终我得到了如下代码:

const parseDate = dateString => {
  const b = dateString.split(/\D+/);
  const offsetMult = dateString.indexOf('+') !== -1 ? -1 : 1;
  const hrOffset = offsetMult * (+b[7] || 0);
  const minOffset = offsetMult * (+b[8] || 0);  
  return new Date(Date.UTC(+b[0], +b[1] - 1, +b[2], +b[3] + hrOffset, +b[4] + minOffset, +b[5], +b[6] || 0));
};


1

我想要一个 date 对象,以便在 kendo 图表中表示数据。使用 Date.UTC,我猜无法获取 date 对象。 - Mohit Pandey
你不必改变对象本身,只需使用获取utc字符串的方法,例如:.toUTCString() - Lashus

1
new Date(this.datePipe.transform(isoDate,'yyyy-MM-dd HH:mm:ss', 'UTC'));

Angular日期管道转换将按指定的简单日期时间格式转换它,没有时区。在ISO字符串格式的情况下,日期构造函数会将其视为UTC时间,但现在,日期构造函数将其视为本地时间。
例如,在我的情况下(IST):
input string: 2020-04-19T09:15:00.000Z
after transform this.datePipe.transform(input string)
2020-04-19 09:15:00
Date object 
new Date(this.datePipe.transform(isoDate,'yyyy-MM-dd HH:mm:ss', 'UTC'));//treats the transformed date as local timezone date when creating the date object
Sun Apr 19 2020 09:15:00 GMT+0530 (India Standard Time)

-1

如何从 ISO 字符串中获取时间和日期 JavaScript

var isoDate = '2014-11-03T19:38:34.203Z';

isoDate.getFullYear()+'-' + (isoDate.getMonth()+1) + '-'+isoDate.getDate();

将ISO格式转换为JavaScript日期

date = new Date(isoDate);
date.getFullYear()+'-' + (date.getMonth()+1) + '-'+date.getDate();


-1
我使用了Moment.js将时间转换为UTC - 参考链接

https://momentjs.com/docs/#/parsing/utc/

让日期范围等于 moment.utc("2021-11-11T20:00:00Z").format("YYYY-MM-DD")

let dateRange = moment.utc("2021-11-11T20:00:00Z").format("YYYY-MM-DD")
alert(new Date(dateRange))
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>


-4

为了显示的目的,你可以简单地这样做... 给定 ISO 格式的“日期”,你可以实现以下代码:

<div> {{Date | date:"dd MMM yy hh:mm a" }} </div>

一个巧妙的技巧,可以以所需格式显示(仅显示)日期。
希望能对您有所帮助!

1
你是否看到问题描述和标签,都包含了纯JavaScript代码。没有使用Angular或任何JS框架来绑定数据,所以你的答案与主题无关。 - ahmed hamdy

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