Разбор очень длинного формата даты в DateTime в C#

Как бы я проанализировал следующую строковую дату для объекта DateTime в C#:

"Четверг, 1 января 1970 года"

Это происходит из фида XML, и DateTime.Parse, похоже, не нравится в локали en-GB. Фид будет поступать только с британского сервера, поэтому меня не волнуют проблемы глобализации.

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

  • Удалите все до запятой, включая запятую и пробел, чтобы оставить "1 января 1970"
  • Затем удалите "st", "nd", "rd" или "th", если необходимо, чтобы оставить "1 января 1970"
  • Затем конвертируйте месяц в его числовой эквивалент, оставляя "1 1 1970"
  • Затем замените пробелы на "/", чтобы получить "01.01.1970"

Я уверен, что должен быть куда более элегантный способ? Я не мог заставить DateTime.Prse или Datetime.ParseExact работать

3 ответа

Решение

Просто, чтобы дать немного другое представление об этом, и дать вам представление о некоторых других вариантах, которые у вас есть; Вы можете указать формат DateTime.Parse (или TryParse, как в моем примере) для учета обстоятельств, подобных этому, без попытки "предварительно отформатировать" строку во что-то еще с String.Replace звонки и тому подобное;

public DateTime ParseOrdinalDateTime(string dt)
{
    string[] expectedFormats = 

    DateTime d;
    if (DateTime.TryParseExact(dt, "dddd, d\"st\" MMMM yyyy", null, DateTimeStyles.None, out d))
        return d;
    if (DateTime.TryParseExact(dt, "dddd, d\"nd\" MMMM yyyy", null, DateTimeStyles.None, out d))
        return d;
    if (DateTime.TryParseExact(dt, "dddd, d\"rd\" MMMM yyyy", null, DateTimeStyles.None, out d))
        return d;
    if (DateTime.TryParseExact(dt, "dddd, d\"th\" MMMM yyyy", null, DateTimeStyles.None, out d))
        return d;

    throw new InvalidOperationException("Not a valid DateTime string");
}

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

Или небольшое отклонение от приведенного выше, принимая во внимание комментарии ниже;

private static DateTime ParseOrdinalDateTime(string dt)
{
    string[] expectedFormats = new[]
    {
        "dddd, d'st' MMMM yyyy",
        "dddd, d'nd' MMMM yyyy",
        "dddd, d'rd' MMMM yyyy",
        "dddd, d'th' MMMM yyyy"
    };

    try
    {
        return DateTime.ParseExact(dt, expectedFormats, null, DateTimeStyles.None);
    }
    catch (Exception e)
    {
        throw new InvalidOperationException("Not a valid DateTime string", e);
    }
}

ПРИМЕЧАНИЕ. Единственная причина, по которой я перехватываю исключение InvalidOperationException, приведенное выше, - это защита вызывающего абонента от необходимости catch Exception обрабатывать любые возможные исключения DateTime.ParseExact может бросить. Вы можете легко изменить этот API.

Я не верю этому DateTime Синтаксический анализ знает что-либо о порядковых числах, но он должен уметь обрабатывать все остальное Таким образом, вы можете использовать:

public static string RemoveOrdinals(string input)
{
    // Ugly but oh so simple.
    return input.Replace("0th", "0")
                .Replace("1st", "1")
                .Replace("2nd", "2")
                .Replace("3rd", "3")
                .Replace("11th", "11") // Need to handle these separately...
                .Replace("12th", "12")
                .Replace("13th", "13")
                .Replace("4th", "4")
                .Replace("5th", "5")
                .Replace("6th", "6")
                .Replace("7th", "7")
                .Replace("8th", "8")
                .Replace("9th", "9");
}

Затем:

string text = RemoveOrdinals(text);
DateTime date = DateTime.ParseExact(text, "dddd, d MMMM yyyy",
                                    CultureInfo.GetCulture("en-GB"));

(Как быстрый плагин, конечно, вы хотите просто дату, а не дату / время. К сожалению..NET не имеет типа, чтобы представлять это - но вы могли бы использовать LocalDate в моей библиотеке Noda Time. Мы не работаем с ординалами - пока, во всяком случае, - поэтому вам все еще нужен дополнительный метод. Дайте мне знать, если вы хотите увидеть соответствующий код.)

Использование DateTime.Parse с форматером, специфичным для культуры:

http://msdn.microsoft.com/en-us/library/kc8s65zs.aspx

Сначала поменяйте логику в этом ответе, чтобы убрать "st", "nd" и т. Д. Со дня месяца:

/questions/45652234/kak-mne-sozdat-format-datyi-takoj-kak-1-noyabrya-v-c/45652248#45652248

Тогда просто используйте DateTime.Parse обычно:

var result = DateTime.Parse("Thursday, 1 January 1970", new CultureInfo("en-GB"));
Другие вопросы по тегам