Как преобразовать даты, возвращаемые из webapi в строковом формате, в формат даты javascript для AngularJs

У меня есть ряд действий .net webApi, возвращающих даты, которые десериализуются в JSON. Затем мое угловое приложение использует эти строки даты для отображения\редактирования или в качестве ngModel в различных директивах даты. Для многих из этих директив требуется объект даты javascript, а не строковое представление даты. Как сериализовать строку даты обратно в дату javascript для всех возвращаемых данных webapi?

Н.Б. Я пробовал множество регулярных выражений, которые претендуют на совместимость с 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, так как это часть более длинной строки»


person sarin    schedule 22.06.2016    source источник


Ответы (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;
            }
        };
    });
})();

Таким образом, приведенный выше код изначально был взят где-то из Интернета и имел ручное сравнение регулярных выражений. Регулярное выражение было описано как соответствующее ISO 8601, но я нашел множество примеров, когда это не так. Теперь это зависит от моментов библиотеки с открытым исходным кодом, чтобы определить, является ли дата ISO 8601 и выполнить преобразование. Если дата не соответствует, строковое значение просто возвращается. ISO 8601 — отличный стандарт для использования (поскольку он охватывает множество случаев), и он намного лучше, чем жесткое кодирование любого ожидаемого конкретного формата, который может привести вас к тому, что «о… это пропущено».

На данный момент это анализ всех возвращаемых значений объекта ответа для потенциальных дат. Я подумал об улучшении этого, явно пометив запрос свойствами ответа, которые, как мы ожидаем, будут датами. Таким образом, нам не пришлось бы пытаться/разбирать все (что медленно), а также рисковать тем, что что-то, что мы не хотим конвертировать, будет преобразовано. Однако этот подход немного запутан и замусорит много запросов. Мне нравится этот подход на данный момент, и он, кажется, работает. Рад, что его доработали!

person sarin    schedule 22.06.2016

Вот решение 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;

}

person CaptainDingle    schedule 29.11.2018