使用javascript

时间:2017-11-29 21:25:08

标签: javascript date momentjs

我在Apple的收据验证服务器上有RFC 3339日期格式的日期。我需要将它与今天的日期进行比较。我正在尝试使用moment.js,但我也可以使用原生Date

日期看起来像2017-11-28 23:37:52 Etc/GMT,并且无法使用moment.js或Date.parse()

解析

更新

我不想简单地删除Etc/,因为它对于根据此确定正确的时区非常重要。 https://opensource.apple.com/source/system_cmds/system_cmds-230/zic.tproj/datfiles/etcetera

  

我们在区域名称和输出缩写中使用POSIX样式的标志,尽管这与许多人期望的相反。 POSIX在格林威治以西有积极迹象,但许多人预计格林威治以东的积极迹象。例如,TZ ='Etc / GMT + 4'使用缩写“GMT + 4”并且相当于UTC后4小时(即格林威治以西),尽管很多人都希望它比UTC早4小时(即东部)格林威治)。

3 个答案:

答案 0 :(得分:1)

您可以采用以下两种策略之一:

  1. 手动解析字符串并使用Date构造函数的部分,然后调整时区。
  2. 将时间戳转换为大多数正在使用的浏览器应支持的字符串(即每个ECMA-262的ISO 8601扩展格式)。
  3. 第一种方式更强大。

    该参考文献没有说明像+0530这样的时区是如何用Etc /格式表示的,所以以下内容并未涉及它们:

    • 'Etc / GMT'变为'+00:00'
    • 'Etc / GMT + 4'变为'-04:00'
    • 'Etc / GMT-10'变为'+10:00'

    此外,以下函数不验证格式,它们假定提供的字符串是合适的。

    // Parse strings in format 2017-11-28 23:37:52 Etc/GMT
    function parsePOZIX(s) {
      var b = s.split(' ');
      // These are the date and time parts
      var c = b[0].split(/\D/).concat(b[1].split(/\D/));
      // Create a new Date using UTC
      var d = new Date(Date.UTC(c[0],c[1]-1,c[2],c[3],c[4],c[5]));
      
      // Now adjust for the timezone
      var tz = b[2].split('/')[1];
      var sign = /^\+/.test(tz) ? 1 : -1;
      var hr = tz.replace(/\D/g, '') || '0';
      d.setUTCHours(d.getUTCHours() + sign*hr);
      return d;
    }
    
    ['2017-11-28 23:37:52 Etc/GMT',
    '2017-11-28 23:37:52 Etc/+8',
    '2017-11-28 23:37:52 Etc/-10'].forEach(function(s){
      console.log(s + '\n' + parsePOZIX(s).toISOString());
    });

    解析和重新格式化字符串的第二种(不太可靠的方法),然后使用内置的解析器:

    // Reformat strings like 2017-11-28 23:37:52 Etc/GMT 
    // to ISO 8601 compliance, then use built-in parser
    function parsePOSIX2(s) {
      var b = s.split(' ');
      var tz = b[2].split('/')[1];
      var sign = /^\+/.test(tz)? '-' : '+';
      var hr = tz.replace(/\D/g,'') || '0';
      hr = ('0' + hr).slice(-2) + ':00'; // Must include colon for Safari
      return new Date(b[0] + 'T' + b[1] + sign + hr);
    }
    
    ['2017-11-28 23:37:52 Etc/GMT',
     '2017-11-28 23:37:52 Etc/-4'].forEach(function(s) {
      console.log(s + '\n' + parsePOSIX2(s).toISOString());
    });

    请注意,Safari不会解析像“+0000”这样的时区(导致日期无效),它必须包含冒号:“+00:00”。

答案 1 :(得分:0)

解析任意格式的最简单方法是使用一些正则表达式将其拆分为多个部分,然后以您可以使用的格式进行排列。

const date = '2017-11-28 23:37:52 Etc/GMT';

const [,year,month,day,hour,minute,second,timezone] = date.match(/(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\sEtc\/([A-Z]{3})/);

console.log(year, month, day, hour, minute, second, timezone);

const parsedDate = new Date(`${year}-${month}-${day} ${hour}:${minute}:${second} ${timezone}`);
console.log(parsedDate);

这种方法的好处是适用于您可能遇到的任何随机格式(您只需要一个不同的正则表达式)。通过ES6破坏,它可以非常紧凑。

注意:我不确定Etc位是否为常量或具有特殊含义,因此您应该查看规范并确保不需要对其进行任何操作。

答案 2 :(得分:0)

Apple返回的格式包括ISO 8601日期时间和IANA时区。这是我在其他地方从未见过的怪异格式,考虑到苹果公司的文档声称这是RFC 3339日期时间字符串,这似乎对苹果公司来说是一个错误。

JavaScript不支持使用IANA时区。因此,核心Moment.js库也没有。但是,Moment Timezone可以。如果同时包含了时刻库和时刻时区库,则可以这样解析日期:

/**
 * Parse a datetime string returned from the Apple Receipt Validation Server, in
 * a format like:
 *     2017-11-28 23:37:52 Etc/GMT
 * and return its value as a Moment datetime object.
 */
function parseAppleDatetime(appleDatetimeStr) {
    const [dateStr, timeStr, timezoneStr] = appleDatetimeStr.split(' '),
          datetimeStr = dateStr + ' ' + timeStr;
    return moment.tz(datetimeStr, timezoneStr);
}

现在,例如,

parseAppleDatetime('2017-11-28 23:37:52 Etc/GMT').format()

...您会得到:

"2017-11-28T23:37:52Z"