Разобрать строку в DateTime в C # - PullRequest
141 голосов
/ 20 марта 2011

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

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

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

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

Ответы [ 8 ]

235 голосов
/ 20 марта 2011

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

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

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

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

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

Еще один полезный ресурс для строк формата C # - Форматирование строк в C #

38 голосов
/ 27 августа 2013

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

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

В отличие от Parse, ParseExact и т. Д. Он не выбрасываетисключение и позволяет вам проверить через

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

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

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

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

Здесь вы можететакже используйте 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?, который мы намерены вернуть.В C # версии 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 dt; - вы можете сделать это в одной строке кода.(Также было бы разрешено писать out DateTime dt вместо out var dt, если вы предпочитаете это.)

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


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

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вместо того, чтобы разобрать, я цитирую его по этой теме: 2)

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

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

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

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

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


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


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

13 голосов
/ 20 марта 2011
var dateStr = @"2011-03-21 13:26";
var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm", CultureInfo.CurrentCulture);

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

5 голосов
/ 20 марта 2011

DateTime.Parse () должен нормально работать для этого формата строки. Справка:

http://msdn.microsoft.com/en-us/library/1k1skd40.aspx#Y1240

Это исключение FormatException для вас?

4 голосов
/ 30 апреля 2011

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

DateTime.ParseExact("April 16, 2011 4:27 pm", "MMMM d, yyyy h:mm tt", null);
2 голосов
/ 10 июля 2018

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

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.
 * */
2 голосов
/ 06 июня 2017

Вы также можете использовать 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-синтаксический-в-net.html

0 голосов
/ 24 января 2019

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

Month = Date = DateTime.Now.Month.ToString();   
Year = DateTime.Now.Year.ToString(); 
ViewBag.Today = System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(Int32.Parse(Month)) + Year;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...