Строка parse для DateTime в С#

У меня есть дата и время в строке, отформатированной так:

"2011-03-21 13:26" //year-month-day hour:minute

Как я могу разобрать его на System.DateTime?

Я хочу использовать функции типа DateTime.Parse() или DateTime.ParseExact(), если это возможно, чтобы указать формат даты вручную.

Ответ 1

DateTime.Parse() попробует выяснить формат данной даты, и обычно это делает хорошую работу. Если вы можете гарантировать, что даты всегда будут в определенном формате, вы можете использовать ParseExact():

string s = "2011-03-21 13:26";

DateTime dt = 
    DateTime.ParseExact(s, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);

(Но учтите, что обычно безопаснее использовать один из методов TryParse в случае, если дата не находится в ожидаемом формате)

Обязательно проверьте Пользовательские строки формата даты и времени при построении строки формата, особенно обратите внимание на количество букв и фраз (например, "ММ" и "мм" означают совсем другие вещи).

Другим полезным ресурсом для строк формата С# является Форматирование строк в С#

Ответ 2

Как я TryParse позже, я всегда TryParse TryParseExact методы TryParse и TryParseExact. Поскольку они немного громоздки в использовании, я написал метод расширения, который значительно упрощает анализ:

var    dtStr = "2011-03-21 13:26";
DateTime? dt = dtStr.ToDate("yyyy-MM-dd HH:mm");

В отличие от Parse, ParseExact и т.д. Он не ParseExact исключение и позволяет проверять через

if (dt.HasValue) {//continue processing } else {//do error handling }

было ли преобразование успешным (в этом случае dt имеет значение, к dt.Value вы можете получить доступ через dt.Value) или нет (в этом случае оно равно null).

Это даже позволяет использовать элегантные ярлыки, такие как "Элвис" -operator ?. , например:

int? year = dtStr?.ToDate("yyyy-MM-dd HH:mm")?.Year;

Здесь вы также можете использовать year.HasValue чтобы проверить, year.HasValue ли выполнено преобразование, и если оно не удалось, то year будет содержать значение null, в противном случае - часть года в дате. Нет исключения, если преобразование не удалось.


Решение: метод расширения .ToDate()

Попробуйте это в .NetFiddle

public static class Extensions
{
    // Extension method parsing a date string to a DateTime?
    // dateFmt is optional and allows to pass a parsing pattern array
    // or one or more patterns passed as string parameters
    public static DateTime? ToDate(this string dateTimeStr, params string[] dateFmt)
    {
      // example: var dt = "2011-03-21 13:26".ToDate(new string[]{"yyyy-MM-dd HH:mm", 
      //                                                  "M/d/yyyy h:mm:ss tt"});
      // or simpler: 
      // var dt = "2011-03-21 13:26".ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");
      const DateTimeStyles style = DateTimeStyles.AllowWhiteSpaces;
      if (dateFmt == null)
      {
        var dateInfo = System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat;
        dateFmt=dateInfo.GetAllDateTimePatterns();
      }
      // Commented out below because it can be done shorter as shown below.
      // For older C# versions (older than C#7) you need it like that:
      // DateTime? result = null;
      // DateTime dt;
      // if (DateTime.TryParseExact(dateTimeStr, dateFmt,
      //    CultureInfo.InvariantCulture, style, out dt)) result = dt;
      // In C#7 and above, we can simply write:
      var result = DateTime.TryParseExact(dateTimeStr, dateFmt, CultureInfo.InvariantCulture,
                   style, out var dt) ? dt : null as DateTime?;
      return result;
    }
}

Некоторая информация о коде

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

Обновление: .ToDate() (без параметров) теперь по умолчанию использует все распространенные шаблоны даты/времени в текущей культуре потока.
Обратите внимание, что нам нужен result и dt вместе, потому что TryParseExact не позволяет использовать DateTime? , который мы намерены вернуть. В С# версии 7 вы могли бы немного упростить функцию ToDate следующим образом:

 // in C#7 only: "DateTime dt;" - no longer required, declare implicitly
 if (DateTime.TryParseExact(dateTimeStr, dateFmt,
     CultureInfo.InvariantCulture, style, out var dt)) result = dt;

или, если вам нравится еще короче

 // in C#7 only: Declaration of result as a "one-liner" ;-)
 var result = DateTime.TryParseExact(dateTimeStr, dateFmt, CultureInfo.InvariantCulture,
              style, out var dt) ? dt : null as DateTime?;

в каком случае вам не нужны два объявления DateTime? result = null; DateTime? result = null; и DateTime dt; вообще - вы можете сделать это в одной строке кода. (Было бы также разрешено записывать out DateTime dt вместо out var dt если вы предпочитаете это).

Я упростил код дальше, используя params ключевое слово: Теперь вам не нужно перегруженный метод 2 - й больше.


Пример использования

var dtStr="2011-03-21 13:26";    
var dt=dtStr.ToDate("yyyy-MM-dd HH:mm");
if (dt.HasValue)
{
    Console.WriteLine("Successful!");
    // ... dt.Value now contains the converted DateTime ...
}
else
{
    Console.WriteLine("Invalid date format!");
}

Как вы можете видеть, этот пример просто запрашивает dt.HasValue чтобы увидеть, было ли преобразование успешным или нет. В качестве дополнительного бонуса, TryParseExact позволяет указать строгий DateTimeStyles чтобы вы точно знали, была ли передана правильная строка даты/времени или нет.


Больше примеров использования

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

string[] dateFmt = {"M/d/yyyy h:mm:ss tt", "M/d/yyyy h:mm tt", 
                     "MM/dd/yyyy hh:mm:ss", "M/d/yyyy h:mm:ss", 
                     "M/d/yyyy hh:mm tt", "M/d/yyyy hh tt", 
                     "M/d/yyyy h:mm", "M/d/yyyy h:mm", 
                     "MM/dd/yyyy hh:mm", "M/dd/yyyy hh:mm"};
var dtStr="5/1/2009 6:32 PM"; 
var dt=dtStr.ToDate(dateFmt);

Если у вас есть только несколько шаблонов шаблонов, вы также можете написать:

var dateStr = "2011-03-21 13:26";
var dt = dateStr.ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");

Расширенные примеры

Вы можете использовать ?? оператор по умолчанию в отказоустойчивом формате, например

var dtStr = "2017-12-30 11:37:00";
var dt = (dtStr.ToDate()) ?? dtStr.ToDate("yyyy-MM-dd HH:mm:ss");

В этом случае .ToDate() будет использовать распространенные локальные форматы дат культуры, и если все это не удастся, он попытается использовать стандартный формат ISO "yyyy-MM-dd HH:mm:ss" в качестве запасного варианта. Таким образом, функция расширения позволяет легко "связывать" различные резервные форматы.

Вы даже можете использовать расширение в LINQ, попробуйте это (оно в .NetFiddle выше):

var patterns=new[] { "dd-MM-yyyy", "dd.MM.yyyy" };
(new[] { "15-01-2019", "15.01.2019" }).Select(s => s.ToDate(patterns)).Dump(); 

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


Немного предыстории о TryParseExact

Наконец, вот несколько комментариев об истории вопроса (т.е. причина, по которой я написал это так):

Я предпочитаю TryParseExact в этом методе расширения, потому что вы избегаете обработки исключений - вы можете прочитать в статье Эрика Липперта об исключениях, почему вы должны использовать TryParse, а не Parse, я процитирую его по этой теме: 2)

