it-swarm.com.ru

Разобрать строку в DateTime в C #

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

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

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

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

140
Hooch

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 #

233
Mitch Wheat

Как я объясню позже, я всегда предпочел бы методы 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).

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

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: теперь вам не нужной перегруженный метод больше.


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

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, и во время преобразования вам необходимо оценить возвращаемое логическое значение - либо вы должны немедленно использовать ifstatement, либо вы должны сохранить возвращаемое значение в дополнительной логической переменной, чтобы вы могли выполнить проверку позже. И вы не можете просто использовать целевую переменную, не зная, было ли преобразование успешным или нет.

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

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

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


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


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

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

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

13
Rob

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

http://msdn.Microsoft.com/en-us/library/1k1skd40.aspx#Y124

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

5
cacois

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

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

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

2
Amir Shenouda

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

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
Shivam Bharadwaj

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

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