我有以下代码,它有效。
string testDateStr = "2009.7.28 05:23:15";
DateTime testDateObj = Convert.ToDateTime(testDateStr, CultureInfo.GetCultureInfo("fr-FR"));
我检查了我的文化的有效格式:
string[] validFormats = testDateObj.GetDateTimeFormats(CultureInfo.GetCultureInfo("fr-FR"));
并且它们都不符合“2009.7.28 05:23:15”格式。我想知道如何在不抛出格式异常的情况下对其进行解析,以及在调用Convert.ToDateTime()时执行何种隐藏解析。
更新: 在LakshmiNarayanan的回答后我尝试了以下内容。
foreach(var culture in CultureInfo.GetCultures(CultureTypes.AllCultures))
{
foreach(var format in testDateObj.GetDateTimeFormats(culture))
{
if (format == testDateStr)
{
Console.WriteLine(culture.DisplayName);
}
}
}
有些文化实际上包含了我的字符串所在的格式,但仍然无法解释为什么当我们要求它使用特定文化进行转换时它不会引发异常,而该文化不知道字符串的格式是英寸
答案 0 :(得分:3)
Convert.ToDateTime
方法内部使用DateTime.Parse
方法,该方法基于内部复杂的Lex
方法。传递的字符串有一堆规则。它被分成令牌并分析每个令牌。分析非常复杂,我只会展示几条规则。
如果令牌由数字组成且长度为3~8,则此令牌将成为年份,这就是为什么可以解析01.2014.01
字符串,这将产生01 Jan 2014
结果。请注意,您还可以解析01 2014 01
或01\n2014\n01
等字符串,并给出相同的结果。您可以使用空格或,
或.
符号来分隔令牌。
如果token是月份的名称,则它将是月份(表或标记是在内部DateTimeFormatInfo.CreateTokenHashTable
方法中构建的)。因此,您找到Feb
或February
的位置并不重要。您可以同样解析2014 1 Jan
或2014.Jan.1
,2014...,Jan..,..1
甚至5Jan2014
字符串(最后一个不使用任何分隔符,但会检查数字结束的位置,因此它已成功分为5
,Jan
和2014
令牌。
如果我们有不明确的字符串01/04
,那么来自文化的信息将用于解决日/月的顺序。订单摘自DateTimeFormatInfo.MonthDayPattern。例如,对于en-US
,它是MMMM dd
,对于en-GB
,它是dd MMMM
。内部private static bool GetMonthDayOrder(string pattern, DateTimeFormatInfo dtfi, out int order)
类中有System.DateTimeParse
方法,用于提取订单。如果order
变量的值为6
,则为MM/dd
,如果值为7
,则为dd/MM
。请注意,不会尝试对01/31
进行一些启发式操作,只考虑从文化中提取的订单。以下是测试代码:
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模式的检查,星期几,时间后缀(例如韩语,시
后缀被认为是,意味着小时)等。
以下代码将生成有关特定于文化的标记的信息:
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
文化(请注意列表中包含July
以及来自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
答案 1 :(得分:1)
Datetime.GetDateTimeFormats()方法未按格式列出日期" 2009.7.28 05:23:15"这可能是因为默认的cultureInfo。
但是,如果您查看GetDateTimeFormats(IFormatProvider)方法的IFormatProvider重载,您可以看到对于culture" fr-FR",该方法能够成功解析日期"点"分隔符。例如28.07.09 5:23:15
因此,对于其工作原理的逻辑假设是,如果没有提供任何特定的文化,DateTime.Parse()会在所有可能的文化中运行字符串,并且只有在没有任何文化时才会返回异常。 ;字符串匹配。
编辑:
通过MSDN挖掘,Convert.ToDateTime(stringTime)正在使用当前文化的DateTimeFormatInfo进行解析。
如果value不为null,则返回值是调用的结果 使用a中的格式信息对值的DateTime.Parse方法 为当前区域性初始化的DateTimeFormatInfo对象。 value参数必须包含日期和时间的表示 以DateTimeFormatInfo主题中描述的格式之一。
因此,如果未设置特定区域性,DateTimeFormatInfo对象将引用默认构造函数。参考MSDN,
此构造函数创建一个表示的DateTimeFormatInfo对象 不变文化的日期和时间信息。创建一个 对于特定文化的DateTimeFormatInfo对象,创建CultureInfo 该文化的对象并检索DateTimeFormatInfo对象 由CultureInfo.DateTimeFormat属性返回。
当没有定义文化时,默认文化是默认的。因此,Convert.ToDateTime的默认字符串方法引用DateTimeFormatInfo的默认对象,该对象引用不变文化。这意味着Convert.ToDateTime必须解析所有文化中的所有验证。
因此,我们假设正在检查所有培养变体的验证是正确的。
希望它有所帮助。荣誉,一个非常有趣的观察。
答案 2 :(得分:0)
可能的方式
dateString = "05/01/1996";
ConvertToDateTime(dateString);
dateString = "Tue Apr 28, 2009";
ConvertToDateTime(dateString);
dateString = "Wed Apr 28, 2009";
ConvertToDateTime(dateString);
dateString = "06 July 2008 7:32:47 AM";
ConvertToDateTime(dateString);
dateString = "17:32:47.003";
ConvertToDateTime(dateString);
// Convert a string returned by DateTime.ToString("R").
dateString = "Sat, 10 May 2008 14:32:17 GMT";
ConvertToDateTime(dateString);
// Convert a string returned by DateTime.ToString("o").
dateString = "2009-05-01T07:54:59.9843750-04:00";
ConvertToDateTime(dateString);
int year=2009;
int month=7;
int day=28;
int hr=5;
int min=23;
int s=15;
DateTime testDateObj = Convert.ToDateTime(year, month, day, hr, min, s);
或只是
DateTime testDateObj = Convert.ToDateTime(2009, 7, 28, 5, 23, 15);
答案 3 :(得分:0)
尝试使用类DateTimeFormatInfo为您的文化提供信息abount datetime格式。
答案 4 :(得分:0)
更新: - 试试这个:
string testDateStr = "2009.7.28 05:23:15";
string testDateObj = Convert.ToDateTime(testDateStr).Date.ToString("d");
string[] validFormats = (Convert.ToDateTime(testDateObj)).GetDateTimeFormats();
foreach(string s in validFormats)
{
lblresult.Text += s;
}