如何Convert.ToDateTime()解析给定的字符串时,给定的文化并不知道格式 [英] How Convert.ToDateTime() parses a given string when the given culture does not know the format

查看:208
本文介绍了如何Convert.ToDateTime()解析给定的字符串时,给定的文化并不知道格式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下的code,和它的作品。

I have the following code, and it works.

string testDateStr = "2009.7.28 05:23:15";
DateTime testDateObj = Convert.ToDateTime(testDateStr, CultureInfo.GetCultureInfo("fr-FR"));

和我查了有效的格式,我的文化:

And I checked the valid formats for my culture:

string[] validFormats = testDateObj.GetDateTimeFormats(CultureInfo.GetCultureInfo("fr-FR"));

和他们都不符合2009年7月28日五点23分15秒的格式。我想知道这是如何解析的,没有抛出一个格式异常,而当我们调用Convert.ToDateTime什么样的隐藏解析完成()。

And none of them matches the "2009.7.28 05:23:15" format. I want to know how this is parsed without throwing a format exception, and what kind of hidden parsing is done when we call the Convert.ToDateTime().

更新: 我试过后LakshmiNarayanan的回答如下。

Update: I tried the following after LakshmiNarayanan's answer.

foreach(var culture in CultureInfo.GetCultures(CultureTypes.AllCultures))
{
    foreach(var format in testDateObj.GetDateTimeFormats(culture))
    {
        if (format == testDateStr)
        {
            Console.WriteLine(culture.DisplayName);
        }
    }
}

有培养实际上包含格式我的字符串是,但它仍然无法解释为什么它的时候,我们要求它使用一个特定的文化转换不会抛出异常,而这种文化不知道的格式字符串研究。

There are cultures which actually contain the format my string is in, but still it fails to explain why it does not throw an exception when we ask it to convert using a specific culture while that culture does not know the format the string is in.

推荐答案

Convert.ToDateTime 方法在内部使用 DateTime.Parse 方法,它是基于内部精密莱克斯方法。有适用于通过串一串规则。它被分成令牌,每个令牌进行分析。该分析是非常复杂的,我将只显示两个规则。

The Convert.ToDateTime method internally uses DateTime.Parse method, which is based on internal sophisticated Lex method. There is a bunch of rules applied to passed string. It is split into tokens and each token is analyzed. The analysis is really complex and I'm going to show only couple of rules.

如果令牌是由数字和长度为3〜8,那么这个令牌将是这一年中,这就是为什么它能够解析 01.2014.01 字符串,这将产生 2014年1月1日的结果。请注意,您也可以解析如 01 2014年01 01 \ n2014 \ N01 赋予相同的结果字符串。你可以单独使用空格标记或符号。

If token is composed of digits and has length 3~8, then this token is going to be the year, that's why it is possible to parse 01.2014.01 string, which would produce 01 Jan 2014 result. Note that you can also parse strings like 01 2014 01 or 01\n2014\n01 giving the same result. You can separate tokens using whitespaces or , or . symbols.

如果令牌是该月的名称,那么它将会是这个月(表或标记是建立内部的 DateTimeFormatInfo.CreateTokenHashTable 法)。所以不要紧,你在哪里找到。您同样可以解析 2014年1月1日 2014.Jan.1 2014年...扬.. .. 1 甚至 5Jan2014 的字符串(最后一个不使用任何分隔符,但它会检查数量两端在哪里,所以它成功地分成 5 1 2014年标记)。

If token is the name of the month, then it is going to be the month (the table or tokens is built within internal DateTimeFormatInfo.CreateTokenHashTable method). So it doesn't matter where do you locate Feb or February. You can equally parse 2014 1 Jan or 2014.Jan.1, 2014...,Jan..,..1 or even 5Jan2014 string (the last one doesn't use any separator, but it checks where the number ends, so it is successfully split into 5, Jan and 2014 tokens).

如果我们有明确的字符串 01/04 ,然后从文化的信息是解决日/月秩序。顺序是从<一个提取href="http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.monthdaypattern.aspx"相对=nofollow> DateTimeFormatInfo.MonthDayPattern 。例如,的en-US MMMM DD ,以及 EN-GB DD MMMM 。有内部 System.DateTimeParse 私有静态布尔GetMonthDayOrder(字符串模式,的DateTimeFormatInfo dtfi,OUT INT顺序)方法,这是用于提取的顺序。如果变量取值 6 ,然后是 MM / DD ,如果花费值 7 ,然后是 DD / MM 。需要注意的是它的不会试着做一下一些启发1月31日,只为了从培养物中提取的考虑。这里是code测试:

