2013-07-17 2 views
2

Как бы я разобрать следующую строку даты в объект DateTime в C#:Анализировать формат очень долго дата DateTime в C#

«в четверг, 1 января 1970 года»

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

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

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

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

+0

осторожно при удалении «st», если вы ожидаете августа. Попробуйте Regex.Replace («1 августа 2009», «([0-9]) (st | nd | rd | th)», «$ 1»); очевидно, используя вашу дату вместо строки, которую я использовал в качестве примера. – Steve

ответ

5

Просто чтобы предоставить sli ghtly different берут на себя это и дают вам представление о некоторых других вариантах, которые у вас есть; вы можете указать формат 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.

+0

Почему бы не использовать перегрузку, которая принимает несколько шаблонов? Кроме того, вы можете использовать '' 'вместо' '', чтобы процитировать часть шаблона, что упростило бы это. –

+0

Это тоже было бы неплохо. –

+2

Я бы также предложил явно указать культуру - мы знаем, что это значит чтобы быть, так зачем полагаться на текущую культуру потока? –

6

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

+0

Просто примечание об ординалах; формы «2d» и «3d» обычно считаются приемлемыми для словаря (если нечасто используются) вместо «2-го» и «третьего». Убедитесь, что они правильно разбираются. – Tenner

+0

@Tenner: Я был бы удивлен, если бы в этом контексте. Есть только так много угловых случаев, о которых стоит беспокоиться, ИМО. –

+0

Я не предполагаю знать, что рядом с вами так же, как и вы, Джон, но не проще ли просто «Заменить (« th »,« ») .Replace (« nd »,« »)' etc? Это позаботится о таких случаях, как 21, 12, 22. Или есть еще одна причина, по которой разработчик хотел бы закодировать 'Replace()' для каждой потенциальной даты? –

0

Использовать DateTime.Parse с определенной культурой f ormatter:

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

Первый реверс логики в этом ответе раздеть "ул", "е" и т.д. со дня месяца:

https://stackoverflow.com/a/4544313/2420979

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

var result = DateTime.Parse("Thursday, 1 January 1970", new CultureInfo("en-GB")); 
+1

Ответ, который вы получили связанный с конвертированием * в * порядковый формат - не * из * его. Я также рекомендую использовать определенный формат, а не только 'DateTime.Parse', который всегда очень похож на« хит и надежду »для меня. –

+0

Верно, и извините, я хотел сказать REVERSE логику ... Обновление. :) – Haney

Смежные вопросы