-2

我收到Date来自不同的 3 种格式APIs

  1. UTC格式2014-01-01T00:00:00.000Z:( String)
  2. GMT格式Thu, 29 Nov 2018 17:30:56 GMT:( String)
  3. unixTimeStamp: 1558606726( number)

此外,UTC格式有时可能Z最终没有,因此正常解析会产生时间差异。

function formatDate(dateString) {
  var dateTime, utcFormatRegex, zeroHourOffsetRegex;

// Some APIs return a Date in standard ISO UTC format may not have Z at the end
  utcFormatRegex = /^\d{4}-\d{2}-\d{2}T.*$/;
  zeroHourOffsetRegex = /^.*Z$/;

  if (utcFormatRegex.test(dateString) && !zeroHourOffsetRegex.test(dateString)) {
    dateString+='Z';
  }

    dateTime = new Date(dateString);

}

鉴于所有不同格式都有解析函数,我需要一个函数来确定我们应该根据 a 使用哪个解析函数,regexparse相应地使用它。如果正则表达式不是理想的解决方案,那么我该如何解决?

我要说的是,可能应该有一个比“如果没有 Z 则添加一个”更强大的解决方案来让它通过单个日期时间解析器进行解析。如果我们得到另一种日期时间格式,它不能很好地与最后的 Z 配合使用怎么办?我们将在那个时间点进行多项更改。

4

1 回答 1

1

使用正则表达式是可以的,但您需要严格测试您期望的格式。如果你得到你不期望的东西,抛出一个错误。当前内置解析器的缺点之一是无法指定严格的解析,例如在提供格式的地方,如果输入字符串不匹配,解析器会抛出错误。

有一些图书馆可以提供帮助,搜索会发现很多。

但是,如果您只需要支持 OP 中的 3 种格式,则可能适合以下内容:

/* Return a Date where the input may be:
**   string: ISO 8601 timestamp that should be treated as UTC
**           whether it has a trailing Z or not
**   string: Timestamp in the format (using moment.js tokens): 
**           ddd, DD MMM YYYY HH:mm:ss GMT 
**   nunber: UNIX time value, seconds since 1970-01-01 UTC
*/
function toDate(value) {
  // Parse the string & fail early if it fails
  let d = new Date(value);
  
  // Throw error if couldn't parse value
  if (isNaN(d.getTime())) {
    throw 'Invalid timestamp: ' + value;
  }
  
  // Otherwise, do the work
  let days = 'Sun Mon Tue Wed Thu Fri Sat'.split(' ');
  let months = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');

  // Test for time value first as that's the easiest
  if (typeof value == 'number' && !isNaN(value)) {
    return new Date(value * 1000);
    
  // Test for ISO 8601 next
  } else if (/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d\d\dZ?$/.test(value)) {
    return new Date(/Z$/.test(value)? value : value + 'Z');
    
  // Test for random format
  } else if (/^[a-z]{3}, \d?\d [a-z]{3} \d{4} \d\d:\d\d:\d\d GMT$/i.test(value)) {
    let b = value.split(/ |:/);

    if (days.includes(b[0].substr(0,3)) && months.includes(b[2])) {
      let x = new Date(Date.UTC(
                b[3],                 // year
                months.indexOf(b[2]), // month, zero indexed
                b[1],                 // day
                b[4], b[5], b[6]      // hh:mm:ss
              ));
      // Check value was a valid date, only need to check some parts
      if (x.getUTCFullYear() == b[3] &&
          x.getUTCDate() == b[1] &&
          x.getUTCHours() == b[4] &&
          x.getUTCSeconds() == b[6]) {
        return x;
      } else {
        throw 'Invalid timestamp: ' + value;
      }
    }

  // Throw error as must be unknown format
  } else {      
    throw 'Unknown format: ' + value;
  }
}

// Minimal testing 
var isoString0 = '2014-01-01T00:00:00.000Z',
    isoString1 = '2014-01-01T00:00:00.000',         // no Z, parse as UTC anyway
    randomString = 'Thu, 29 Nov 2018 17:30:56 GMT',
    unixTimeValue = 1558606726,                     // Assume seconds
    invalidDate0 = '2018-02-29T00:00:00.000Z',      // no 29 Feb in 2018, fail built-in parse
    invalidDate1 = 'Thu, 29 Feb 2018 17:30:56 GMT', // no 29 Feb in 2018, fail manual parse
    invalidFormat = '6/6/2019';                     // Unknown format

[isoString0, isoString1, randomString, unixTimeValue, invalidDate0,
 invalidDate1, invalidFormat].forEach(s => {
  var result;
  try {
    result = toDate(s);
    console.log(s + ' =>\n' + result.toISOString());
  } catch (e) {
    console.log(e);
  }
});

于 2019-05-31T04:34:06.483 回答