简体   繁体   English

如何使用JSON.parse reviver参数解析日期字符串

[英]How to use JSON.parse reviver parameter to parse date string

My JSON string contains a date field that returns such a value:我的 JSON 字符串包含返回这样一个值的日期字段:

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

I am particularly interested in parsing only the date compartment not the time.我对只解析日期隔间而不是时间特别感兴趣。 I tried using a reviver function, but interestingly the reviver function is never invoked!我尝试使用 reviver function,但有趣的是 reviver function 从未被调用! (tried on Firefox) (在 Firefox 上试过)

Here is my code to accomplish that:这是我的代码来完成它:

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);
        ....
    });
}
};

JSON.parse in loadArticle never calls dateReviver . loadArticle 中的loadArticle从不调用dateReviver

I invested a whole day but no luck?我投资了一整天但没有运气? Could someone please help me?有人可以帮我吗?

Using TypeSript, my solution is as follows:使用TypeSript,我的解决方案如下:

    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;
}

Best of all worlds ;-) It uses an anonymous datereviver, which gets called by JSON.parse on each property.最棒的 ;-) 它使用匿名 datereviver,它由 JSON.parse 在每个属性上调用。 The reviver logic is to check whether the property is of type string and if so, whether it looks like the start of a date ... If it is a date, then let new Date(value) do the actual parsing ... all timezone variations are supported that way. reviver 逻辑是检查属性是否是字符串类型,如果是,它是否看起来像一个日期的开始......如果它是一个日期,那么让 new Date(value) 做实际的解析......所有以这种方式支持时区变化。

Hope it helps!希望能帮助到你!

  1. The regular expression expects a "Zulu" timezone (A 'Z' character at the end), while the sample date-time string shows a numeric timezone ('-04:00').正则表达式需要一个“祖鲁语”时区(末尾有一个 'Z' 字符),而示例日期时间字符串显示一个数字时区 ('-04:00')。 The following regex will accept both:以下正则表达式将接受两者:

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

    If the time zone digits are not zero, you might want to actually modify the date after parsing and/or converting to UTC, to respect the timezone.如果时区数字不为零,您可能希望在解析和/或转换为 UTC 后实际修改日期,以尊重时区。

  2. I can see dateReviver() being hit.我可以看到 dateReviver() 被击中。 Try the following in a browser:在浏览器中尝试以下操作:

     <!-- 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>

    I am getting the following in the browser, indicating successful parsing:我在浏览器中得到以下信息,表明解析成功:

     Sat Apr 4 15:55:16 PDT 2009

Extending the jQuery.ajax converters setting worked fine for me from its's default:从默认情况下,扩展 jQuery.ajax 转换器设置对我来说效果很好:

"text json": jQuery.parseJSON

to

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

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

does not adjust the date for the timezone information, the -4:00 in the example.不调整时区信息的日期,示例中为-4:00

An alternative is to let Date() do the parsing for you:另一种方法是让 Date() 为您解析:

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

If the JSON had been formatted with JSON.stringify() it would have been in UTC (Z).如果 JSON 已使用 JSON.stringify() 进行格式化,则它将采用 UTC (Z)。

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;
}

Drop-in solution嵌入式解决方案

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);
}

I ran into this problem today and I have a different approach from those contributed by others.我今天遇到了这个问题,我的方法与其他人提供的方法不同。

If you know the keys that contain dates ahead of time, you could write the reviver like so:如果您提前知道包含日期的密钥,则可以像这样编写 reviver:

export const jsonDateReviver = (keysToParse: Record<string, boolean>) => (key: string, value: any) => {
  if (keysToParse[key]) {
    if (Array.isArray(value)) {
      return value.map(v => new Date(v));
    }
    return new Date(value);
  }
  return value;
};

You could then use it like so:然后你可以像这样使用它:

JSON.parse(data, jsonDateReviver({ lastModifiedAt: true }))

Or you could have a global keysToParse object instead of redefining it every time或者你可以有一个全局keysToParse object 而不是每次都重新定义它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM