2013-05-02 28 views
12

我將所有DateTime字段存儲爲UTC時間。當用戶請求網頁時,我想採用他首選的本地時區(而不是服務器本地時區),並自動將所有Web表單中的所有DateTime字段顯示爲本地日期。將UTC日期時間全局轉換爲用戶指定的本地日期時間

當然,我可以在每個窗體的每個DateTime.ToString()調用上應用轉換,或者實現一些輔助工具,但這是一個耗時的任務,還有一些第三方組件很難配置自定義DateTime顯示模板。

從本質上講,我想提出DateTime類的行爲如下:

from this moment on for this web request, 
whenever some code calls DateTime.ToString(), convert it to the local time 
     using the timezone offset given at the very beginning of the web request, 
but if possible, please keep .NET core library DateTime.ToString() calls intact 
     (I don't want to mess up event logging timestamps etc.) 

有沒有辦法做到這一點?

順便說一句,我使用ASP.NET MVC 4,如果它很重要。

回答

3

簡短的答案是,你不能。 HTTP不需要(甚至不提供標準方式)用戶代理(瀏覽器)在HTTP請求中提供本地時間或時區信息。

您可能需要

  • 要求用戶提供其首選的時區,或
  • 有客戶端的JavaScript報告給你以某種方式(餅乾嗎?AJAX?其他?)

請記住,客戶端JavaScript解決方案也不完美。 Javascript禁用(或者對於某些瀏覽器不存在)。 Javascript可能無法訪問時區信息。等

26

你不能直接做你所要求的,但我會建議一些替代品。正如尼古拉斯指出的那樣,HTTP中沒有任何東西可以直接給你時區。

選項1

  • 首先,決定你要使用哪種類型的時區的數據。有兩種不同的類型可用,您可以通過TimeZoneInfo課程訪問的Microsoft時區,或者世界其他地區使用的IANA/Olson時區。 Read here for more info。我的建議是後者,使用NodaTime提供的實施。

  • 然後確定要將哪個時區轉換爲。你應該允許你的用戶在某個地方選擇他們的時區。

    • 你可能會顯示一個下拉列表中進行選擇的幾個時區,或者你可能會做更有用的東西,像顯示世界地圖的,他們可以單擊以選中他們的時區。有幾個庫可以在Javascript中做到這一點,但我最喜歡的是this one

    • 您可能想要猜測使用的默認時區,因此您可以在從列表(或地圖)中選擇之前儘可能接近準確。這個名爲jsTimeZoneDetect的圖書館很棒。它會詢問瀏覽器的時鐘,並且猜測它可能是什麼時區。這是相當不錯的,但它仍然只是一個猜測。不要盲目使用它 - 但要用它來確定一個起點。 更新您現在還可以使用moment.tz.guess()在moment.js的moment-timezone組件中執行此操作。

  • 現在你知道用戶的時區,您可以使用該值將UTC DateTime值轉換爲本地時區。不幸的是,沒有什麼可以在線程上設置的。當您更改系統時區時,它對所有進程和線程都是全局的。所以你別無選擇,只能將時區傳遞給你發送回去的每一個地方。 (我相信這是你的主要問題。)See this almost duplicate here.

  • 之前將其轉換爲字符串,則需要也知道用戶所在的區域(這可以從Request.UserLanguages值獲得)。您可以將其分配給當前線程,也可以將其作爲參數傳遞給DateTime.ToString()方法。這不會做任何時區轉換 - 它只是確保數字處於正確的位置,使用正確的分隔符以及適用於平日或月份名稱的語言。

選項2

不要其轉換爲本地時間在服務器上的。

  • 既然你說你與UTC值工作,確保他們的.Kind屬性爲Utc。你或許應該這樣做,當你從數據庫中加載,但如果你有,你可以做手工:

    myDateTime = DateTime.SpecifyKind(myDateTime, DateTimeKind.Utc); 
    
  • 發送回瀏覽器作爲純UTC,像ISO8601不變的格式。換句話說:

    myDateTime.ToString("o"); // example: "2013-05-02T21:01:26.0828604Z" 
    
  • 使用瀏覽器的JavaScript部分來解析它爲UTC。它會自動獲取瀏覽器的本地時間設置。一種方法是使用內置的Date對象在JavaScript中,像這樣的:

    var dt = new Date('2013-05-02T21:01:26.0828604Z'); 
    

    然而,這隻會在支持ISO-8601格式的新瀏覽器。相反,我建議使用moment.js庫。它在瀏覽器中保持一致,並且更好地支持ISO日期和本地化。另外你還可以獲得許多其他有用的解析和格式化功能。

    // pass the value from your server 
    var m = moment('2013-05-02T21:01:26.0828604Z'); 
    
    // use one of the formats supported by moment.js 
    // this is locale-specific "long date time" format. 
    var s = m.format('LLLL'); 
    

選項1的好處是,你可以在任何時區的時間工作。如果您可以從下拉列表中詢問用戶的時區,那麼您不需要使用任何Javascript。

選項2的優點是您可以讓瀏覽器爲您完成一些工作。如果您發送的是原始數據,例如將AJAX調用到WebAPI,這是最好的方法。但是,JavaScript只知道UTC和瀏覽器的本地時區。因此,如果您需要將其轉換爲其他區域,則效果不佳。

您還應該注意,如果您選擇選項#2,則可能會受到ECMAScript 5.1設計中的缺陷的影響。如果您使用的夏時制規則所涵蓋的日期與當前生效的日期一致,則這會起作用。您可以閱讀更多in this questionon my blog

如果我們在HTTP標頭中有一些時區信息,那很容易,但不幸的是我們沒有。這些是可以跳過的很多環節,但這是兼顧靈活性和準確性的最佳方式。

+0

很好的答案!你說這也可以用JavaScript中的內置Date對象完成。你能否更新你的答案以表明如何做到這一點? – Scott 2013-12-31 17:05:17

+0

@Scott - 已更新。謝謝。 – 2013-12-31 18:04:20

相關問題