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

发布于 2024-08-12 11:06:18 字数 866 浏览 13 评论 0原文

我的 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

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

My JSON string contains a date field that returns such a value:

"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! (tried on 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.

I invested a whole day but no luck! Could someone please help me?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

玩心态 2024-08-19 11:06:18

使用 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 对每个属性调用。
恢复逻辑是检查该属性是否是字符串类型,如果是,则它是否看起来像日期的开始......
如果它是日期,则让 new Date(value) 进行实际解析...所有时区变化都以这种方式支持。

希望有帮助!

Using TypeScript, my solution is as follows:

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

Hope it helps!

じее 2024-08-19 11:06:18
  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() 被击中。在浏览器中尝试以下操作:

    
    
        <头>
            <脚本 src="http://www.json.org/json2.js">
            <脚本类型=“text/javascript”src=“http://ajax.Microsoft.com/ajax/jQuery/jquery-1.3.2.js”>
            <脚本>
                $(函数(){
                    // 一个模拟代理,用于返回一些 json 来使用
                    var 代理 = {
                        getArticle: 函数(id, foo) { foo({
                            结果: '["2009-04-04T22:55:16.0000000-04:00"]'
                        }); }
                    };
                    // 原始 Site 对象,具有固定的正则表达式
                    var 站点 = {
                        dateReviver:函数(键,值){
                            变量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);
                                如果(一){
                                    返回新日期(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                                                    +a[5], +a[6]));
                                }
                            }
                            返回值;
                        },
                        加载文章:函数(id){
                            proxy.getArticle(id, 函数(响应) {
                                var data = JSON.parse(response.result, Site.dateReviver);
                                // 将解析后的 JSON 日期放到页面上
                                $("#output").html(data[0].toString());
                            });
                        }
                    };
                    // 尝试我们的 Site 对象
                    Site.loadArticle();
                });
            
        
        <正文>
            

    我在浏览器中看到以下内容,表明解析成功:

    2009 年太平洋夏令时间 4 月 4 日星期六 15:55:16
    
  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'). 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.

  2. I can see dateReviver() being hit. 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
    
哎呦我呸! 2024-08-19 11:06:18

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

"text json": jQuery.parseJSON

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

Extending the jQuery.ajax converters setting worked fine for me from its's default:

"text json": jQuery.parseJSON

to

"text json": function (xmlValue) {
            var value = JSON.parse(xmlValue, Site.dateReviver);
      return value;
      } 
め可乐爱微笑 2024-08-19 11:06:18

使用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) 格式。

The use of 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.

An alternative is to let Date() do the parsing for you:

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

奶茶白久 2024-08-19 11:06:18
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;
}
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;
}
陌上芳菲 2024-08-19 11:06:18

嵌入式解决方案

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

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);
}
失眠症患者 2024-08-19 11:06:18

我今天遇到了这个问题,我的方法与其他人提供的方法不同。

如果您提前知道包含日期的键,则可以像这样编写 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;
};

然后可以像这样使用它:

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

或者您可以拥有一个全局 keysToParse 对象,而不是每次都重新定义它

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:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文