String.Format yyyy/MM/dd? 誤會大了
10 | 61,283 |
今天才發現一件誤很大的事...
Console.WriteLine(string.Format("{0:yyyy/MM/dd}", DateTime.Today));
結果應該是什麼? 不就是2009/04/01嗎?
答案是不一定,也有可能是2009-04-01哦!
根據本草綱目MSDN Library記載,日期格式裡的"/"代表的並不是斜線符號,而是DateTimeFormatInfo.DataSeparator。
Represents the date separator defined in the current DateTimeFormatInfo.DateSeparator property. This separator is used to differentiate years, months, and days.
表示目前 DateTimeFormatInfo.DateSeparator 屬性中所定義的日期分隔符號。此分隔符號可用來分隔年、月和日。
換句話說,如果日期格式被設定為yyyy-MM-dd,則DateTimeFormatInfo.DataSeparator = "-",此時string.Format("{0:yyyy/MM/dd}", DateTime.Today)就會變成2009-04-01,而不是想像中的2009/04/01。
要如何解決? 請愛用Escape字符"\",寫成以下的格式就OK了。
Console.WriteLine(string.Format("{0:yyyy\\/MM\\/dd}", DateTime.Today));
Comments
# by eric
又更加的佩服Jeffrey ,有如滔滔江水......... 我們的程式之前RUN在簡體OS的環境,日期格式有時會莫明奇妙的變成 - ,一直都不求甚解,今天看了Jeffrey才知道....原來一直誤很大啊~~~
# by huang47
這是4/1騙人的嗎 @_@
# by Jason
不是很了解. 我認為, 若使用DateTimeFormatInfo.DateSeparator處理, 則表示想利用System.Globalization中的CultureInfo和DateTimeFormatInfo內的資訊,來為你自動處理日期格式問題; 而例子中, 您用的是自訂格式來指定輸出日期格式. 我認為, 假若您用的是自行指定日期輸出格式, 根本不需要考慮 "/" or "-", 愛用哪一個, Console.WriteLine時或反向把字串轉回DateTime時, 都不會發生錯誤. 反之, 您若也都利用CultureInfo中的定義,讓.NET自行去轉換, 也都不會發生問題. 問題是出在您把兩者混用. 其實這令我非常不解且沒有必要.
# by Jeffrey
to Jason, 我們還蠻常遇到二者混用的情境,最常見的狀況便是DateTime.ToString()與DateTime.ParseExact()不是在發生在同一台機器上。例如: 機器A用"/",將日期傳成字串傳給機器B,而機器B由User管理,分隔符號用"-",要將字串轉回日期就要留意。 還有一種更常見的情況是Client端由Server端收到日期字串(有可能Server歸第三者管理,日期格式由不得我們決定),要轉型回DateTime,如果純粹只是字串轉日期,有另一種做法是指定Culture,例如: DateTime.ParseExact("2009/04/01", "yyyy/MM/dd", System.Globalization.CultureInfo.InvariantCulture),這樣也可以避開User自訂日期格式的干擾。
# by tomexou
我的系統習慣使用yyyy-MM-dd,因此平時有注意到這現象,也大概知道原因,不過倒沒細查該如何解決。感謝jeffery提供solution。
# by Jason
剛好藉這機會仔細去翻了翻本草綱目. 確實發現了些以前沒注意到的東西, 我認為我應該有找到更深一層的原因. 當然, 您的解法確實是一條可行的路, 某些狀況下, 我應該也會採用, 不過我還是想提出一些我不一樣的想法. 首先先說一下這狀況發生的精確原因: 根據此 http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.dateseparator.aspx URL的Remark部分描述. (其實我是反覆實驗中先發現當自訂的格式字串中含有 '/' 時, 才會發生您所說的現象, 之後才去找到此說明) 我實驗出來的結果得到的推論是 (VS.NET 2008+Vista 英文版): 1. 自訂日期格式中若含有 '/', 當日期輸出為字串時, 會被DateTimeFormatInfo.DateSeparator 取代; 反之若自定格式使用 "yyyy-MM-dd", 而 DateSeparator 為 "/", 則不會被取代. 2. 而甚麼字元是DateSeparator, 則由 Region Option中的Short Date Format的分格字元所決定.(當然我發現似乎只有{'/', '-', '.'}三個字元可以做為分格字元, 試了好幾種"#$%!" 都沒法apply) 至於我原本說的 "混用" 這定義似乎也模糊, 當然我原本也誤解您的意思, 在此抱歉. 所以也就不再繼續在這兩字上做文章. 另外想提供個我覺得ok的方法, 雖然多寫點東西, 不過這類格式轉換, 通常該在utility function中定義, 所以覺得該是還算可接受的:(以下code,包含了我上述的#1, #2的實驗, 以及我覺得另一可行的做法.) DateTimeFormatInfo fmt = (new CultureInfo("zh-TW")).DateTimeFormat; fmt.DateSeparator = "$"; fmt.ShortDatePattern = "yyyy-MM-dd"; Console.WriteLine(dt.ToString("d", fmt)); fmt.ShortDatePattern = "yyyy/MM/dd"; Console.WriteLine(dt.ToString("d", fmt)); Console.WriteLine(string.Format(fmt, "{0:yyyy-MM-dd}", dt)); Console.WriteLine(string.Format(fmt, "{0:yyyy/MM/dd}", dt));
# by kikkoma
我慣用的方式是 DateTime.ToString("yyyy/MM/dd"); 所以一直以來都認為這是理所當然的 還沒用過string.Format來格式化日期物件呢 感謝提醒囉~
# by T@T
指定DateTimeFormatInfo.InvariantInfo 為Format的IFormatProvider 即可實現你format的指定的時間格式 不論在哪個國家都一樣, 相關可以查下MSDN
# by KK
最近將電腦時間改成yyyy-MM-dd的格式 在程式中寫DateTime.Now.ToString("yyyy/MM/dd") 出來確是yyyy-MM-dd的時間,而不是yyyy/MM/dd 原來如此是這樣 感謝,又學到一課。
# by Kalin
Jeffrey, "yyyy\\/MM\\/dd" 用於 string.Format("{0:yyyy\\/MM\\/dd}", DateTime.Today) 下確實可以產出 yyyy/MM/dd 的格式 可是改用 DateTime.ToString("yyyy\\/MM\\/dd") 反而會出現 "2010\\/06\\/14" 這種怪結果..