web-dev-qa-db-fra.com

Analyser la chaîne à DateTime en C #

J'ai date et heure dans une chaîne formatée comme celle-là:

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

Comment puis-je l'analyser en System.DateTime?

Je souhaite utiliser des fonctions telles que DateTime.Parse() ou DateTime.ParseExact() si possible, afin de pouvoir spécifier le format de la date manuellement.

133
Hooch

DateTime.Parse() essaiera de déterminer le format de la date donnée, et il fait généralement du bon travail. Si vous pouvez garantir que les dates seront toujours dans un format donné, vous pouvez utiliser ParseExact():

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

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

(Notez toutefois qu'il est généralement plus prudent d'utiliser l'une des méthodes TryParse au cas où une date ne serait pas au format attendu.)

Assurez-vous de vérifier Chaînes de format de date et heure personnalisées lors de la construction de chaîne de format, faites particulièrement attention au nombre de lettres et de casse (c.-à-d. "MM" et "mm" signifient des choses très différentes).

Une autre ressource utile pour les chaînes de format C # est Formatage des chaînes en C #

221
Mitch Wheat

Comme je l'expliquerai plus tard, je privilégierais toujours les méthodes TryParse et TryParseExact. Parce qu'ils sont un peu encombrants à utiliser, j'ai écrit une méthode d'extension qui facilite grandement l'analyse syntaxique:

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

Contrairement à Parse, ParseExact etc., il ne lève pas d'exception et vous permet de vérifier via

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

si la conversion a réussi (dans ce cas, dt a une valeur à laquelle vous pouvez accéder via dt.Value) ou non (dans ce cas, il s'agit de null).

Cela permet même d’utiliser des raccourcis élégants comme l’opérateur "Elvis" ?., par exemple:

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

Ici, vous pouvez également utiliser year.HasValue pour vérifier si la conversion a réussi et si elle n'a pas réussi, alors year contiendra null, sinon la partie année de la date. Il n'y a pas d'exception levée si la conversion a échoué.


Solution: La méthode d'extension .ToDate ()

essayez-le dans .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;
    }
}

Quelques informations sur le code

Vous vous demandez peut-être pourquoi j'ai utilisé InvariantCulture en appelant TryParseExact: Ceci oblige la fonction à traiter les modèles de format toujours de la même manière (sinon, par exemple, "." Pourrait être interprété comme séparateur décimal en anglais pendant que c'est un séparateur de groupe ou un séparateur de date en allemand. Rappelons que nous avons déjà interrogé quelques lignes auparavant sur les chaînes de format basées sur la culture, alors tout va bien ici.

Mise à jour: .ToDate() (sans paramètre) utilise désormais tous les modèles de date/heure courants de la culture actuelle du thread.
Notez que nous avons besoin de result et dt ensemble, car TryParseExact ne permet pas d'utiliser DateTime?, que nous avons l'intention de renvoyer. Dans C # Version 7 vous pouvez simplifier la fonction ToDate un peu comme suit:

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

ou, si vous l'aimez encore plus court:

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

dans ce cas, vous n'avez pas besoin des deux déclarations DateTime? result = null; et DateTime dt; - vous pouvez le faire en une seule ligne de code. (Il serait également permis d'écrire out DateTime dt au lieu de out var dt si vous préférez cela).

J'ai simplifié davantage le code en utilisant le mot clé params: vous n'avez plus besoin du 2dakota du Nord méthode surchargée plus.


Exemple d'utilisation

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

Comme vous pouvez le constater, cet exemple interroge simplement dt.HasValue pour voir si la conversion a réussi ou non. En bonus supplémentaire, TryParseExact permet de spécifier strict DateTimeStyles pour que vous sachiez exactement si une chaîne de date/heure appropriée a été transmise ou non.


Plusieurs exemples d'utilisation

La fonction surchargée vous permet de transmettre un tableau de formats valides utilisés pour analyser/convertir les dates comme indiqué ici (TryParseExact le supporte directement), par exemple.

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

Si vous n'avez que quelques modèles, vous pouvez aussi écrire:

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

