Разбор произвольного формата даты в дартс

Я разрабатываю приложение, которое должно принимать даты в произвольном формате — другими словами, если оно ходит как дата, говорит как дата, это дата.

Я попытался адаптировать синтаксический анализатор формата даты из пакета moment.js для генерации строки формата с некоторым частичным успехом, но столкнулся с ситуацией, когда входная строка содержит какой-то элемент, который не распознается.

Например, кажется, что нет правильного формата для работы со строкой

Thu Nov 07 2019 13:50:03 GMT-0800 (PST)

-- или, по крайней мере, один, который кажется мне понятным, но, возможно, я что-то упустил в документации.

Я просмотрел https://pub.dev/documentation/intl/latest/intl/DateFormat-class.html, но я не вижу способа, например, игнорировать поля, которые могут быть нерелевантными, или правильно кодировать формат (например, поле GMT-0800).

Я использую пакет jiffy для анализа даты, если это имеет значение.

Далее: я подозреваю, что я ищу что-то, что действует более или менее как strptime() в языке C. А может и нет.


person Teakwood J Overclutch    schedule 30.09.2020    source источник


Ответы (3)


если он ходит как свидание, говорит как свидание, это свидание

Проблема в том, что нет ни такой прогулки, ни такого свидания.

Даты — это проблема для правильной реализации на любом языке, поскольку нет правил, определяющих точно то, как люди должны форматировать дату. Произвольно отформатированные даты, которые вы запрашиваете, ну, они не будут многого стоить, поскольку они не будут представлять фактические даты предсказуемым образом. Ознакомьтесь с последними вопросами, связанными с датой/временем здесь, на SO, чтобы получить представление!

Используя класс Dart DateTime, вы можете создать объект DateTime только путем анализа правильно отформатированной строки, которая соответствует подмножеству ИСО 8601

Как вы получите такую ​​строку из произвольного ввода, должно быть определено вами.

Вы можете использовать некоторые предопределенные константы для улучшения читаемости кода, но использование класса DateTime напрямую потребует от вас написания довольно классного кода для извлечения и форматирования любого возможного восприятия даты в любой точке мира в правильный синтаксис для создания пригодного для использования Объект DateTime. Может быть, создать ИИ для ввода даты!

К счастью, вы можете сделать много тяжелой работы, используя упомянутый вами класс: DateFormat Class, и именно так я бы атаковал это.

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

Но точную логику лучше создать самостоятельно, так как она будет варьироваться от случая к случаю/от приложения к приложению.

person cseder    schedule 30.09.2020
comment
Спасибо. Как я уже упоминал, я как бы портировал генератор формата даты для moment.js, который генерирует строку формата, которую затем можно применить к рассматриваемой строке, чтобы получить объект DateTime в качестве награды за ваши усилия. Чего мне не хватало (и действительно не хватало в документации), так это экранирования текста для неразобранных литералов. Инкапсуляция GMT-0800 в GMT-0800 вместе с небольшой дополнительной логикой в ​​синтаксическом анализаторе сделали свое дело. - person Teakwood J Overclutch; 30.09.2020

Основной ответ, как я упоминал в комментарии к cseder, заключался в том, чтобы инкапсулировать неинтересные токены строки даты в одинарные кавычки в соответствии с документацией.

Например, формат

EEE MMM DD yyyy H:mm:ss 'GMT-0800' '(PST)'

счастливо анализирует строку

Thu Nov 07 2019 13:50:03 GMT-0800 (PST)

Я, вероятно, также могу решить проблемы с часовым поясом, но это решает непосредственный вопрос.

person Teakwood J Overclutch    schedule 30.09.2020
comment
Ага, исходя из упрощенной, искусственной, настраиваемой реальности, этого было бы достаточно. - person cseder; 11.10.2020
comment
А что такое программирование, как не упрощенная, искусственная, настраиваемая реальность? Приношу свои извинения за нанесенное оскорбление. - person Teakwood J Overclutch; 12.10.2020
comment
Ну, это и не так. Он заключается в том, что он имеет дело с конкретным экземпляром в конкретном контексте конкретной проблемы, которая должна была иметь дело с этой конкретной строкой. Дело не в том, что он явно не имеет дело со всей вселенной синтаксического анализа даты в свободной форме, что я полностью признал в другом комментарии. У меня есть другие мысли по этому поводу, включая подход Dart к обработке даты/времени, но их, вероятно, лучше оставить для какого-то другого форума. - person Teakwood J Overclutch; 13.10.2020

Существует несколько способов анализа различных форматов меток времени. Но обратите внимание, что принятие совершенно произвольных форматов может быть неоднозначным: 01-02-2020 означает 2 января 2020 года (обычное соглашение в США) или 1 февраля 2020 года (большинство других частей мира)?

В конкретном случае, который вы описываете, я бы сначала разбил строку с помощью RegExp (или из .split(' ')), чтобы разделить биты, которые может обрабатывать DateFormat (в основном все, кроме часовых поясов, которые DateFormat не поддерживает). Хотя вы можете использовать механизм DateFormat для экранирования буквального текста, чтобы игнорировать часовой пояс, это будет работать только в том случае, если часовой пояс гарантированно никогда не изменится. Даже если строки поступают с сервера в фиксированном месте, GMT-0800 (PST) может измениться на GMT-0700 (PDT), если действовало летнее время.

Сам часовой пояс можно разобрать вручную с помощью RegExp или использовать TZDateTime.parse из package:timezone.

Я считаю, что следующий код должен анализировать строку как объект UTC DateTime:

DateTime parseDate(String timestamp) {
  final re = RegExp(''
      r'^(?<datetime>\w{3} \w{3} \d{2} \d{4} \d{2}:\d{2}:\d{2}) '
      r'\w{3}(?<offset>[+-]\d{4}) '
      r'.*$');
  final match = re.firstMatch(timestamp);
  if (match == null) {
    throw FormatException('Failed to parse timestamp: $timestamp');
  }

  final rawOffsetFromGMT = int.parse(match.namedGroup('offset'));
  final offsetFromGMT = Duration(
    hours: rawOffsetFromGMT ~/ 100,
    minutes: rawOffsetFromGMT.remainder(100),
  );

  return DateFormat('EEE MMM DD yyyy H:mm:ss')
      .parse(
        match.namedGroup('datetime'),
        true,
      )
      .subtract(offsetFromGMT);
}

void main() {
  print(parseDate('Thu Nov 07 2019 13:50:03 GMT-0800 (PST)'));
}
person jamesdlin    schedule 30.09.2020
comment
Спасибо. Я полностью понимаю двусмысленность в синтаксическом анализе даты. Поверьте, у меня есть боевые шрамы, подтверждающие это. Моя проблема заключалась просто в том, что я упустил важный момент в документации об экранировании строк, и, да, я понимаю, что это не общее решение - это просто привело меня к немедленному горбу, и мне придется вернуться назад и сделать некоторые дальнейшие дополнения к коду позже. - person Teakwood J Overclutch; 01.10.2020