程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 使用.NET Framework中新的日期時間類型

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

編輯:關於.NET

概述

寫下本文緣於前幾天博客園一位朋友發表了一篇.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中對於日期時間類型的支持,希望對大家有所幫助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved