Разбор нестандартных форматов даты с DateTime.TryParseExact - PullRequest
4 голосов
/ 29 августа 2011

Привет, я пытаюсь разобрать строки даты, такие как "1012012", "1 января 2012".

  1. прочитайте API Это говорит использовать d,% d, где дата не имеет начального 0. Не могу заставить его работать для дат, таких как "1012012"

  2. пытаясь использовать "d MMM YYYY" для "1 января 2012", что я использую, чтобы 'st', 'th' работали?

    using System;
    using System.IO;
    using System.Globalization;
    
    namespace test
    {
      class Script
      {
        static public void Main(string [] args)
        {
    
            //String dateString = "9022011";  // q1
            String dateString = "9th February 2011";  //q2
            System.DateTime date = DateTime.MinValue;
            string[] format = { "ddMMyyyy", "d MMM yyyy" }; // what would be the correct format strings?
    
            if (DateTime.TryParseExact(dateString,format,new CultureInfo("en-AU"),DateTimeStyles.None,out date))
                            {
                Console.Out.WriteLine(date.ToString());
            } 
                            else
                            {
                Console.Out.WriteLine("cant convert");
            }
         }
      }
    
    }
    

Ответы [ 3 ]

4 голосов
/ 29 августа 2011
  1. Не думаю, что это можно сделать.Синтаксический анализатор обрабатывает ваш ввод слева направо, поэтому, если он увидит «1012012», он будет считать, что день равен 10, а затем не сможет выполнить синтаксический анализ, потому что осталось недостаточно символов, даже если строка формата - «dMMyyyy».Потребовалось бы какое-то обратное отслеживание, чтобы учесть вероятность того, что день равен 1, но, к сожалению, этого не происходит.

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

    string input = "1012012";
    Match m = Regex.Match(input, @"^(?<day>\d{1,2})(?<month>\d{2})(?<year>\d{4})$");
    if( m.Success )
    {
        DateTime d = new DateTime(Convert.ToInt32(m.Groups["year"].Value),
                                  Convert.ToInt32(m.Groups["month"].Value),
                                  Convert.ToInt32(m.Groups["day"].Value));
    }
    

    Другой вариант - просто добавить начальный ноль, если длина строки семь:

    string input = "1012012";
    if( input.Length == 7 )
        input = "0" + input;
    DateTime d = DateTime.ParseExact(input, "ddMMyyyy", CultureInfo.CurrentCulture);
    
  2. Вместо того, чтобы пытаться выполнить несколько операций поиска и замены, как в других ответах, вы можете использовать тот факт, что точный формат строки известен.Он начинается с одной или двух цифр, за которыми следуют две буквы, за которыми следуют месяц и год.Таким образом, вы можете извлечь дату следующим образом:

    string input = "1st January 2012";
    int index = char.IsNumber(input, 1) ? 2 : 1;
    input = input.Substring(0, index) + input.Substring(index + 2);
    DateTime d = DateTime.ParseExact(input, "d MMMM yyyy", CultureInfo.InvariantCulture);
    

    Конечно, это будет принимать даты, которые имеют чистую чепуху в этих позициях, например, «1xx январь 2012», но я не уверен, что это проблемав вашем случае.

    Также обязательно передайте соответствующий CultureInfo, если на входе могут содержаться неанглийские названия месяцев.

Если вы можете получить любой формат беззная заранее, что вы получаете, вам нужно будет просто проверить, какой метод использовать заранее.Строки в первом формате всегда будут состоять из 7 или 8 символов, а строки во втором формате всегда будут длиннее, поэтому это должно быть легко проверить.Другой способ - проверить, содержит ли строка какие-либо нечисловые символы (в этом случае это длинный формат).

3 голосов
/ 29 августа 2011
var dateString = "1st February 2011";
DateTime date;
var replaced = dateString.Substring(0,4)
                         .Replace("nd","")
                         .Replace("th","")
                         .Replace("rd","")
                         .Replace("st","")
                         + dateString.Substring(4);

DateTime.TryParseExact(replaced, "d MMMM yyyy",
                       new CultureInfo("en-us"), DateTimeStyles.AssumeLocal, 
                       out date);

должен сделать трюк (извините, 'th' противный) - вы должны позаботиться о st (август) - просто удалите его только из первых нескольких появлений:

2 голосов
/ 29 августа 2011

Если вы хотите разобрать строки дат, относящиеся к конкретной культуре, вы должны использовать соответствующую культуру.CultureInfo.InvariantCulture не очень хорошая идея, потому что она будет работать только с английскими строками.
Однако то, что вы пытаетесь сделать, невозможно только с помощью спецификаторов формата, потому что нет дня, который может разобратьth "," st "и т. д. строки.Вам придется предварительно удалить их вручную.

...