2010-07-28 3 views
2

Consultez le code suivant:Comment supprimer DateTime.Parse dépendance à l'égard System.Threading.Thread.CurrentThread.CurrentCulture

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fo-FO"); 
      var s = DateTime.MaxValue.ToString("yyyy-MM-ddTHH:mm:ssZ"); 
      var d = DateTime.Parse(s, CultureInfo.InvariantCulture); 
      Console.WriteLine("Was able to parse with fo-FO"); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Exception: {0}", e); 
     } 

     try 
     { 
      System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); 
      var s = DateTime.MaxValue.ToString("yyyy-MM-ddTHH:mm:ssZ"); 
      var d = DateTime.Parse(s, CultureInfo.InvariantCulture); 
      Console.WriteLine("Was able to parse with en-US"); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Exception: {0}", e); 
     } 
    } 
} 

La sortie est:

Exception: System.FormatException: String was not recognized as a valid DateTime. 
    at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles) 
    at System.DateTime.Parse(String s, IFormatProvider provider) 
    at DateTimeTest2.Program.Main(String[] args) in C:\Projects\DateTimeTest2\DateTimeTest2\Program.cs:line 17 
Was able to parse with en-US 

Ce fragment de code prouve que DateTime. Parse utilise Thread.CurrentThread.CurrentCulture sans tenir compte du fait que la "InvariantCulture" est passée. Je trouve cela si peu intuitif que je le considère comme un "bug". Pourquoi devons-nous passer dans un CultureInfo si en fait il est ignoré par DateTime.Parse dans tous les cas? Y at-il un moyen d'appeler DateTime.Parse d'une manière qui est indépendante de la CurrentCulture?

+0

Vous appelez 'DateTime.MaxValue.ToString' sans culture - êtes-vous Assurez-vous que cette chaîne est correctement formatée? (Je ne sais pas comment fo-FO met en forme ses chaînes de date ...) –

+0

J'ai une exception dans les deux cas. Quel cadre de version avez-vous utilisé? –

+1

@Adam Qu'est-ce qui fonctionne: la culture invariante peut analyser une chaîne produite par en-US. Cependant, la culture invariante ne peut pas analyser une chaîne produite par fo-FO. –

Répondre

9

Ce fragment de code prouve que DateTime.Parse utilise Thread.CurrentThread.CurrentCulture indépendamment du fait que le « InvariantCulture » est passé dans

Je ne sais pas comment cet exemple prouve que. Les chaînes passées à DateTime.Parse sont différentes, donc il n'est pas complètement surprenant que des résultats différents s'ensuivent.

La première chaîne a l'heure au format 23.59.59, qui (apparemment) InvariantCulture ne peut pas analyser; la deuxième chaîne a l'heure formatée comme 23:59:59, que InvariantCulturepeut analyser. Quel est le problème?

modifier ajouter, puisque apparemment il fait une différence, je suis en cours d'exécution avec .NET 2.0 et les chaînes produites par fo-FO et en-US sont respectivement

9999-12-31T23.59.59Z 

et

9999-12-31T23:59:59Z 
+0

+1 bonne place, je pense qu'au départ, on supposait que les deux chaînes étaient les mêmes. Je n'ai pas remarqué cela jusqu'à ce que je lise votre réponse. –

0

deux analyse l'utilisation InvariantCulture, qui est en fait une référence codée en dur à la culture «en-US» (il peut y avoir des cas où le InvariantCulture n'est pas «en-US» mais ne viennent pas à travers eux).

Remplacez votre utilisation de InvariantCulture par new CultureInfo("en-US") et il deviendra évident pourquoi la première analyse ne fonctionne pas.

+0

En fait, les deux ne sont pas les mêmes. Voir http://stackoverflow.com/questions/2329297/net-are-there-any-differences-between-invariantculture-and-en-us –

+0

Ah, merci. C'est utile. –

1

de MSDN:

La culture est invariant insensible culture. Votre application spécifie la culture invariante par le nom en utilisant une chaîne vide ("") ou par son identifiant de langue. InvariantCulture récupère une instance de la culture invariante. C'est associé à la langue anglaise mais pas avec n'importe quel pays/région.

Je n'ai trouvé aucune référence à l'utilisation de la culture du thread actuel, car cela serait contre-intuitif comme vous l'avez dit.

Vous pouvez (en solution de contournement) mettre en cache la culture du thread en cours, la définir sur une culture connue (en-US), effectuer votre analyse, puis redéfinir la culture du thread sur l'ancienne valeur.

CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture; 
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); 
var s = DateTime.MaxValue.ToString("yyyy-MM-ddTHH:mm:ssZ"); 
var d = DateTime.Parse(s, CultureInfo.InvariantCulture); 
System.Threading.Thread.CurrentThread.CurrentCulture = ci; 

Cela garantira que vous savez ce que la culture est utilisée pour analyser la chaîne DateTime et n'affectera pas le code appelant à l'extérieur parce que la culture ne change jamais d'un point de vue extérieur.

0

En plus de ce AakashM a écrit:

Je l'ai essayée en cours d'exécution dans .NET 3.5 SP1. Dans le second cas, j'obtiens une exception System.FormatException indiquant que la valeur du DateTime est hors limites.

1

Si vous ne voulez pas respecter les fuseaux horaires dans l'analyse syntaxique, vous pouvez utiliser

var d = DateTime.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); 

ou

var d = DateTime.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal); 
Questions connexes