談談C#日期格式化和數字格式化的實現
字符串格式化這部分內容是我們經常用到的,如“2008-03-26”日期格式、“28.20”數字格式。
舉一個例子,我們有時需要將訂單號“12”顯示為“00000012”這種樣式(不足8位前面補0),就可以使用下面的方法:
- intoriginalCode=12;
- Response.Write(string.Format("{0:00000000}",originalCode));
或者
- intoriginalCode=12;
Response.Write(originalCode.ToString("00000000"))又如我們在使用日期做為某種關鍵字時,比如圖片的文件名,一般是到秒級,如“20080326082708”Response.Write(DateTime.Now.ToString("yyyyMMddHHmmss"));//輸出:20080326082708
這樣如果并發操作比較多的話,就會產生文件重名的現象。我們可以將日期精確到1/10000000秒,這樣的話重名的可能性就很小了。
- Response.Write(DateTime.Now.ToString("yyyyMMddHHmmssfffffff"));//輸出:200803260827087983268
格式
基本內容是:可以在Console.WriteLine(以及String.Format,它被Console.WriteLine調用)中的格式字符串內的括號中放入非索引數字的內容。格式規范的完整形式如下:
- {index[,width][:formatstring]}
其中,index是此格式程序引用的格式字符串之后的參數,從零開始計數;width(如果有的話)是要設置格式的字段的寬度(以空格計)。width取正數表示結果右對齊,取負數則意味著數字在字段中左對齊。(請參閱下面的前兩個示例。)
formatstring是可選項,其中包含有關設置類型格式的格式說明。如果對象實現IFormattable,formatstring就會傳遞給對象的Format方法(在Beta2和后續版本中,該方法的簽名變為ToString(string,IFormatProvider),但功能不變)。如果對象不實現IFormattable,就會調用Object.ToString(),而忽略formatstring。
另請注意,在Beta1中不區分當前語言的ToString在Beta2和后續版本中“將”區分語言。例如,對于用“.”分隔千位,用“,”分隔小數的國家,1,234.56將會格式化成1.234,56。如果您需要結果無論在什么語言下都是一樣的,就請使用CultureInfo.InvariantCulture作為語言。
若要獲取有關格式的完整信息,請查閱“.NET框架開發人員指南”中的格式概述(英文)。
數字格式
請注意,數字的格式是區分語言的:分隔符以及分隔符之間的空格,還有貨幣符號,都是由語言決定的—默認情況下,是您計算機上的默認語言。默認語言與執行線程相關,可以通過Thread.CurrentThread.CurrentCulture了解和設置語言。有幾種方法,可以不必僅為一種給定的格式操作就立即更改語言。
內置類型的字母格式
有一種格式命令以單個字母開頭,表示下列設置:
G—常規,E或F中較短的
F—浮點數,常規表示法
E—用E表示法表示的浮點數(其中,E代表10的次冪)
N—帶有分隔符的浮點數(在美國為逗號)
C—貨幣,帶有貨幣符號和分隔符(在美國為逗號)
D—十進制數,僅用于整型
X—十六進制數,僅用于整型
字母可以后跟一個數字,根據字母的不同,該數字可以表示總位數、有效位數或小數點后面的位數。
下面是字母格式的一些示例:
- doublepi=Math.PI;
- doublep0=pi*10000;
- inti=123;
- Console.WriteLine("浮點格式,無分隔符(逗號)");
- Console.WriteLine("pi,Left{0,-25}",pi);//3.1415926535897931
- Console.WriteLine("p0,Rt.{0,25}",p0);//3.1415926535897931
- Console.WriteLine("pi,E{0,25:E}",pi);//3.1416E+000
- Console.WriteLine("使用E和F格式,小數點后保留n(此處為4)位");
- Console.WriteLine("pi,E4{0,25:E4}",pi);//3.1416E+000
- Console.WriteLine("pi,F4{0,25:F4}",pi);//3.1416
- Console.WriteLine("使用G格式,保留4位有效數字——如果需要請使用E格式");
- Console.WriteLine("pi,G4{0,25:G4}",pi);//3.142
- Console.WriteLine("p0,G4{0,25:G4}",p0);//3.142E4
- Console.WriteLine("N和C格式帶有逗號(分隔符),"+
- "默認小數點后保留兩位,四舍五入。");
- Console.WriteLine("p0,N{0,25:N}",p0);//31,415.93
- Console.WriteLine("p0,N4{0,25:N4}",p0);//31,415.9265
- Console.WriteLine("p0,C{0,25:C}",pi);// $3.14
- Console.WriteLine("D和X格式僅用于整型,"+
- "非整型將產生格式異?!猉指十六進制");
- Console.WriteLine("i,D{0,25:D}",i);//123
- Console.WriteLine("i,D7{0,25:D7}",i);//0000123
- Console.WriteLine("i,X{0,25:X}",i);//7B
- Console.WriteLine("i,X8{0,25:X8}",i);//0000007B
圖片格式
與字母格式不同,formatstring可以包含“圖片格式”。下面是從代碼中摘錄的幾個實例。(這類似于Basic中的“PrintUsing”語句。)圖片格式功能甚至包括以不同方式設置負數、正數和零的格式的能力。還有幾個圖片格式功能,下面的示例中未包括在內。有關詳細信息,請參閱“.NET框架開發人員指南”或文檔中的主題圖片格式數字串(英文)。
在下例中您將注意到,好心的博士既使用了“#”字符,又使用了“0”字符。如果相應的數字是前導零或尾隨零,“#”字符就會替換為空值。無論相應數字的值如何,“0”字符都會被替換為零字符—因此,數字將會被零填補。句號(如果有的話)表示小數分隔符的位置。
那么,為什么要同時使用這些字母,比如“###0.##”?如果要設置格式的值恰好為零,“#”圖片字符就被替換為“無”(連零字符也不是)。您可能“總是”希望在小數點的左邊至少有一個“0”,否則,如果值為零,字段就沒有輸出。換言之,僅包含“#”字符,一個“0”也沒有的格式常被認為是一個編程錯誤。
逗號有兩種用法:如果一個逗號或一組逗號緊跟在句號的左邊(或者沒有句號時在結尾),它們就會告訴格式化程序分隔10**(3*n)所顯示的數字,其中,n是逗號的個數。換言之,數字按千位、百萬位、十億位等分隔。
如果逗號的右側至少有一個“0”或“#”占位符,它就會告訴格式化程序在各數位組之間放置適當的組分隔符字符(在美國為逗號。)(在美國,每三個數位算一組。)
可以設置百分比的格式,方法是在圖片中放入“%”?!?”將在指定的位置顯示,在顯示前數字將被乘以100(這樣,0.28就變成了28%)。
如果希望將圖片格式用于指數表示法,可以指定“e”或“E”后跟加號或減號,再后跟任意個零,比如“E+00”或“e-000”。如果使用“e”,則顯示小寫“e”。如果使用“E”,則顯示大寫“E”。如果使用加號,則指數的符號總是出現。如果使用減號,則符號只有在指數為負數時才會顯示。(Beta1版在處理“-”時有問題,該符號會導致負號總是出現。)
根據要設置格式的數字的符號,還有一個條件格式。在格式字符串中僅包含兩個或三個獨立的格式,它們由分號分隔。如果有兩個格式,則第一個將用于非負數,第二個用于負數。如果有三個格式,則第一個將用于正數,第二個用于負數,第三個用于零。
可以在格式字符串中包含文字字符。如果所需的字符具有特殊意義,請在其前面使用反斜杠符號,使其“轉義”。例如,如果希望在不乘以100的情況下顯示百分比符號,就可以在數字前面使用反斜杠(在C++和C#中必須使用兩個反斜杠),比如“#0.##\%”。(如果正在使用C#,就可以使用極酷的逐字字符串文字,比如@"#0.##%"。)或者,也可以將字符串放入單引號或雙引號中,以避免將其字符解釋為格式命令。在Beta2及更高版本中,可以通過使用雙括號,從而在格式字符串中包含文字括號。
下面是有關圖片格式的一些示例:
- longm34=34000000;//34,000,000
- Console.WriteLine("幾種圖片格式");
- Console.WriteLine("如果沒有數位,0將打印0;"+
- "諸如i:的文字總是打印");
- Console.WriteLine("t句點代表小數分隔符的位置");
- Console.WriteLine("i,i:0000.0{0,10:i:0000.0}",i);//
- i:0123.0
- Console.WriteLine("如果沒有有效數字#將不顯示,"+
- "逗號意味著放入分隔符");
- Console.WriteLine("請確保在數字圖片中至少使用一個0。");
- Console.WriteLine("p0,##,##0.#{0,10:##,##0.#}",-p0);//-31,415.9
- Console.WriteLine("m34,0,,{0,10:0,,百萬}",m34);//34百萬
- Console.WriteLine("p0,#0.#E+00{0,10:#0.#E+00}",p0);//31.4E+03
- Console.WriteLine("%乘以100并打印百分號");
- Console.WriteLine("pi,###0.##%{0,10:###0.##%}",pi);//314.16%
- Console.WriteLine("因為\而沒有進行乘法運算"+
- "(注意:兩個反斜線?。?);
- Console.WriteLine("pi,###0.##\\%{0,10:###0.##\%}",pi);//3.14%
- Console.WriteLine("與C#的逐字字符串相同");
- Console.WriteLine(@"pi,###0.##\%{0,10:###0.##%}",pi);//3.14%
- Console.WriteLine("10,'#'#0{0,10:'#'#0}",10);//#10
- Console.WriteLine("基于符號的條件格式");
- Console.WriteLine("如果是0或正數打印#,如果是負數打印(#)");
- Console.WriteLine("-50;(0){0,10:0;(0)}",-5);//(5)
- Console.WriteLine("如果是正數打印#,如果是負數打印-#,如果是0打印zip");
- Console.WriteLine("00;-0;zip{0,10:0;-0;zip}",0);//zip
如您所見,格式功能非常強大。
格式的工作方式
文檔中的示例對所傳遞的對象類型的變量調用Format方法。對這些Format方法僅傳遞格式規范的formatstring部分,而不傳遞index和width。(在Beta2中,對Format的調用將改為對ToString的調用。)
index和width由String.Format(它被Console.Write和Console.WriteLine調用)使用,以獲得調用Format的正確對象以及將該調用的結果左或右對齊。(順便說一下,如果要設置格式的對象不實現IFormattable(并因此調用Format方法),String.Format將調用對象的ToString()方法,而忽略formatstring。)
換言之,Console.WriteLine調用String.Format,傳遞向它傳遞的所有參數。String.Format分析字符串,查找“{”字符。找到該字符后,它將分析子字符串直到第一個“}”為止,以確定index數、width和formatstring。然后,它按照index訪問相應的參數,并調用其Format方法,傳遞“{}”段中的formatstring部分。(如果參數對象不實現IFormattable,則被調用的是ToString。)
無論是實現還是不實現,都會返回一個字符串,并且String.Format在繼續分析格式字符串之前會將其與結果字符串連接。之后,String.Format將生成的帶格式字符串返回給Console.WriteLine,由Console.WriteLine進行顯示。
對于Beta2及更高版本,對象的Format方法(它是IFormattable中的Format方法)被ToString所替代,ToString獲取一個格式字符串和一個IFormatProvider(或null)。但String.Format仍存在,因此這些調用將不改變。
自定義格式
您自己也可以編寫格式化程序,用于自己的類型或作為內置類型的自定義格式化程序,如“.NET框架開發人員指南”中的自定義Format方法所說明的那樣。如果編寫內置類型的自定義格式化程序,就不能從Console.WriteLine中使用它,但可以通過調用String.Format的重載而使用它,String.Format的重載將采用IServiceObjectProvider(在beta2及更高版本中稱為IFormatProvider)作為參數。
C#日期格式化和時間格式
您將記起,有一個叫做DateTime的類,用于保存日期和時間。像您所猜想的那樣,有大量方法可供設置DateTime對象的格式:僅日期、僅時間、世界時或本地時、若干種日/月/年順序,甚至可分類。C#日期格式化和時間格式是區分語言的。
還可以使用自定義格式字符串來設置DateTime對象的格式。這種字符串將包含由某些字母組成的區分大小寫的子字符串,以表示日期和時間的各個不同部分,如星期幾、幾號、月份、年份、紀元、小時、分鐘、秒或時區。這些部分中有許多具有多種格式,例如,M是沒有前導零的數字月份,MM是有前導零的數字月份,MMM是三個字母的月份縮寫,MMMM是所在國家語言對應的完整月份名稱的拼寫。在“.NET框架參考”中可以找到自定義和標準格式字符的完整列表。
下面是有關C#日期格式化和時間格式的一個示例:
- longm34=34000000;//34,000,000
- Console.WriteLine("幾種圖片格式");
- Console.WriteLine("如果沒有數位,0將打印0;"+
- "諸如i:的文字總是打印");
- Console.WriteLine("t句點代表小數分隔符的位置");
- Console.WriteLine("i,i:0000.0{0,10:i:0000.0}",i);//
- i:0123.0
- Console.WriteLine("如果沒有有效數字#將不顯示,"+
- "逗號意味著放入分隔符");
- Console.WriteLine("請確保在數字圖片中至少使用一個0。");
- Console.WriteLine("p0,##,##0.#{0,10:##,##0.#}",-p0);//-31,415.9
- Console.WriteLine("m34,0,,{0,10:0,,百萬}",m34);//34百萬
- Console.WriteLine("p0,#0.#E+00{0,10:#0.#E+00}",p0);//31.4E+03
- Console.WriteLine("%乘以100并打印百分號");
- Console.WriteLine("pi,###0.##%{0,10:###0.##%}",pi);//314.16%
- Console.WriteLine("因為\而沒有進行乘法運算"+
- "(注意:兩個反斜線!)");
- Console.WriteLine("pi,###0.##\\%{0,10:###0.##\%}",pi);//3.14%
- Console.WriteLine("與C#的逐字字符串相同");
- Console.WriteLine(@"pi,###0.##\%{0,10:###0.##%}",pi);//3.14%
- Console.WriteLine("10,'#'#0{0,10:'#'#0}",10);//#10
- Console.WriteLine("基于符號的條件格式");
- Console.WriteLine("如果是0或正數打印#,如果是負數打印(#)");
- Console.WriteLine("-50;(0){0,10:0;(0)}",-5);//(5)
- Console.WriteLine("如果是正數打印#,如果是負數打印-#,如果是0打印zip");
- Console.WriteLine("00;-0;zip{0,10:0;-0;zip}",0);//zip
【編輯推薦】