Это неудачное дизайнерское решение 1) [аннотация: позволить методу Parse генерировать исключение] было настолько досадным, что вскоре после этого команда разработчиков интегрировала TryParse, что делает правильную вещь.

Это так, но TryParse и TryParseExact по-прежнему намного менее удобны в использовании: они вынуждают вас использовать неинициализированную переменную в качестве параметра out который не должен иметь значение NULL, и во время преобразования вам нужно оценить логическое возвращаемое значение - либо вы должны немедленно использовать оператор if либо вы должны сохранить возвращаемое значение в дополнительной логической переменной, чтобы вы могли выполнить проверку позже. И вы не можете просто использовать целевую переменную, не зная, было ли преобразование успешным или нет.

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

Метод расширения, который я написал, делает именно это (он также показывает, какой код вам придется писать каждый раз, если вы не собираетесь его использовать).

Я считаю, что преимущество .ToDate(strDateFormat) состоит в том, что он выглядит простым и .ToDate(strDateFormat) - таким же простым, как предполагалось в оригинальном DateTime.Parse - но с возможностью проверки успешности преобразования и без исключения.


1) Здесь подразумевается обработка исключений (т. try {... } catch(Exception ex) {...} Блок try {... } catch(Exception ex) {...}), который необходим при использовании Parse, потому что он выдаст исключение, если недопустимый Анализ строки - это не только не нужно в этом случае, но и раздражает, и усложняет ваш код. TryParse избегает всего этого, поскольку пример кода, который я предоставил, показывает.


2) Эрик Липперт - известный сотрудник StackOverflow, пару лет проработавший в Microsoft в качестве основного разработчика в команде компилятора С#.

Ответ 3

var dateStr = @"2011-03-21 13:26";
var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm", CultureInfo.CurrentCulture);

Проверьте эту ссылку для других строк формата!

Ответ 5

Поместите значение удобочитаемой строки в .NET DateTime с таким кодом:

DateTime.ParseExact("April 16, 2011 4:27 pm", "MMMM d, yyyy h:mm tt", null);

Ответ 6

Вы также можете использовать XmlConvert.ToDateString

var dateStr = "2011-03-21 13:26";
var parsedDate = XmlConvert.ToDateTime(dateStr, "yyyy-MM-dd hh:mm");

Хорошо указать тип даты, код:

var anotherParsedDate = DateTime.ParseExact(dateStr, "yyyy-MM-dd hh:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);

Подробнее о различных параметрах разбора. Http://amir-shenodua.blogspot.ie/2017/06/datetime-parsing-in-net.html.

Ответ 7

Простой и понятный ответ ->

using System;

namespace DemoApp.App

{
public class TestClassDate
{
    public static DateTime GetDate(string string_date)
    {
        DateTime dateValue;
        if (DateTime.TryParse(string_date, out dateValue))
            Console.WriteLine("Converted '{0}' to {1}.", string_date, dateValue);
        else
            Console.WriteLine("Unable to convert '{0}' to a date.", string_date);
        return dateValue;
    }
    public static void Main()
    {
        string inString = "05/01/2009 06:32:00";
        GetDate(inString);
    }
}
}

/**
 * Output:
 * Converted '05/01/2009 06:32:00' to 5/1/2009 6:32:00 AM.
 * */

Ответ 8

Попробуйте следующий код

Month = Date = DateTime.Now.Month.ToString();   
Year = DateTime.Now.Year.ToString(); 
ViewBag.Today = System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(Int32.Parse(Month)) + Year;