我有一個非常類似的問題。 DateTime.Parse或DateTime.TryParse將假定一天中的時間爲00:00:00,此時該字符串不包含任何時間信息。正如年份假設一樣,沒有辦法指定一個不同的時間作爲默認值。這是一個真正的問題,因爲設置這些默認值的時間是,因此解析方法會經歷所有的詳細步驟。否則,你必須非常痛苦地重新發明輪子,以確定該字符串是否包含將覆蓋默認值的信息。
我看了一下日期時間的源代碼。TryParse,並且可以預料的是,微軟已經竭盡全力去擴展DateTime類。所以我編寫了一些使用反射的代碼來利用它可以從DateTime的源代碼中獲得的東西。這有一些顯著的缺點:
- 的使用反射代碼是尷尬
- 的使用反射代碼調用,如果.NET Framework是升級這可能會改變內部成員
- 反射,使用代碼將運行比一些不需要使用反射的假設替代方法慢
在我的情況下,我認爲沒有什麼比從頭開始重新創建DateTime.TryParse更尷尬了。我有單元測試,表明內部成員是否已經改變。我認爲對我而言,表現的懲罰是微不足道的。
我的代碼如下。此代碼用於覆蓋默認的小時/分鐘/秒,但我認爲可以輕鬆修改或擴展以覆蓋默認年份或其他內容。該代碼忠實地模仿內部System.DateTimeParse.TryParse之一的重載的內部代碼(它確實是DateTime.TryParse的實際工作),儘管我不得不使用尷尬的反射來做到這一點。唯一與System.DateTimeParse.TryParse有效不同的是它指定了一個默認的小時/分鐘/秒而不是將它們全部設置爲零。
以供參考,這是類DateTimeParse的,我模仿
internal static bool TryParse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result) {
result = DateTime.MinValue;
DateTimeResult resultData = new DateTimeResult(); // The buffer to store the parsing result.
resultData.Init();
if (TryParse(s, dtfi, styles, ref resultData)) {
result = resultData.parsedDate;
return true;
}
return false;
}
的方法在這裏是我的代碼
public static class TimeExtensions
{
private static Assembly _sysAssembly;
private static Type _dateTimeParseType, _dateTimeResultType;
private static MethodInfo _tryParseMethod, _dateTimeResultInitMethod;
private static FieldInfo _dateTimeResultParsedDateField,
_dateTimeResultHourField, _dateTimeResultMinuteField, _dateTimeResultSecondField;
/// <summary>
/// This private method initializes the private fields that store reflection information
/// that is used in this class. The method is designed so that it only needs to be called
/// one time.
/// </summary>
private static void InitializeReflection()
{
// Get a reference to the Assembly containing the 'System' namespace
_sysAssembly = typeof(DateTime).Assembly;
// Get non-public types of 'System' namespace
_dateTimeParseType = _sysAssembly.GetType("System.DateTimeParse");
_dateTimeResultType = _sysAssembly.GetType("System.DateTimeResult");
// Array of types for matching the proper overload of method System.DateTimeParse.TryParse
Type[] argTypes = new Type[]
{
typeof(String),
typeof(DateTimeFormatInfo),
typeof(DateTimeStyles),
_dateTimeResultType.MakeByRefType()
};
_tryParseMethod = _dateTimeParseType.GetMethod("TryParse",
BindingFlags.Static | BindingFlags.NonPublic, null, argTypes, null);
_dateTimeResultInitMethod = _dateTimeResultType.GetMethod("Init",
BindingFlags.Instance | BindingFlags.NonPublic);
_dateTimeResultParsedDateField = _dateTimeResultType.GetField("parsedDate",
BindingFlags.Instance | BindingFlags.NonPublic);
_dateTimeResultHourField = _dateTimeResultType.GetField("Hour",
BindingFlags.Instance | BindingFlags.NonPublic);
_dateTimeResultMinuteField = _dateTimeResultType.GetField("Minute",
BindingFlags.Instance | BindingFlags.NonPublic);
_dateTimeResultSecondField = _dateTimeResultType.GetField("Second",
BindingFlags.Instance | BindingFlags.NonPublic);
}
/// <summary>
/// This method converts the given string representation of a date and time to its DateTime
/// equivalent and returns true if the conversion succeeded or false if no conversion could be
/// done. The method is a close imitation of the System.DateTime.TryParse method, with the
/// exception that this method takes a parameter that allows the caller to specify what the time
/// value should be when the given string contains no time-of-day information. In contrast,
/// the method System.DateTime.TryParse will always apply a value of midnight (beginning of day)
/// when the given string contains no time-of-day information.
/// </summary>
/// <param name="s">the string that is to be converted to a DateTime</param>
/// <param name="result">the DateTime equivalent of the given string</param>
/// <param name="defaultTime">a DateTime object whose Hour, Minute, and Second values are used
/// as the default in the 'result' parameter. If the 's' parameter contains time-of-day
/// information, then it overrides the value of 'defaultTime'</param>
public static Boolean TryParse(String s, out DateTime result, DateTime defaultTime)
{
// Value of the result if no conversion can be done
result = DateTime.MinValue;
// Create the buffer that stores the parsed result
if (_sysAssembly == null) InitializeReflection();
dynamic resultData = Activator.CreateInstance(_dateTimeResultType);
_dateTimeResultInitMethod.Invoke(resultData, new Object[] { });
// Override the default time values of the buffer, using this method's parameter
_dateTimeResultHourField.SetValue(resultData, defaultTime.Hour);
_dateTimeResultMinuteField.SetValue(resultData, defaultTime.Minute);
_dateTimeResultSecondField.SetValue(resultData, defaultTime.Second);
// Create array parameters that can be passed (using reflection) to
// the non-public method DateTimeParse.TryParse, which does the real work
Object[] tryParseParams = new Object[]
{
s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, resultData
};
// Call non-public method DateTimeParse.TryParse
Boolean success = (Boolean)_tryParseMethod.Invoke(null, tryParseParams);
if (success)
{
// Because the DateTimeResult object was passed as a 'ref' parameter, we need to
// pull its new value out of the array of method parameters
result = _dateTimeResultParsedDateField.GetValue((dynamic)tryParseParams[3]);
return true;
}
return false;
}
}
- 編輯 - 後來我意識到,我需要爲方法DateTime.TryParseExact做同樣的事情。但是,上述方法對TryParseExact不起作用,這導致我擔心該方法比我想象的更脆弱。好吧。令人高興的是,我能夠想到的TryParseExact一個非常不同的方法不使用任何反射
public static Boolean TryParseExact(String s, String format, IFormatProvider provider,
DateTimeStyles style, out DateTime result, DateTime defaultTime)
{
// Determine whether the format requires that the time-of-day is in the string to be converted.
// We do this by creating two strings from the format, which have the same date but different
// time of day. If the two strings are equal, then clearly the format contains no time-of-day
// information.
Boolean willApplyDefaultTime = false;
DateTime testDate1 = new DateTime(2000, 1, 1, 2, 15, 15);
DateTime testDate2 = new DateTime(2000, 1, 1, 17, 47, 29);
String testString1 = testDate1.ToString(format);
String testString2 = testDate2.ToString(format);
if (testString1 == testString2)
willApplyDefaultTime = true;
// Let method DateTime.TryParseExact do all the hard work
Boolean success = DateTime.TryParseExact(s, format, provider, style, out result);
if (success && willApplyDefaultTime)
{
DateTime rawResult = result;
// If the format contains no time-of-day information, then apply the default from
// this method's parameter value.
result = new DateTime(rawResult.Year, rawResult.Month, rawResult.Day,
defaultTime.Hour, defaultTime.Minute, defaultTime.Second);
}
return success;
}
的,這是接近:http://stackoverflow.com/questions/2003088/using-datetime-tryparseexact-without-瞭解這一年的 – 2012-07-26 14:29:44
更多的信息也在這裏;不是很重複http://stackoverflow.com/questions/2024273/convert-a-two-digit-year-to-a-four-digit-year – 2017-02-08 18:28:30