Analysieren Sie die Zeichenfolge in C # auf DateTime

165

Ich habe Datum und Uhrzeit in einer Zeichenfolge, die so formatiert ist:

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

Wie kann ich es analysieren System.DateTime?

Ich möchte Funktionen wie DateTime.Parse()oder DateTime.ParseExact()wenn möglich verwenden, um das Format des Datums manuell festlegen zu können.

Fusel
quelle
19
Warum verwenden Sie DateTime.Parse nicht?
Austin Salonen
8
Ich war einer der Downvoter. Dies lag daran , dass Ihre ursprüngliche Frage ( stackoverflow.com/revisions/… ) besagte, dass Sie DateTime.Parse () verwenden wollten, aber nicht angegeben haben, WARUM Sie es nicht verwenden konnten. Dies ließ es wie eine Unsinnsfrage erscheinen, zumal eine einfache Überprüfung deutlich gemacht hätte, dass Cacois korrekt war: Ihre Zeichenfolge "2011-03-21 13:26" ist für DateTime.Parse () kein Problem. Schließlich haben Sie ParseExact () in Ihrer ursprünglichen Frage nicht erwähnt. Sie haben bis nach Mitch 'Antwort gewartet , um dies in einer Bearbeitung hinzuzufügen.
Anon
4
Ich liebe es einfach, wenn diese Leute ihre Frage ohne Angabe von Gründen ablehnen.
Hooch

Antworten:

271

DateTime.Parse()Ich werde versuchen, das Format des angegebenen Datums herauszufinden, und es macht normalerweise einen guten Job. Wenn Sie garantieren können, dass die Daten immer in einem bestimmten Format vorliegen, können Sie Folgendes verwenden ParseExact():

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

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

(Beachten Sie jedoch, dass es normalerweise sicherer ist, eine der TryParse-Methoden zu verwenden, wenn ein Datum nicht das erwartete Format hat.)

Stellen Sie sicher, dass Sie beim Erstellen von Formatzeichenfolgen die benutzerdefinierten Formatzeichenfolgen für Datum und Uhrzeit aktivieren , und achten Sie insbesondere auf die Anzahl der Buchstaben und Groß- / Kleinschreibung (dh "MM" und "mm" bedeuten sehr unterschiedliche Bedeutungen).

Eine weitere nützliche Ressource für Zeichenfolgen im C # -Format ist die Zeichenfolgenformatierung in C #

Mitch Wheat
quelle
5
Korrektur - es ist IMMER sicherer;) Wenn Sie eine Methode mit einer Ausnahme aufrufen, überprüfen Sie nach Möglichkeit immer zuerst die Ausnahmebedingung.
Gusdor
3
Ich würde sagen, es ist sicherer, Ihre Kultur immer weiterzugeben. Ich hätte lieber eine Ausnahme, als dass "01-02-2013" entweder als zweiter Januar oder als erster Februar falsch interpretiert wird.
Carra
1
@Carra: Daten im ISO8601-Format (dh JJJJ-MM-TT 'werden immer richtig interpretiert. Deshalb verwenden wir Daten im ISO8601-Format ...
Mitch Wheat
Parse genau kann nützlich sein. Manchmal würde ich es vorziehen, wenn meine Anwendung abstürzt und mein Computer brennt, anstatt eine falsche Ausgabe zu erzeugen. Kommt auf die Anwendung an.
Allen
ParseExact ist großartig, weil es flexibel ist, aber einen Nachteil hat: Beachten Sie, dass die Methoden ParseExact und Parse Ausnahmen auslösen, wenn im Datumsformat der Variablen ein Syntaxfehler vorliegt s. Daher ist es besser, TryParseExcact zu verwenden . Ich habe in meiner Antwort unten darauf hingewiesen, warum.
Matt
47

Wie ich später erläutere, würde ich immer die TryParseund TryParseExactMethoden bevorzugen . Da die Verwendung etwas umfangreich ist , habe ich eine Erweiterungsmethode geschrieben, die das Parsen erheblich vereinfacht:

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

Im Gegensatz zu Parse, ParseExactusw. wirft es keine Ausnahme, und ermöglicht es Ihnen , über zu überprüfen

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

ob die Konvertierung erfolgreich war (in diesem Fall dthat sie einen Wert, über den Sie zugreifen können dt.Value) oder nicht (in diesem Fall ist dies der Fall null).

Damit können sogar elegante Verknüpfungen wie der "Elvis" -Operator verwendet werden ?., zum Beispiel:

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

Hier können Sie auch year.HasValueüberprüfen, ob die Konvertierung erfolgreich war, und wenn sie nicht erfolgreich war year, enthält sie nullden Jahresanteil des Datums. Es wird keine Ausnahme ausgelöst, wenn die Konvertierung fehlgeschlagen ist.


Lösung:   Die Erweiterungsmethode .ToDate ()

Probieren Sie es in .NetFiddle aus

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;
    }
}