Exemples avancés

Vous pouvez utiliser l'opérateur ?? pour utiliser par défaut un format de sécurité, par exemple.

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

Dans ce cas, la .ToDate() utiliserait les formats de date de culture locaux communs, et si tout cela échouait, elle essaierait d'utiliser le norme ISO format "yyyy-MM-dd HH:mm:ss" comme solution de secours. De cette façon, la fonction d’extension permet de "chaîner" facilement différents formats de secours.

Vous pouvez même utiliser l'extension dans LINQ, essayez ceci (c'est dans le .NetFiddle ci-dessus):

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

qui convertira les dates du tableau à la volée en utilisant les modèles et les affichera dans la console.


Quelques informations sur TryParseExact

Enfin, voici quelques commentaires sur l’arrière-plan (c’est-à-dire la raison pour laquelle je l’ai écrit de cette façon):

Je préfère TryParseExact dans cette méthode d'extension, car vous évitez la gestion des exceptions - vous pouvez lisez dans l'article d'Eric Lippert sur les exceptions pourquoi vous devriez utiliser TryParse plutôt que Parse, je le cite à ce sujet:2)

Cette décision de conception malheureuse 1) [annotation: laisser la méthode Parse générer une exception] était tellement frustrant que bien sûr l'équipe des cadres a implémenté TryParse peu de temps après , ce qui est bien.

C’est le cas, mais TryParse et TryParseExact sont encore beaucoup moins confortables à utiliser: ils vous obligent à utiliser une variable non initialisée en tant que paramètre out qui ne doit pas être nullable et tant que vous le souhaitez. Vous devez convertir la valeur de retour booléenne - vous devez utiliser immédiatement une instruction if ou stocker la valeur de retour dans une variable booléenne supplémentaire afin de pouvoir effectuer la vérification ultérieurement. Et vous ne pouvez pas simplement utiliser la variable cible sans savoir si la conversion a réussi ou non.

Dans la plupart des cas, vous voulez simplement savoir si la conversion a réussi ou non (et bien sûr la valeur si elle a réussi) , donc un Une variable cible nullable qui conserve toutes les informations serait souhaitable et beaucoup plus élégante, car toute l’information n’est stockée qu’à un seul endroit: c’est cohérent et facile à utiliser, et beaucoup moins sujet aux erreurs .

La méthode d’extension que j’ai écrite fait exactement cela (elle vous indique également quel type de code vous auriez à écrire à chaque fois si vous n’allez pas l’utiliser).

Je pense que l'avantage de .ToDate(strDateFormat) est qu'il a l'air simple et propre - aussi simple que l'original DateTime.Parse était supposé l'être - mais avec la possibilité de vérifier si la conversion a réussi et sans lever d'exceptions.


1) Ce que l’on entend ici est que la gestion des exceptions (c’est-à-dire un bloc try { ... } catch(Exception ex) { ...}) - nécessaire lorsque vous utilisez Parse car il lève une exception si un chaîne invalide est analysée - est non seulement inutile dans ce cas, mais également ennuyeux et complique votre code. TryParse évite tout cela, comme le montre l'exemple de code que j'ai fourni.


2) Eric Lippert est un célèbre membre de StackOverflow et travaillait chez Microsoft en tant que développeur principal de l’équipe du compilateur C # pendant quelques années.

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

Découvrez ce lien link pour les autres chaînes de format!

13
Rob

DateTime.Parse () devrait fonctionner correctement pour ce format de chaîne. Référence:

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

Lance-t-il une exception FormatException pour vous?

5
cacois

Mettez la valeur d'une chaîne lisible par l'homme dans un .NET DateTime avec un code comme celui-ci:

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

Vous pouvez également utiliser XmlConvert.ToDateString

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

Il est bon de spécifier le type de date, le code est:

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

Plus de détails sur les différentes options d'analyse http://amir-shenodua.blogspot.fr 2017/06/datetime-parsing-in-net.html

2
Amir Shenouda

La réponse simple et directe ->

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

Essayez le code suivant 

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