If we have ambiguous string 01/04, then the information from culture is taken to resolve the order of day/month. The order is extracted from DateTimeFormatInfo.MonthDayPattern. For example, for en-US it is MMMM dd, and for en-GB it is dd MMMM. There is private static bool GetMonthDayOrder(string pattern, DateTimeFormatInfo dtfi, out int order) method in internal System.DateTimeParse class, which is used to extract the order. If the order variable takes value 6, then it is MM/dd, if it takes value 7, then it is dd/MM. Note that it will not try to do some heuristics about 01/31, only order extracted from culture is considered. Here is the code for test:

CultureInfo ci = CultureInfo.GetCultureInfo("en-US");

DateTimeFormatInfo dtfi = ci.DateTimeFormat;
Assembly coreAssembly = Assembly.ReflectionOnlyLoad("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
Type dateTimeParseType = coreAssembly.GetType("System.DateTimeParse");
MethodInfo getMonthDayOrderMethodInfo = dateTimeParseType.GetMethod("GetMonthDayOrder", BindingFlags.Static | BindingFlags.NonPublic);
object[] parameters = new object[] { dtfi.MonthDayPattern, dtfi, null };
getMonthDayOrderMethodInfo.Invoke(null, parameters);
int order = (int)parameters[2];
switch (order)
{
    case -1:
        Console.WriteLine("Cannot extract information");
        break;
    case 6:
        Console.WriteLine("MM/dd");
        break;
    case 7:
        Console.WriteLine("dd/MM");
        break;
}

和很多对AM / PM模式,星期,时间后缀(如韩国语的后缀认为,这意味着每小时)等检查,等等。

And a lot of other checks against AM/PM pattern, day of week, time suffix (for example for Korean language the suffix is considered, meaning hour), etc.

下面code会产生约​​文化的特定标记信息:

The following code would produce information about culture-specific tokens:

DateTimeFormatInfo dti = CultureInfo.InvariantCulture.DateTimeFormat;
dynamic hashes = dti.GetType().GetMethod("CreateTokenHashTable", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(dti, null);
var tokens = Enumerable.Repeat(new { str = "", type = "", value = "" }, 0).ToList();
foreach (dynamic hash in hashes)
    if (hash != null)
    {
        Type hashType = hash.GetType();
        tokens.Add(new { str = (string)hashType.GetField("tokenString", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(hash).ToString(),
                         type = (string)hashType.GetField("tokenType", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(hash).ToString(),
                         value = (string)hashType.GetField("tokenValue", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(hash).ToString() });
    }
foreach (var token in tokens.Distinct().OrderBy(t => t.type).ThenBy(t => t.value))
    Console.WriteLine("{0,10} {1} {2}", token.str, token.type, token.value);

有关 InvariantCulture的的输出是:

        AM 1027 0
        PM 1284 1
    Sunday DayOfWeekToken 0
       Sun DayOfWeekToken 0
    Monday DayOfWeekToken 1
       Mon DayOfWeekToken 1
   Tuesday DayOfWeekToken 2
       Tue DayOfWeekToken 2
 Wednesday DayOfWeekToken 3
       Wed DayOfWeekToken 3
       Thu DayOfWeekToken 4
  Thursday DayOfWeekToken 4
    Friday DayOfWeekToken 5
       Fri DayOfWeekToken 5
       Sat DayOfWeekToken 6
  Saturday DayOfWeekToken 6
        AD EraToken 1
      A.D. EraToken 1
         , IgnorableSymbol 0
         . IgnorableSymbol 0
   January MonthToken 1
       Jan MonthToken 1
   October MonthToken 10
       Oct MonthToken 10
  November MonthToken 11
       Nov MonthToken 11
  December MonthToken 12
       Dec MonthToken 12
  February MonthToken 2
       Feb MonthToken 2
     March MonthToken 3
       Mar MonthToken 3
       Apr MonthToken 4
     April MonthToken 4
       May MonthToken 5
      June MonthToken 6
       Jun MonthToken 6
       Jul MonthToken 7
      July MonthToken 7
       Aug MonthToken 8
    August MonthToken 8
 September MonthToken 9
       Sep MonthToken 9
         / SEP_Date 0
         - SEP_DateOrOffset 0
         日 SEP_DaySuff 0
         일 SEP_DaySuff 0
         时 SEP_HourSuff 0
         時 SEP_HourSuff 0
         T SEP_LocalTimeMark 0
         分 SEP_MinuteSuff 0
         月 SEP_MonthSuff 0
         월 SEP_MonthSuff 0
         秒 SEP_SecondSuff 0
         : SEP_Time 0
         년 SEP_YearSuff 0
         年 SEP_YearSuff 0
       GMT TimeZoneToken 0
         Z TimeZoneToken 0

有关 FR-FR 文化(注意,七月被列入名单,以及其他标记 InvariantCulture的

For fr-FR culture (notice that July is included in the list as well as other tokens from InvariantCulture)

        AM 1027 0
        PM 1284 1
         h DateWordToken 0
  dimanche DayOfWeekToken 0
       Sun DayOfWeekToken 0
      dim. DayOfWeekToken 0
    Sunday DayOfWeekToken 0
     lundi DayOfWeekToken 1
    Monday DayOfWeekToken 1
      lun. DayOfWeekToken 1
       Mon DayOfWeekToken 1
   Tuesday DayOfWeekToken 2
       Tue DayOfWeekToken 2
     mardi DayOfWeekToken 2
      mar. DayOfWeekToken 2
  mercredi DayOfWeekToken 3
 Wednesday DayOfWeekToken 3
      mer. DayOfWeekToken 3
       Wed DayOfWeekToken 3
     jeudi DayOfWeekToken 4
  Thursday DayOfWeekToken 4
       Thu DayOfWeekToken 4
      jeu. DayOfWeekToken 4
      ven. DayOfWeekToken 5
  vendredi DayOfWeekToken 5
    Friday DayOfWeekToken 5
       Fri DayOfWeekToken 5
    samedi DayOfWeekToken 6
      sam. DayOfWeekToken 6
       Sat DayOfWeekToken 6
  Saturday DayOfWeekToken 6
 ap. J.-C. EraToken 1
         , IgnorableSymbol 0
         . IgnorableSymbol 0
   January MonthToken 1
     janv. MonthToken 1
   janvier MonthToken 1
       Jan MonthToken 1
      oct. MonthToken 10
       Oct MonthToken 10
   octobre MonthToken 10
   October MonthToken 10
      nov. MonthToken 11
       Nov MonthToken 11
  novembre MonthToken 11
  November MonthToken 11
      déc. MonthToken 12
  December MonthToken 12
       Dec MonthToken 12
  décembre MonthToken 12
     févr. MonthToken 2
   février MonthToken 2
  February MonthToken 2
       Feb MonthToken 2
      mars MonthToken 3
     March MonthToken 3
       Mar MonthToken 3
       Apr MonthToken 4
      avr. MonthToken 4
     avril MonthToken 4
     April MonthToken 4
       mai MonthToken 5
       May MonthToken 5
      June MonthToken 6
      juin MonthToken 6
       Jun MonthToken 6
      July MonthToken 7
     juil. MonthToken 7
   juillet MonthToken 7
       Jul MonthToken 7
       Aug MonthToken 8
      août MonthToken 8
    August MonthToken 8
     sept. MonthToken 9
       Sep MonthToken 9
 septembre MonthToken 9
 September MonthToken 9
         / SEP_Date 0
         - SEP_DateOrOffset 0
         日 SEP_DaySuff 0
         일 SEP_DaySuff 0
         时 SEP_HourSuff 0
         時 SEP_HourSuff 0
         T SEP_LocalTimeMark 0
         分 SEP_MinuteSuff 0
         月 SEP_MonthSuff 0
         월 SEP_MonthSuff 0
         秒 SEP_SecondSuff 0
         : SEP_Time 0
         년 SEP_YearSuff 0
         年 SEP_YearSuff 0
       GMT TimeZoneToken 0
         Z TimeZoneToken 0

这篇关于如何Convert.ToDateTime()解析给定的字符串时,给定的文化并不知道格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