1. 程式人生 > >收藏--頁面匯出為Excel檔案中時間格式的問題

收藏--頁面匯出為Excel檔案中時間格式的問題

一個管理類系統中,在頁面生成報表時允許使用者選擇他prefer的時間格式,有下面四種時間格式可供選擇: 
Default Option: yyyy-mm-dd 
Descriptive (1-Jan-07) 
Short Date: mm/dd/yy 
Short Date: dd/mm/yy 
另外,使用者可以選擇報表是頁面形式還是匯出為Excel檔案。原有的處理在頁面上顯示時間格式沒有任何問題,但是昨天發現,如果匯出Excel,那麼時間格式就出錯了:( 
原因: 

當我們把web頁面上的資料導成excel形式時,有時候我們的資料需要以特定的格式呈現出來,這時候我們就需要給cell新增一些樣式規格資訊。 
首先,我們瞭解一下excel從web頁面上匯出的原理。當我們把這些資料傳送到客戶端時,我們想讓客戶端程式(瀏覽器)以excel的格式讀取它,所以把 mime型別設為:application/vnd.ms-excel,當excel讀取檔案時會以每個cell的格式呈現資料,如果cell沒有規定的格式,則excel會以預設的格式去呈現該cell的資料。這樣就給我們提供了自定義資料格式的空間,當然我們必須使用excel支援的格式。下面就列出常用的一些格式: 
1) 文字:vnd.ms-excel.numberformat:@ 
2) 日期:vnd.ms-excel.numberformat:yyyy/mm/dd 
3) 數字:vnd.ms-excel.numberformat:#,##0.00 
4) 貨幣:vnd.ms-excel.numberformat:¥#,##0.00 
5) 百分比:vnd.ms-excel.numberformat: #0.00% 
這些格式你也可以自定義,比如年月你可以定義為:yy-mm等等。那麼知道了這些格式,怎麼去把這些格式新增到cell中呢?很簡單,我們只需要把樣式新增到對應的標籤對(即閉合標籤)即可。如<td></td>,給標籤對<td></td>新增樣式,如下: 
<td style="vnd.ms-excel.numberformat:@">410522198402161833</td> 
同樣,我們也可以給<div></div>新增樣式,也可以給<tr></tr>,<table></table>新增樣式,這樣就會引入一個問題,你注意到了嗎?先看如下的程式碼: 
<table style='vnd.ms-excel.numberformat:#,##0.00'> 
<tr> 
<td>542</td> 
<td style='vnd.ms-excel.numberformat: #0.00%'>0.25</td> 
</tr> 
</table> 
對,當我們在父標籤對和子標籤對都新增樣式時,資料會以哪一個樣式呈現呢?經過測試,會以離資料最近的樣式呈現,這也是符合我們的意願的(好像也符合一句俗話:縣官不如現管)。這樣我們就可以通過改變樣式而改變資料在excel中呈現的方式(這些樣式規格你可以在前臺頁面上新增也可以在後臺程式碼裡給相應的控制元件如:DataGrid等新增這些樣式)。如果你的應用比較簡單,那麼這已經足夠滿足你的需求。但如果你的應用比較複雜,那麼你也可以採取一種方式來達到不同的資料呈現效果。下面,我就舉一個稍微複雜一點的應用。 
例如:你的資料要呈現給不同國家和地區的使用者檢視,這樣資料的呈現的格式就會不一樣,那麼我們怎麼解決這個問題呢?當然了,你可以手工把這些資料處理好,但這畢竟不是最好的方法,因為如果我們每增加一個其他國家或地區的使用者,那麼我們就需要把所有的資料以客戶要求的格式處理一遍,當資料量很大時,這無疑是一件很沉重且無聊的工作。那麼我們究竟應該怎樣解決類似這樣的問題呢?下面我說一下,我自己的看法:把這些格式化的資訊抽取到一個xml檔案中,程式執行時根據不同的客戶讀取不同的格式化資訊,然後把這些格式化資訊動態的新增到我們的資料上,這樣,當我們每增加一個其他國家或地區的使用者時,我們只需要多增加一個xml檔案,把對應的格式化資訊寫入這個xml檔案,然後當這個國家或地區的使用者檢視時,就把對應的格式化資訊讀取出來應用到資料上即可。 
以上這個例子是我突然想到的,相信跨國企業的公司會遇到類似的問題,解決方法只是提供給大家一個思路,希望可以起到拋磚引玉的效果。 
DataGrid: 
Asp.Net WebForm中DataGrid匯出的時候,在ItemDataBound內 
if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) 

e.Item.Cells[0].Attributes.Add("style","vnd.ms-excel.numberformat:@"); 

如果在WinForm內則可以 
Excel.Range range = (Excel.Range)worksheet.Cells[1,1]; 
range.NumberFormat = Excel.XlParameterDataType.xlParamTypeUnknown; 
VB: 
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then 
e.Item.Cells(1).Attributes.Add("style", "vnd.ms-excel.numberformat:@") 
End If 
如果是Label,則在<td>的style中加上: 
<td style="height: 22px; vnd.ms-excel.numberformat:@" bgcolor="#eff3fb"> 
<asp:Label ID="Label2" runat="server" Text="Label"></asp:Label></td> 
如果是Gridview,(07.12.13 Update) 
則需要在後臺列印click事件程式碼中加兩句話: 
// More Codes 
string style = @"<style> .text { mso-number-format:\@; } </script> "; 
Response.Write(style); 
Response.Output.Write(oStringWriter.ToString()); 
--------------------------------------------------------------- 
下面開始說我處理這個問題的過程: 
首先,根據上面那篇文章中說的那樣,在<td></td>標籤上加上style屬性,並根據使用者選擇的時間格式設定: 
<TD VALIGN=TOP style="vnd.ms-excel.numberformat:<%=DateFormat%>">...</td> 
然後開始測試,結果前三種時間格式都沒問題,最後一個:dd/mm/yy,有的時間正確的,有的是錯誤的,錯誤的時間均為dd>12的那些。為什麼會這樣呢,經過反覆的測試琢磨,最後終於弄清楚了:原來,在我們使用匯出資料到Excel中去時,Excel會從中作梗!不只是這樣,我們可以試著在Excel中輸入時間,不管你輸入的是什麼格式,它都會把這個時間強行轉化為 mm/dd/yyyy 格式。我傳過去的日期(例如:30/10/08)到它那邊,它就傻了,因為它不認識了,然後在cell裡顯示時,就老老實實地顯示為30/10/08,也算歪打正著吧(其實是錯的)。但是如果是 1/10/08 (這個是我已經轉換好的 dd/mm/yy 格式)呢?它可不管,認為這個(1/10/08)是 mm/dd/yy 格式的,不管三七二十一,轉換為 1/10/2008,注意,這個( 1/10/2008)的意思是 2008年1月10日,已經完全背離了我的意願了:( 
忘了說一個東西了,我們從資料庫中取出日期資料時,會根據使用者選擇的格式(上面列出的4種格式)來進行format。這時我想到一個trick,就是如果使用者選擇的是dd/mm/yy這種格式,我先不把date格式化為 dd/mm/yy,而是mm/dd/yy,這樣資料到達Excel時它就可以分辨出來了,同時,由於我指定了<td>的 style 屬性,excle會嚴格地按照那種格式來進行顯示(不管Excel上顯示的時間格式是什麼樣的,當你編輯時間是,你會看到,你可以編輯的格式永遠是 mm/dd/yyyy)。 
至此,問題圓滿得到解決。