使用.NET Framework中新的日期時間類型

來源:互聯網
上載者:User
概述

寫下本文緣於前幾天部落格園一位朋友發表了一篇.NET面試題的文章,其中一個關於DateTime的問題引起了大家激烈的爭論,鑒於日期時間類型是大家開發中會頻繁使用的一個中資料類型,這裡我們有必要來對.NET Framework中的日期時間類型做一個深入的認識。

從.NET Framework 1.0開始,就提供了DateTime類型來表示一個日期時間類型,它是一個結構類型,並且不可以為空白,這在一定程度上給我們在往資料庫中儲存資料時帶來了很大的麻煩,因為我們知道,在資料庫中datatime類型是可以為Null的,為瞭解決這個問題,不得不經常使用DateTime.MinValue來表示,但這並不是我們想要的。幸運的是到了.NET Framework 2.0中,提供了可空類型,此時我們就可以使用Nullable<DateTime>來表示一個日期時間類型,它是可以為Null的,這給我們帶來了極大的方便。

到了.NET Framework 3.5中,又為我們提供了一個全新的日期時間類型DateTimeOffset,它通常以相對于格林威治時間(GMT,Greenwich Mean Time)的日期和時間來表示,格林威治時間又被稱為國際標準時間UTC(Universal Time Code)。除此之外,在.NET Framework中還為我們提供了TimeZone類用來表示時區,到了.NET Framework 3.5中,對TimeZone類進一步增強,提供了TimeZoneInfo類來表示世界上的任何時區。

在本文中,我們將對以上日期時間類型、時區類進行詳細的介紹。

DateTime和DateTimeOffset

DateTime 實值型別表示值範圍在公元0001 年1 月1 日午夜12:00:00 到公元9999 年12月31日晚上11:59:59 之間的日期和時間;DateTimeOffset包含一個DateTime 值以及一個名為Offset屬性,該屬性用於確定當前 DateTimeOffset 執行個體的日期和時間與UTC之間的差值,我們先來看一下這段代碼的輸出:

static void Main(string[] args){    Console.WriteLine(DateTime.Now);    Console.WriteLine(DateTimeOffset.Now);}

輸出結果為:

可以看到,DateTime輸出了日期和時間,DateTimeOffset類型不僅輸出了日期和時間,還給出目前時間與UTC之間的差值。接下來我們再看一段代碼,如何手工構造一個DateTime和DateTimeOffset執行個體:

static void Main(string[] args){    DateTime dateA = new DateTime(2008,8,26,23,1,48);    DateTimeOffset dateB = new DateTimeOffset(2008, 8, 26, 23, 1, 48,        new TimeSpan(4,0,0));    Console.WriteLine(dateA);    Console.WriteLine(dateB);}

輸出結果如所示:

轉換DateTime為DateTimeOffset

通過上面的兩個例子,大家應該對DateTimeOffset有了一個基本的認識,DateTimeOffset提供了比DateTime更高程度的時區識別能力,接下來我們看如何在DateTime和DateTimeOffset之間進行轉換,開始之前我們先瞭解一下DateTimeKind枚舉,在DateTime中提供了一個名為Kind的屬性,它用來指示DateTime對象是表示本地時間、國際標準時間(UTC),還是既不指定為本地時間,也不指定為國際標準時間(UTC),DateTimeKind的定義如下:

public enum DateTimeKind{    Unspecified,    Utc,    Local}

對於UTC 和本地DateTime值,得到的DateTimeOffset值的Offset屬性準確反映UTC 或本地時區位移量,如下面的代碼將 UTC 時間轉換為與之等效的DateTimeOffset值:

static void Main(string[] args){    DateTime dateA = new DateTime(2008,8,24,23,33,58);    DateTime dateB = DateTime.SpecifyKind(dateA, DateTimeKind.Utc);    DateTimeOffset dateC = dateB;    Console.WriteLine(dateB);    Console.WriteLine(dateC);}

輸出結果如所示:

再來寫一個表示本地時間的轉換,如下代碼所示:

static void Main(string[] args){    DateTime dateA = new DateTime(2008, 8, 24, 23, 33, 58);    DateTime dateB = DateTime.SpecifyKind(dateA, DateTimeKind.Local);    DateTimeOffset dateC = dateB;    Console.WriteLine(dateB);    Console.WriteLine(dateC);}

輸出結果如所示:

如果在轉換時指定的時間是Unspecified,轉換後產生的DateTimeOffset的值的位移量將會為本地時區,如下代碼所示:

static void Main(string[] args){    DateTime dateA = new DateTime(2008, 8, 24, 23, 33, 58);    DateTime dateB = DateTime.SpecifyKind(dateA, DateTimeKind.Unspecified);    DateTimeOffset dateC = dateB;    Console.WriteLine(dateB);    Console.WriteLine(dateC);}

輸出結果如所示,可以看到它產生的輸出是本地時區:

這一點其實從DateTimeOffset的一個參數為DateTime的建構函式中就能夠看出來,它只判斷DateTime是否為UTC,否則就取當前本地時區的位移量:

