Правильно форматировать/анализировать разные форматы даты

Я получаю Date в 3-х форматах от разных APIs

  1. UTC формат: 2014-01-01T00:00:00.000Z (String)
  2. GMTформат: Thu, 29 Nov 2018 17:30:56 GMT (String)
  3. unixTimeStamp: 1558606726 (number)

Кроме того, формат UTC иногда может не иметь Z в конце, поэтому обычный синтаксический анализ даст разницу во времени.

function formatDate(dateString) {
  var dateTime, utcFormatRegex, zeroHourOffsetRegex;

// Some APIs return a Date in standard ISO UTC format may not have Z at the end
  utcFormatRegex = /^\d{4}-\d{2}-\d{2}T.*$/;
  zeroHourOffsetRegex = /^.*Z$/;

  if (utcFormatRegex.test(dateString) && !zeroHourOffsetRegex.test(dateString)) {
    dateString+='Z';
  }

    dateTime = new Date(dateString);

}

Учитывая, что существуют функции синтаксического анализа для всех различных форматов, мне нужна функция, которая определяет, какую функцию синтаксического анализа мы должны использовать на основе regex и parse соответственно. Если регулярное выражение не является идеальным решением, то как я могу подойти к этому?

Я имею в виду, что, вероятно, должно быть более надежное решение, чем «если нет Z, то добавьте его», чтобы заставить его анализировать синтаксический анализатор времени с одной датой. Что, если мы получим другой формат даты и времени, который плохо работает с буквой Z в конце? В этот момент мы внесем несколько изменений.

зачем нужно регулярное выражение?

Kunal Mukherjee 30.05.2019 11:47

Я пробовал, пожалуйста, не делайте таких предположений. Я задал этот вопрос без кода, чтобы получить общее предложение, как к этому подойти. Моя функция выглядит примерно так: codepen.io/kira510/pen/YbJOwe.

Kiran Kumar 30.05.2019 12:25

@Liam ^^ Приведенный выше код для справки.

Kiran Kumar 30.05.2019 12:33
пожалуйста, не делай таких предположений вам нужно включить в вопрос то, что вы пробовали, иначе да, люди будут делать предположения.
Liam 30.05.2019 12:38

Так что именно вы здесь застряли? У вас есть регулярное выражение, которое проверяет первый формат, создает регулярное выражение для двух других, и все готово?

Liam 30.05.2019 12:40

Формат UTC может иметь Z или нет в конце, и добавление проверки регулярного выражения в середине, по моему мнению, не идеальное решение. Я предполагаю, что я имею в виду, что, вероятно, должно быть более надежное решение, чем «если нет Z, то добавьте его», чтобы заставить его анализировать синтаксический анализатор времени с одной датой. Что, если мы получим другой формат даты и времени, который плохо работает с буквой Z в конце? В этот момент мы внесем несколько изменений.

Kiran Kumar 30.05.2019 12:44

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

RobG 30.05.2019 13:35

просто сделайте Z необязательным Z?

Liam 30.05.2019 13:40

Вы знаете, что невозможно написать регулярное выражение, которое будет анализировать форматы даты все, верно? Я до сих пор понятия не имею, что вы на самом деле спрашиваете

Liam 30.05.2019 13:41

"В этот момент мы внесем несколько изменений." действительно. Вы не можете надежно проанализировать случайную строку, вы должен знаете формат, и вы должны сообщить анализатору или использовать правильный анализатор для формата.

RobG 30.05.2019 15:04
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
10
107
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Использование регулярных выражений допустимо, но вам нужно строго тестировать форматы, которые вы ожидаете. Если вы получите что-то, чего не ожидаете, выдайте ошибку. Один из недостатков текущих встроенных анализаторов заключается в том, что нет возможности указать строгий анализ, например. где предоставляется формат, и синтаксический анализатор выдает ошибку, если входная строка не совпадает.

Есть библиотеки, которые могут помочь, поиск покажет немало.

Но если вам нужно поддерживать только 3 формата в OP, может подойти что-то вроде следующего:

/* Return a Date where the input may be:
**   string: ISO 8601 timestamp that should be treated as UTC
**           whether it has a trailing Z or not
**   string: Timestamp in the format (using moment.js tokens): 
**           ddd, DD MMM YYYY HH:mm:ss GMT 
**   nunber: UNIX time value, seconds since 1970-01-01 UTC
*/
function toDate(value) {
  // Parse the string & fail early if it fails
  let d = new Date(value);
  
  // Throw error if couldn't parse value
  if (isNaN(d.getTime())) {
    throw 'Invalid timestamp: ' + value;
  }
  
  // Otherwise, do the work
  let days = 'Sun Mon Tue Wed Thu Fri Sat'.split(' ');
  let months = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');

  // Test for time value first as that's the easiest
  if (typeof value == 'number' && !isNaN(value)) {
    return new Date(value * 1000);
    
  // Test for ISO 8601 next
  } else if (/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d\d\dZ?$/.test(value)) {
    return new Date(/Z$/.test(value)? value : value + 'Z');
    
  // Test for random format
  } else if (/^[a-z]{3}, \d?\d [a-z]{3} \d{4} \d\d:\d\d:\d\d GMT$/i.test(value)) {
    let b = value.split(/ |:/);

    if (days.includes(b[0].substr(0,3)) && months.includes(b[2])) {
      let x = new Date(Date.UTC(
                b[3],                 // year
                months.indexOf(b[2]), // month, zero indexed
                b[1],                 // day
                b[4], b[5], b[6]      // hh:mm:ss
              ));
      // Check value was a valid date, only need to check some parts
      if (x.getUTCFullYear() == b[3] &&
          x.getUTCDate() == b[1] &&
          x.getUTCHours() == b[4] &&
          x.getUTCSeconds() == b[6]) {
        return x;
      } else {
        throw 'Invalid timestamp: ' + value;
      }
    }

  // Throw error as must be unknown format
  } else {      
    throw 'Unknown format: ' + value;
  }
}

// Minimal testing 
var isoString0 = '2014-01-01T00:00:00.000Z',
    isoString1 = '2014-01-01T00:00:00.000',         // no Z, parse as UTC anyway
    randomString = 'Thu, 29 Nov 2018 17:30:56 GMT',
    unixTimeValue = 1558606726,                     // Assume seconds
    invalidDate0 = '2018-02-29T00:00:00.000Z',      // no 29 Feb in 2018, fail built-in parse
    invalidDate1 = 'Thu, 29 Feb 2018 17:30:56 GMT', // no 29 Feb in 2018, fail manual parse
    invalidFormat = '6/6/2019';                     // Unknown format

[isoString0, isoString1, randomString, unixTimeValue, invalidDate0,
 invalidDate1, invalidFormat].forEach(s => {
  var result;
  try {
    result = toDate(s);
    console.info(s + ' =>\n' + result.toISOString());
  } catch (e) {
    console.info(e);
  }
});

Является ли формат часового пояса без Z в конце принятым форматом? Согласно стандарту ISO, Z является обязательным для информирования о том, что это UTC. Без Z это дает GMT?

Kiran Kumar 31.05.2019 13:55

Другие вопросы по теме