【问题标题】:How to use JSON.parse reviver parameter to parse date string如何使用 JSON.parse reviver 参数解析日期字符串
【发布时间】:2010-12-20 01:20:19
【问题描述】:

我的 JSON 字符串包含一个返回此类值的日期字段:

"2009-04-04T22:55:16.0000000-04:00"

我对只解析日期而不是时间特别感兴趣。我尝试使用 reviver 函数,但有趣的是 reviver 函数从未被调用! (在 Firefox 上试过)

这是我的代码:

var Site = {
.....
dateReviver: function(key, value) {
    var a;
    if (typeof value === 'string') {
        a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
        if (a) {
            return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
        }
    }
    return value;
},
loadArticle: function(id) {
....
    proxy.getArticle(id, function(response) {
        var data = JSON.parse(response.result, Site.dateReviver);
        ....
    });
}
};

loadArticle 中的 JSON.parse 从不调用 dateReviver

我投资了一整天,但没有运气!有人可以帮我吗?

【问题讨论】:

    标签: javascript json debugging date-parsing reviver-function


    【解决方案1】:
    1. 正则表达式需要一个“Zulu”时区(末尾有一个“Z”字符),而示例日期时间字符串显示一个数字时区(“-04:00”)。以下正则表达式将同时接受:

      /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)(Z|([+\-])(\d{2}):(\d{2}))$/
      

      如果时区数字不为零,您可能希望在解析和/或转换为 UTC 后实际修改日期,以尊重时区。

    2. 我可以看到 dateReviver() 被击中。在浏览器中尝试以下操作:

      <!-- saved from url=(0014)about:internet -->
      <html>
          <head>
              <script src="http://www.json.org/json2.js"></script>
              <script type="text/javascript" src="http://ajax.Microsoft.com/ajax/jQuery/jquery-1.3.2.js"></script>
              <script>
                  $(function () {
                      // a mock proxy to return some json to play with
                      var proxy = {
                          getArticle: function(id, foo) { foo({
                              result: '["2009-04-04T22:55:16.0000000-04:00"]'
                          }); }
                      };
                      // the origial Site object, with the fixed regex
                      var Site = {
                          dateReviver: function(key, value) {
                              var a;
                              if (typeof value === 'string') {
                                  a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)(Z|([+\-])(\d{2}):(\d{2}))$/.exec(value);
                                  if (a) {
                                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                                                      +a[5], +a[6]));
                                  }
                              }
                              return value;
                          },
                          loadArticle: function(id) {
                              proxy.getArticle(id, function(response) {
                                  var data = JSON.parse(response.result, Site.dateReviver);
                                  // put the parsed JSON date on the page
                                  $("#output").html(data[0].toString());
                              });
                          }
                      };
                      // try out our Site object
                      Site.loadArticle();
                  });
              </script>
          </head>
          <body>
              <div id="output"></div>
          </body>
      </html>
      

      我在浏览器中得到如下信息,说明解析成功:

      Sat Apr 4 15:55:16 PDT 2009
      

    【讨论】:

    • 谢谢 Oren;) 最终我在您的帮助下找到了问题所在。我使用的是 jayrock 附带的 json.js 文件,它在解析函数中不接受 reviver 参数。我所做的是使用 eval 方法来解析(这听起来很奇怪)JSON 字符串:我非常感激;)
    【解决方案2】:

    从默认设置扩展 jQuery.ajax 转换器设置对我来说效果很好:

    "text json": jQuery.parseJSON
    

    "text json": function (xmlValue) {
                var value = JSON.parse(xmlValue, Site.dateReviver);
          return value;
          } 
    

    【讨论】:

      【解决方案3】:

      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]));的使用

      不调整时区信息的日期,例如-4:00

      另一种方法是让 Date() 为您进行解析:

      var dateReviver = function (key, value) {
          var a;
          if (typeof value === 'string') {
              a = Date.parse(value);
              if (a) {
                  return new Date(a);
              }    
          }
          return value;
      }
      

      如果 JSON 已使用 JSON.stringify() 进行格式化,那么它将采用 UTC (Z)。

      【讨论】:

      • 这将尝试解析所有内容,而不仅仅是日期。 Date.parse("0") &amp;&amp; alert('fail')
      【解决方案4】:

      使用TypeScript,我的解决方案如下:

          export function parseWithDate(jsonString: string): any {
          var reDateDetect = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/;  // startswith: 2015-04-29T22:06:55
          var resultObject = JSON.parse(jsonString,(key: any, value: any) => {
              if (typeof value == 'string' && (reDateDetect.exec(value))) {
                  return new Date(value);
              }
              return value;
          });
          return resultObject;
      }
      

      世界上最好的 ;-) 它使用一个匿名的 datereviver,它被 JSON.parse 在每个属性上调用。 reviver 逻辑是检查属性是否为字符串类型,如果是,它是否看起来像日期的开始...... 如果是日期,则让 new Date(value) 进行实际解析...所有时区变化都支持这种方式。

      希望对你有帮助!

      【讨论】:

        【解决方案5】:
        function dateReviver (k,v) {
        
            var isnum = /^\d+$/.test(v);
        
            // Check if number since Date.parse(number) returns valid date
            if (isnum) {
                return v;
            }
        
            if (Date.parse(v)) {
                return new Date(Date.parse(v));
            }
            return v;
        }
        

        【讨论】:

          【解决方案6】:

          插入式解决方案

          const jsonDateRegexp = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{3})Z$/;
          
          function jsonRetriever(key: string, value: any) {
            // let's try to detect input we dont have to parse early, so this function is as fast as possible
            if (typeof value !== 'string') {
              return value;
            }
          
            const dateMatch = jsonDateRegexp.exec(value);
          
            if (!dateMatch) {
              return value;
            }
          
            return new Date(
              Date.UTC(
                +dateMatch[1],
                +dateMatch[2] - 1,
                +dateMatch[3],
                +dateMatch[4],
                +dateMatch[5],
                +dateMatch[6],
                +dateMatch[7],
              ),
            );
          }
          
          export function parseJsonWithDates(input: string) {
            return JSON.parse(input, jsonRetriever);
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-05-22
            • 1970-01-01
            • 2018-04-18
            • 1970-01-01
            • 2014-06-04
            • 1970-01-01
            相关资源
            最近更新 更多