如何将从字符串格式的 webapi 返回的日期转换为 javascript AngularJs 的日期格式

How do I convert dates returned from webapi in string format to javascript date format for AngularJs

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

N.B。我已经尝试了各种声称符合 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. 不应转换属于较长字符串一部分的日期,例如'Should not convert 2015-12-12T00:00:00Z as this is part of a longer string'

因此,首先为了拦截所有字符串日期并将其转换为 javascript 日期,我们需要 angular 进行拦截和替换。为此,我们可以在 httpProvider 上使用拦截器,以确保在执行任何其他代码之前,我们的代码 运行s 在所有返回的 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 标准,但我发现了很多不符合标准的示例。这现在依赖于 Open Source library momentJs to determine if the date is ISO 8601 兼容并进行转换。如果日期不兼容,则简单地返回字符串值。 ISO 8601 是一个很好的使用标准(因为它涵盖了多种情况)并且比硬编码任何预期的特定格式要好得多,后者可能会让您走上“哦......它错过了一个”的道路。

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

这是一个 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;

}