2

我有许多 .net webApi 操作返回反序列化为 JSON 的日期。然后,我的 Angular 应用程序将这些日期字符串用于 display\edit 或作为各种日期指令中的 ngModel。其中许多指令需要 javascript 日期对象,而不是日期的字符串表示形式。如何将所有返回的 webapi 数据的日期字符串序列化回 javascript 日期?

注意我已经尝试了各种符合 ISO 8601 的正则表达式,但是对于我使用的每个正则表达式,都有一堆失败的用例。我需要的案例如下:

  1. 不应转换非日期(字符串),例如“ http://blah/
  2. 不应转换非日期(整数),例如 2015
  3. 不应转换错误日期,例如“2009-05-19T14a39r”
  4. 不应将部分错误日期从字符串转换为日期,例如“1”
  5. 不应转换看起来像一年的字符串,例如 '2015'
  6. 应该将日期从字符串转换为日期,例如“2015-09-09”
  7. 应将带时间的日期从字符串转换为带时间的日期,例如“2009-05-19T14:39”
  8. 应将带时间的日期从字符串转换为带时间的日期,包括秒,例如“2009-05-19T14:39:23”

  9. 应将带时间的日期转换为毫秒,从字符串转换为带毫秒的日期,例如 '2016-06-09T13:02:39.957'

  10. 应该将带有时间的日期从字符串转换为带有 UTC 时间的日期,例如“2009-05-19T14:39Z”

  11. 不应转换作为较长字符串一部分的日期,例如“不应转换 2015-12-12T00:00:00Z,因为这是较长字符串的一部分”

4

2 回答 2

2

因此,首先为了拦截所有字符串日期并将其转换为 javascript 日期,我们需要 Angular 来进行拦截和替换。为此,我们可以在 httpProvider 上使用拦截器,以确保我们的代码在执行任何其他代码之前在所有返回的 http 响应上运行。

var app = angular.module('app');

app.config(configureProviders);

configureProviders.$inject = ['$httpProvider'];
function configureProviders($httpProvider) {
    configureHttp($httpProvider);
}

function configureHttp(httpProvider) {
    // add all http interceptors
    httpProvider.interceptors.push('dateDeserialiserInterceptor');
}

好的,现在我们已经注册了拦截器,但是我们需要一些代码来使它工作:

(function () {
    var module = angular.module('myApp.interceptors');

    module.factory('dateDeserialiserInterceptor', function () {

        function convertDateStringsToDates(input) {
            // Ignore things that aren't objects.
            if (typeof input !== "object") return input;

            for (var key in input) {
                if (!input.hasOwnProperty(key)) continue;

                var value = input[key];
                // Check for string properties which look like dates.
                if (typeof value === "string" && (moment(value, moment.ISO_8601).isValid())) {
                    input[key] = moment(value, moment.ISO_8601).toDate();
                } else if (typeof value === "object") {
                    // Recurse into object
                    convertDateStringsToDates(value);
                }
            }
        };

        return {
            response: function (response) {
                convertDateStringsToDates(response);
                return response;
            }
        };
    });
})();

所以上面的代码最初是从某个地方从互联网上取下来的,并且有一个手动的正则表达式比较。regEx 被描述为符合 ISO 8601,但我发现了许多不符合 ISO 8601 的示例。这现在依赖于开源库 momentJs来确定日期是否符合 ISO 8601并进行转换。如果日期不合规,则简单地返回字符串值。ISO 8601 是一个很好的使用标准(因为它涵盖了多种情况),并且比硬编码任何预期的特定格式要好得多,这可能会导致您走上“哦……它错过了”的道路。

目前,这正在解析所有返回的响应对象值以获取潜在日期。我考虑通过使用我们期望的日期的响应属性显式标记请求来改进这一点。这样我们就不必尝试解析所有内容(这很慢),也不必冒我们不想转换的东西被转换的风险。然而,这种方法有点混乱,会乱扔很多请求。我现在喜欢这种方法,它似乎有效。很高兴它得到改进!

于 2016-06-22T12:07:41.870 回答
1

这是一个 Angular 2+ 解决方案。这假设来自 API 的日期是 ISO 格式:

在您的组件中:

// call to your data service
    this.dataService.getSomeData().map(records => {
    records.map(record => {
      //call to shared service date conversion function
      this.dataService.covertISOFieldstoDateObjects(record);
    });
    return records;
  }).subscribe(x => {
    // processed records will now have date objects for any date properties
    this.records = x;
  }, error => {
    ...
  });

在您的服务中:

covertISOFieldstoDateObjects(currentObj) {
   const entries = Object.entries(currentObj);
    for (const [key, value] of entries) {
    const isDate = moment(value, moment.ISO_8601).isValid();
    if (isDate) {
      currentObj[key] = moment(value as string, 'YYYY-MM-DD HH:mm'); // Use this to get UTC and ignore timezone (good when you need just the date)
      currentObj[key] = moment(value as string, 'YYYY-MM-DD HH:mmZ'); // Use this to include timezone adjustment
    }
}
return currentObj;

}

于 2018-11-29T15:37:27.103 回答