Einige Informationen zum Code

Sie fragen sich vielleicht, warum ich den InvariantCultureAufruf verwendet habe TryParseExact: Dies dient dazu, die Funktion zu zwingen, Formatmuster immer gleich zu behandeln (andernfalls könnte beispielsweise "." Auf Englisch als Dezimaltrennzeichen interpretiert werden, während es sich um ein Gruppentrennzeichen oder ein Datumstrennzeichen handelt Deutsche). Denken Sie daran, dass wir die kulturbasierten Formatzeichenfolgen bereits einige Zeilen zuvor abgefragt haben, sodass dies hier in Ordnung ist.

Update: .ToDate() (ohne Parameter) Standardmäßig werden jetzt alle gängigen Datums- / Zeitmuster der aktuellen Kultur des Threads verwendet.
Beachten Sie, dass wir das resultund dtzusammen benötigen , da TryParseExactes nicht erlaubt, es zu verwenden DateTime?, was wir zurückgeben möchten. In C # Version 7 können Sie die ToDateFunktion wie folgt vereinfachen :

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

oder, wenn Sie es noch kürzer mögen:

 // 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?;

in dem Fall , dass Sie die beiden Erklärungen nicht brauchen DateTime? result = null;und DateTime dt;überhaupt - Sie kann es in einer Zeile Code tun. (Es wäre auch erlaubt zu schreiben out DateTime dtanstatt out var dtwenn Sie das bevorzugen).

Ich habe den Code weiter unter Verwendung des vereinfachten paramsStichwort: Jetzt haben Sie nicht die 2 brauchen nd überladene Methode nicht mehr.


Anwendungsbeispiel

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!");
}

Wie Sie sehen können, wird in diesem Beispiel nur abgefragt dt.HasValue, ob die Konvertierung erfolgreich war oder nicht. Als zusätzlichen Bonus können Sie mit TryParseExact streng festlegen, DateTimeStylesdamit Sie genau wissen, ob eine richtige Datums- / Zeitzeichenfolge übergeben wurde oder nicht.


Weitere Anwendungsbeispiele

Mit der überladenen Funktion können Sie ein Array gültiger Formate übergeben, die zum Parsen / Konvertieren von Daten verwendet werden, wie hier gezeigt ( TryParseExactunterstützt dies direkt), z

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);

Wenn Sie nur wenige Vorlagenmuster haben, können Sie auch schreiben:

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

Fortgeschrittene Beispiele

Sie können den ??Operator verwenden, um standardmäßig ein ausfallsicheres Format zu verwenden, z

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

In diesem Fall wird die .ToDate()würde gemeinsame lokale Kultur Datumsformate verwenden, und wenn alle diese versagen, würde es versuchen , das zu verwenden , ISO - Standard - Format "yyyy-MM-dd HH:mm:ss"als Ausweich. Auf diese Weise ermöglicht die Erweiterungsfunktion das einfache "Verketten" verschiedener Fallback-Formate.

Sie können die Erweiterung sogar in LINQ verwenden. Probieren Sie dies aus (oben in der .NetFiddle):

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

Dadurch werden die Daten im Array im laufenden Betrieb mithilfe der Muster konvertiert und an die Konsole ausgegeben.


Hintergrundinformationen zu TryParseExact

Zum Schluss hier einige Kommentare zum Hintergrund (dh der Grund, warum ich es so geschrieben habe):

Ich bevorzuge TryParseExact in dieser Erweiterungsmethode, weil Sie die Ausnahmebehandlung vermeiden. Sie können in Eric Lipperts Artikel über Ausnahmen lesen, warum Sie TryParse anstelle von Parse verwenden sollten. Ich zitiere ihn zu diesem Thema: 2)

Diese unglückliche Entwurfsentscheidung 1) [Anmerkung: die Parse-Methode eine Ausnahme auslösen zu lassen] war so ärgerlich, dass das Framework-Team natürlich kurz danach TryParse implementierte, was das Richtige tut.

Er tut, aber , TryParseund TryParseExactbeide sind immer noch viel weniger als komfortabel zu bedienen: Sie zwingen Sie eine nicht initialisierte Variable als verwenden outParameter , die keine Nullwerte enthalten sein müssen , und während Sie konvertieren Sie die boolean Rückgabewert bewerten müssen - entweder Sie haben Um eine ifAnweisung sofort zu verwenden, müssen Sie den Rückgabewert in einer zusätzlichen booleschen Variablen speichern, damit Sie die Prüfung später durchführen können. Und Sie können die Zielvariable nicht einfach verwenden, ohne zu wissen, ob die Konvertierung erfolgreich war oder nicht.

In den meisten Fällen möchten Sie nur wissen, ob die Konvertierung erfolgreich war oder nicht (und natürlich den Wert, wenn sie erfolgreich war) . Daher wäre eine nullfähige Zielvariable, die alle Informationen enthält, wünschenswert und viel eleganter - da die gesamte Information ist nur an einem Ort gespeichert: Das ist konsistent und einfach zu bedienen und viel weniger fehleranfällig.

Die Erweiterungsmethode, die ich geschrieben habe, macht genau das (sie zeigt Ihnen auch, welche Art von Code Sie jedes Mal schreiben müssten, wenn Sie ihn nicht verwenden würden).

Ich glaube, der Vorteil von .ToDate(strDateFormat)ist, dass es einfach und sauber aussieht - so einfach wie das Original DateTime.Parsesein sollte -, aber mit der Fähigkeit zu überprüfen, ob die Konvertierung erfolgreich war, und ohne Ausnahmen zu werfen.


1) Damit ist gemeint, dass die Ausnahmebehandlung (dh ein try { ... } catch(Exception ex) { ...}Block) - die erforderlich ist, wenn Sie Parse verwenden, weil sie eine Ausnahme auslöst, wenn eine ungültige Zeichenfolge analysiert wird - in diesem Fall nicht nur unnötig, sondern auch ärgerlich ist Ihren Code komplizieren. TryParse vermeidet dies alles, wie das von mir bereitgestellte Codebeispiel zeigt.


2) Eric Lippert ist ein berühmter StackOverflow-Mitarbeiter und arbeitete einige Jahre bei Microsoft als Hauptentwickler im C # -Compilerteam.

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

Schauen Sie sich diesen Link für andere Formatzeichenfolgen an!

Rob
quelle
4

Fügen Sie den Wert einer für Menschen lesbaren Zeichenfolge mit folgendem Code in eine .NET DateTime ein:

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

Die einfache und unkomplizierte Antwort ->

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.
 * */
Shivam Bharadwaj
quelle
Nizza @ Shivam Bharadwaj, ich habe es genauso gemacht
Muhammad Irfan
2

Sie können auch XmlConvert.ToDateString verwenden

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

Es ist gut, die Datumsart anzugeben. Der Code lautet:

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

Weitere Details zu verschiedenen Parsing-Optionen http://amir-shenodua.blogspot.ie/2017/06/datetime-parsing-in-net.html

Amir Shenouda
quelle
0

Versuchen Sie den folgenden Code

Month = Date = DateTime.Now.Month.ToString();   
Year = DateTime.Now.Year.ToString(); 
ViewBag.Today = System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(Int32.Parse(Month)) + Year;
Adil Ayoub
quelle
Hallo, willkommen, bitte geben Sie eine Erklärung, wenn Sie eine Frage beantworten. Nur Postleitzahl wird nicht empfohlen
Ali