[.NET][C#]讓Datetime.TryParseExact看懂日期時間字串中的"上午"與"下午"

資料交換經常會碰到各種日期時間字串,今天來敲門的是"2016年10月5日 下午 10:06:23",他也是Windows中文繁體(台灣)內建的日期時間表示方式。來筆記快速又正確Parse時間字串方法。

 

 

由於輸入時間字串有"上午"/"下午",是那種行針鐘錶的12小時制的標記,因為不是航空公司、軍隊、金融業標準常用的ISO8601 24小時制格式,不能單純用DateTime.TryParse,這時候可以用TryParseExact指定格式來處理,關鍵字就是tt

什麼是tt

觀察Windows OS,電腦畫面右下角的日期時間格式

當我們月曆類型是西曆(中文)時:

日期格式: 

時間格式

tt是用來表示上午或下午的符號!

小寫h表示12小時制!大寫H表示24小時制!

好!知道怎麼描述時間格式了,來寫程式!

 

Parse日期時間字串中的"上午"與"下午"

1.撰寫兩段方法分別使用InvariantCultureCultureInfo("zh-TW")兩種文化特性Parse日期時間字串。

輸入參數是日期時間字串,用Tuple回傳是否轉換成功(Boolean)及轉換後日期(Datetime)

InvariantCulture
public Tuple<bool, DateTime> InvariantConvert(string sDt)
{
    DateTime dt = new DateTime(1900, 1, 1);
    string[] sDtPattern = new string[]{
                "yyyy年M月d日 上午 hh:mm:ss","yyyy年M月d日 下午 hh:mm:ss",
                "yyyy年M月d日 tt hh:mm:ss"
    };
    return Tuple.Create(DateTime.TryParseExact(sDt, sDtPattern, CultureInfo.InvariantCulture,
DateTimeStyles.AllowWhiteSpaces, out dt), dt);
}

 

CultureInfo("zh-TW"):  使用台灣文化特性,讓TryParseExact看的懂"年","月","日","上午","下午"這些時間元件
public Tuple<bool, DateTime> TwCultureConvert(string sDt)
{
    DateTime dt = new DateTime(1900, 1, 1);
    CultureInfo culTW = new CultureInfo("zh-TW", true);
    string[] sTwDtPattern = new string[] {
    "yyyy年M月d日 tt hh:mm:ss" };

    return Tuple.Create(DateTime.TryParseExact(sDt, sTwDtPattern, culTW, DateTimeStyles.AllowWhiteSpaces, out dt), dt);
}

 

2.撰寫測試程式

 依序用2016/10/5 上午 10:06:23及下午 10:06:23測試。

 [TestMethod]
 public void TestMethod1()
 {
     //Input Datetime string
     string sTWDateTimeAM = "2016年10月5日 上午 10:06:23";
     string sTWDateTimePM = "2016年10月5日 下午 10:06:23";

     //Expected Result
     DateTime TWDateTimeAM = new DateTime(2016, 10, 05, 10, 06, 23);
     DateTime TWDateTimePM = new DateTime(2016, 10, 05, 22, 06, 23);

     Console.WriteLine("InvariantConvert");

     var Result1 = InvariantConvert(sTWDateTimeAM);
     Console.WriteLine($"{Result1.Item1}/{Result1.Item2}");
     //Assert.AreEqual(TWDateTimeAM, Result1.Item2);

     var Result2 = InvariantConvert(sTWDateTimePM);
     Console.WriteLine($"{Result2.Item1}/{Result2.Item2}");
     //Assert.AreEqual(TWDateTimePM, Result2.Item2);

     Console.WriteLine("zh-TW Culture");

     var Result3 = TwCultureConvert(sTWDateTimeAM);
     Console.WriteLine($"{Result3.Item1}/{Result3.Item2}");
     //Assert.AreEqual(TWDateTimeAM, Result3.Item2);

     var Result4 = TwCultureConvert(sTWDateTimePM);
     Console.WriteLine($"{Result4.Item1}/{Result4.Item2}");
     //Assert.AreEqual(TWDateTimePM, Result4.Item2);
}

 

測試結果:

InvariantCulture: 雖然parse設定hh表示12小時,但因為InvariantCulture直接將"上下午"視為無意義的格式字串,當時間落在下午時,Parse後會失去原來時間的精準度
CultureInfo("zh-TW"): 台灣繁體中文的文化特性則可以精準的把"上午""下午"的時間都Parse出來

 

但如果把日期時間字串中的"上午/下午"改為"AM/PM" ?

再寫一段測試程式

[TestMethod]
public void TestMethod1()
{

    //Expected Result
    DateTime TWDateTimeAM = new DateTime(2016, 10, 05, 10, 06, 23);
    DateTime TWDateTimePM = new DateTime(2016, 10, 05, 22, 06, 23);

    Console.WriteLine("");
    string sDateTimeAM = "2016年10月5日 AM 10:06:23";
    string sDateTimePM = "2016年10月5日 PM 10:06:23";


    Console.WriteLine("InvariantConvert");

    var Result5 = InvariantConvert(sDateTimeAM);
    Console.WriteLine($"{Result5.Item1}/{Result5.Item2}");
    //Assert.AreEqual(TWDateTimeAM, Result5.Item2);

    var Result6 = InvariantConvert(sDateTimePM);
    Console.WriteLine($"{Result6.Item1}/{Result6.Item2}");
    //Assert.AreEqual(TWDateTimePM, Result6.Item2);

    Console.WriteLine("zh-TW Culture");

    var Result7 = TwCultureConvert(sDateTimeAM);
    Console.WriteLine($"{Result7.Item1}/{Result7.Item2}");
    //Assert.AreEqual(TWDateTimeAM, Result7.Item2);


    var Result8 = TwCultureConvert(sDateTimePM);
    Console.WriteLine($"{Result8.Item1}/{Result8.Item2}");
    //Assert.AreEqual(TWDateTimePM, Result8.Item2);
}

 

測試結果

1.InvariantCulture可以正確Parse出"AM/PM"。
2.CultureInfo("zh-TW"): 沒辦法Parse,不管AM/PM,日期時間轉換都失敗。

 

小結

  • 看到"上午"/"下午" 用CultureInfo("zh-TW")的tt解題
  • 看到"AM"/"PM" 用InvariantCulture的tt解題

 

參考:

CNS7648(中華民國國家標準,資料元件及交換格式-資訊交換-日期及時間表示法)

ISO8601

tt