public DateTimeOffset(DateTime dateTime) {     TimeSpan offset;    if (dateTime.Kind != DateTimeKind.Utc) {        // Local 和 Unspecified 都轉換為Local        offset = TimeZone.CurrentTimeZone.GetUtcOffset(dateTime);     }    else {         offset = new TimeSpan(0);     }    m_offsetMinutes = ValidateOffset(offset);     m_dateTime = ValidateDate(dateTime, offset);} 
轉換DateTimeOffset為DateTime

在轉換一個DateTimeOffset類型為DateTime類型時,可以使用如下幾個屬性:

DateTime屬性:返回一個指示為Unspecified的DateTime值;

UtcDateTime屬性:返回一個指示為UTC的DateTime值,如果位移量不為0,它會轉換為UTC時間;

LocalDateTime屬性:返回一個指示為Local的DateTime值。

這三個屬性的在DateTimeOffset中的定義如下代碼所示:

public DateTime DateTime {    get {         return ClockDateTime;    }}public DateTime UtcDateTime {    get {         return DateTime.SpecifyKind(m_dateTime, DateTimeKind.Utc);     }} public DateTime LocalDateTime {    get {        return UtcDateTime.ToLocalTime();     }} 

可以看到,在LocalDateTime屬性中首先會擷取UtcDateTime,然後調用ToLocalTime()將其轉換為本地時間。我們現在來看一組測試代碼:

static void Main(string[] args){    DateTimeOffset basic = new DateTimeOffset(2008, 8, 24, 23, 33, 58,            new TimeSpan(8,0,0));    DateTime dateA = basic.DateTime;    DateTime dateB = basic.LocalDateTime;    DateTime dateC = basic.UtcDateTime;    Console.WriteLine(basic);    Console.WriteLine("--------------------------");    Console.WriteLine("Unspecified DateTime:" + dateA);    Console.WriteLine("Local DateTIme:" + dateB);    Console.WriteLine("UTC DateTime:" + dateC);}

最後輸出的結果如所示:

 

在DateTime和DateTimeOffset之間選擇

上面說了這麼多關於DateTime和DateTimeOffset類型,如何在DateTime和DateTimeOffset之間進行選擇呢?從前面的樣本中大家已經看到了,DateTime只可以表示UTC或者本地時區的時間,或者不確定的時區,這給我們應用程式的移植帶來了極大的麻煩,除非你指定它表示的是UTC,否則在移植應用程式時會受到諸多的限制,例如下面這段最簡單的代碼:

static void Main(string[] args){    DateTime date = DateTime.Now;    Console.WriteLine(date);}

如果DateTime表示本地時區,那麼應用程式在本地時區內移植是不會有問題的。但是如果你的應用程式需要對不同的時區都支援,建議在使用時盡量將DateTime的Kind屬性設定為Utc,這一點尤其重要,否則就需要考慮使用DateTimeOffset類型。

與DateTime類型不同的是,DateTimeOffset它唯一的標識了一個明確的時間點,即時間值以及相對於UTC的位移量,它並不依賴於某個特定的時區,在大多數情況下,應當考慮使用DateTimeOffset來代替DateTime類型。並且在SQL Server 2008中也已經提供了對於DateTimeOffset資料類型的支援,詳細資料可以參考這篇文章《SQL Server 2008中的新日期資料類型》。

但是DateTimeOffset類型並不是完全用來代替DateTime類型,在應用程式只用到日期而不涉及時間,如出生日期,用DateTime類型是沒有任何問題的。

時區支援

在.NET Framework 3.5之前,我們只能使用TimeZone來表示一個時區,但是Timezone功能很有限,它只能識別本地時區,可以在UTC和本地時間之間轉換時間;而TimeZoneInfo 對TimeZone進行了很大的增強,它可以表示世界上的任意時區 。看下面一段代碼:

static void Main(string[] args){    TimeZone timeZoneA = TimeZone.CurrentTimeZone;    Console.WriteLine(timeZoneA.StandardName);    TimeZoneInfo timeZoneB = TimeZoneInfo.Local;    Console.WriteLine(timeZoneB.StandardName);    TimeZoneInfo timeZoneC = TimeZoneInfo.Utc;    Console.WriteLine(timeZoneC.StandardName);}

輸出結果如所示:

 

TimeZone提供的屬性和方法非常有限,TimeZoneInfo在這方面就顯的非常豐富,我們可以使用TimeZoneInfo在兩個不同的時區之間轉換時間,如下面的代碼:

static void Main(string[] args){    DateTimeOffset chinaDate = DateTimeOffset.Now;    DateTimeOffset easternDate = TimeZoneInfo.ConvertTime(        chinaDate,        TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"));    Console.WriteLine("Now: {0}", chinaDate);    Console.WriteLine("Now in Eastern: {0}", easternDate);}

輸出結果如所示:

 

這裡使用FindSystemTimeZoneById方法來根據ID來擷取時區。在推出TimeZoneInfo之後,在以後的開發中完全可以放棄TimeZone類了,TimeZoneInfo已經完全包含了它。

總結

本文介紹了.NET Framework中對於日期時間類型的支援,希望對大家有所協助。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.