Синхронизация дат без всех указанных значений

Я использую даты свободной формы как часть синтаксиса поиска. Мне нужно анализировать даты из строк, но сохранять только те части даты, которые указаны на самом деле. Например, "ноябрь 1, 2010" - конкретная дата, но "ноябрь 2010" - это диапазон дат "1 ноября 2010 года" до "30 ноября 2010 года".

К сожалению, DateTime.Parse и друзья проанализируют эти даты с тем же DateTime:

DateTime.Parse("November 1, 2010") // == {11/1/2010 12:00:00 AM}
DateTime.Parse("November, 2010") // == {11/1/2010 12:00:00 AM}

Мне нужно знать, какие части DateTime были фактически проанализированы и которые были догаданы парсером. По сути, мне нужно DateTime.Parse("November, 2010") == {11/-1/2010 -1:-1:-1}; Затем я вижу, что часть дня отсутствует и вычисляет диапазон дат, охватывающих весь месяц.

(Internally, С# имеет классы DateTimeParse и DateTimeResult, которые анализируют дату и сохраняют именно ту информацию, которая мне нужна, но к тому времени, когда дата вернется к общедоступным интерфейсам, она была удалена. избегайте отражения в этих классах, если только это не единственный путь.)

Есть ли способ получить DateTime.Parse, чтобы сообщить мне, какой формат он использовал для анализа даты? Или может ли возвращенный DateTime заполнить местами для неуказанных частей? Я также открыт для использования другого синтаксического анализа даты, но я бы хотел, чтобы он был таким же надежным и локальным, как и внутренний. Спасибо заранее.

EDIT: Я также пробовал ParseExact, но перечисление всех форматов, которые может обрабатывать Parse, кажется почти невозможным. Parse фактически принимает больше форматов, чем возвращается DateTimeFormatInfo.GetAllDateTimePatterns, который является как канонический источник, который я могу найти.

Ответы

Ответ 1

Вы можете попробовать использовать TryParseExact(), который не будет работать, если строка данных не указана в точном формате. Попробуйте множество комбинаций, и когда вам удастся узнать формат, в котором была дата, и, следовательно, вы знаете те части даты, которые там не были, и для которых парсер заполнял значения по умолчанию. Недостатком является то, что вы должны предвидеть, как пользователь хочет вводить даты, поэтому вы можете ожидать именно это.

Вы также можете использовать Regex для переваривания строки даты самостоятельно. Опять же, вам понадобятся разные регулярные выражения (или ДЕЙСТВИТЕЛЬНО сложные одиночные), но, безусловно, можно также вывести эту строку; то вы знаете, что у вас на самом деле.

Ответ 2

Parse анализирует множество вещей, которые ни один здравомыслящий человек не вводил бы в качестве даты, например "January / 2010 - 21 12: 00 :2". Я думаю, вам нужно будет написать свой собственный синтаксический анализатор даты, если вы хотите узнать, что именно вводил пользователь.

Лично я бы сделал это, как предложил KeithS: проанализируйте строку с помощью Parse и вызовите только свою собственную функцию синтаксического анализа, если в одном из полей объекта DateTime есть 0. Есть не те возможности, которые вам нужно проверить, потому что если день равен 0, время тоже будет 0. Итак, начните проверять год, месяц, день и т.д.

Или просто попросите пользователя использовать определенные вами форматы.

Ответ 3

По сути, мне нужно DateTime.Parse( "Ноябрь 2010" ) == {11/-1/2010 -1: -1: -1}; Тогда я могу видеть что часть дня отсутствует и рассчитать диапазон дат, охватывающих весь месяц.

То, что вы хотите, является незаконным DateTime, потому что вы не можете иметь отрицательные часы/секунды/минуты/день. Если вы хотите вернуть что-то другое, кроме юридического DateTime, вы должны написать свой собственный метод, который НЕ возвращает DateTime.

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

Взгляните здесь http://msdn.microsoft.com/en-us/library/w2sa9yss.aspx

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

Ответ 4

Я использовал этот метод, который возвращается к исходной строке, чтобы проверить существование дня и года:

  • Для дней исходная строка должна содержать значение 1 как целое, если указан день. Итак, разделите строку и найдите 1. Единственное исключение возникает, когда месяц - январь (# 1 месяц), поэтому вам нужно проверить два 1 или 1 и "Январь" или "Янв" в исходной строке.
  • Для лет исходная строка должна содержать число, которое может быть годом (например, с 1900 по 2100 год). Другими возможностями могут быть использование апострофа или таких вещей, как 02-10-16, которые вы можете признать по тому факту, что существует ровно три числа.

Я знаю, что это довольно эвристическое, но это быстрое и простое решение, которое работает в большинстве случаев. Я закодировал этот алгоритм в С# в DateFinder.DayExists() и DateFinder.YearExists() в библиотеке sharp-datefinder.