C# 基礎知識系列- 13 常見類庫介紹(二)日期時間類
阿新 • • 發佈:2020-04-26
# 0. 前言
上一篇內容介紹了Console類和Math類,這篇內容著重介紹一下C#中時間日期的處理方式。
> 上一篇勘誤: 上一篇中關於靜態類沒有建構函式,這一表述有誤。正確的說法是C#中靜態類不包含常規建構函式,但可以新增一個靜態建構函式。
> 靜態建構函式與普通普通建構函式的區別是,靜態建構函式沒有訪問修飾符,即訪問修飾符是預設的,且靜態建構函式只能是無參的,並新增 static 修飾符;靜態建構函式不能手動呼叫,會在類載入的時候由系統自己載入。
# 1 DateTime 和 TimeSpan
DateTime表示時間點,TimeSpan表示 時間段。在C#中,這兩個都是結構體,結構體與類都能繼承並實現介面,但是與類不同的是結構體在記憶體中存放在棧裡。這部分在微軟官方文件中關於CLR有過介紹。後續也會針對CLR寫一個系列。這裡就不做過多的介紹了。
DateTime延伸開來也有很多內容要講,這裡只做一個大體的介紹:
## 1. 建立一個DateTime
```c#
DateTime time = new DateTime(2018,1,20);// 2018年1月20日 0時0分0秒
DateTime time = new DateTime(2019,11,30, 12, 01, 59);// 2019年11月30日,12:01:59
DateTime time = DateTime.Now;// 表示程式碼執行到這裡的系統時間,一般意義上的當前時間
DateTime time = new DateTime(long ticks);// 以時間刻度計算日期,以公曆 0001 年 1 月 1 日 00:00:00.000 以來所經歷的以 100 納秒為間隔的間隔數來表示
```
這些是我們常用的建立日期的方法,還有一些通過日曆物件結合日曆來建立日期時間,不過這塊在不涉及到程式國際化之前不需要做過多的深入。
需要注意的是,`DateTime.Now`在每次執行結果都不一樣,這個屬性返回的是系統執行時**當前時間**,而不是程式編寫時的時間。與之對應的還有一個`DaTime.Today`,這個屬性返回結果是**當天**,也就是Now去掉時分秒的時間。
## 2. 日期變更
DateTime提供了很多可以變更日期的方法,這些方法可以獲取一個計算之後的時間值:
```c#
public DateTime AddDays (double value);// 計算天數,正數代表 天數增加,負數代表天數減少
public DateTime AddHours (double value);// 返回一個新的 DateTime,它將指定的小時數加到此例項的值上。
public DateTime AddMilliseconds (double value);//返回一個新的 DateTime,它將指定的毫秒數加到此例項的值上。
public DateTime AddMonths (int months);//返回一個新的 DateTime,它將指定的月數加到此例項的值上
public DateTime AddMonths (int months);// 返回一個新的 DateTime,它將指定的月數加到此例項的值上
public DateTime AddSeconds (double value);/// 返回一個新的 DateTime,它將指定的秒數加到此例項的值上。
public DateTime AddTicks (long value);// 返回一個新的 DateTime,它將指定的刻度數加到此例項的值上,也就是建構函式裡的ticks
public DateTime AddYears (int value);//返回一個新的 DateTime,它將指定的年份數加到此例項的值上。
```
以上是DateTime類對日期計算的支援,其中引數如果是正的表示時間後移,如果是負的則表示時間向前移。
需要注意的一點就是,日期的變更不會在原有的DateTime元素上變更,會返回一個計算之後的日期型別。
## **3. 日期算術運算**
說了這麼多DateTime,沒有介紹TimeSpan,那麼這裡就會介紹一下TimeSpan是什麼了。TimeSpan表示一個時間間隔,也就是兩個DateTime之間的差值。說到這裡,大家也應該明白日期的算術運算應該是指什麼了。以下來看一組示例:
```c#
class Program
{
static void Main(string[] args)
{
DateTime lastYear = new DateTime(2019, 03, 08, 20,49, 36);
DateTime now = DateTime.Now;
TimeSpan span = now - lastYear;
DateTime newTime = lastYear + span;
}
}
```
這就是C#中關於日期運算的基本內容。那我們來看看 TimeSpan裡封裝了哪些內容吧。
TimeSpan的屬性:
```c#
public int Days { get; }//獲取當前 TimeSpan 結構所表示的時間間隔的天數部分。
public int Hours { get; }// 獲取當前 TimeSpan 結構所表示的時間間隔的小時數部分。
public int Milliseconds { get; }//獲取當前 TimeSpan 結構所表示的時間間隔的毫秒數部分。
public int Minutes { get; }//獲取當前 TimeSpan 結構所表示的時間間隔的分鐘數部分。
public int Seconds { get; }//獲取當前 TimeSpan 結構所表示的時間間隔的秒數部分。
```
以上屬性表示一個TimeSpan的代表的時間間隔中的天數、小時、分鐘等。
```c#
public double TotalDays { get; }//獲取以整天數和天的小數部分表示的當前 TimeSpan 結構的值。
public double TotalHours { get; }//獲取以整小時數和小時的小數部分表示的當前 TimeSpan 結構的值。
public double TotalMinutes { get; }//獲取以整分鐘數和分鐘的小數部分表示的當前 TimeSpan 結構的值。
public double TotalSeconds { get; }//獲取以整秒數和秒的小數部分表示的當前 TimeSpan 結構的值。
public double TotalMilliseconds { get; }//獲取以整毫秒數和毫秒的小數部分表示的當前 TimeSpan 結構的值。
```
上述幾組屬性表示以XXX為單位,返回的TimeSpan的值,與之相對應的TimeSpan提供了一組FormXXX的方法,可以將double型別的值還原成TimeSpan。
因為TimeSpan表示時間間隔,所以TimeSpan也允許兩個TimeSpan進行加法運算,並提供了一個`Add(TimeSpan ts)`的方法。
這些是TimeSpan最常用的一些屬性和方法。不過在使用TimeSpan中需要注意的地方是,TimeSpan計算返回的值可正可負,正值表示時間間隔的頭在前尾在後,負值表示頭在後尾在前;TimeSpan中沒有提供TotalMonths這個方法,這是因為每個月具體有多少天不是固定值,如果想計算兩個日期直接相差幾個月,則需要自定義對應的計算方法了。
## 4. DateTime與字串之間的恩怨情仇
在程式中,使用者或者三方輸入的日期大多都是字串格式的,而且系統獲取到的時間也大多會轉成字串給其他人展示,所以這裡就會涉及到DateTime與字串之間的相互轉換。
我們先試試日期的各種ToString會產生什麼樣的結果:
```c#
class Program
{
static void Main(string[] args)
{
DateTime now = DateTime.Now;
Console.WriteLine("ToString :{0}", now.ToString());
Console.WriteLine("ToLongDateString :{0}", now.ToLongDateString());
Console.WriteLine("ToLongTimeString :{0}", now.ToLongTimeString());
Console.WriteLine("ToShortDateString :{0}",now.ToShortDateString());
Console.WriteLine("ToShortTimeString :{0}",now.ToShortTimeString());
}
}
```
結果:
![image-20200425111100330](https://img2020.cnblogs.com/other/1266612/202004/1266612-20200426061031730-1567504832.png)
這是DateTime的預設輸出結果,當然會根據系統的語言和地區等設定變化而產生不同的變化。為了避免這種變化,C#提供了一種日期型別的格式化模板,這裡介紹幾個常用的格式代表:
| 格式符 | 含義 |
| :----: | :----------------------------------------------------------: |
| yy | 年份。00~99,如果年份大於99,則只保留後兩位。如2020年則顯示20,2019年則顯示19 |
| yyyy | 年份,顯示四位。0000~9999 |
| M | 月份,顯示1~12 |
| MM | 月份,顯示01~12 |
| d | 天,1~31(具體看月份允許的最大天數) |
| dd | 與d一致,顯示為01~31 |
| h | 小時,12小時制顯示1~12 |
| hh | 與h一致,顯示為01~12 |
| H | 小時,24小時制,顯示0~23 |
| HH | 小時,24小時制,顯示00~23 |
| m | 分鐘,顯示0~59 |
| mm | 分鐘,顯示00~59 |
| s | 秒,顯示0~59 |
| ss | 秒,顯示00~59 |
| f | 表示日期和時間值的十分之幾秒,顯示0~9 |
| ff | 表示百分之幾秒,顯示00~99 |
最後的f,f的次數越多精度越細,但需要考慮系統的時鐘精度。
在實際開發中,最常用的格式是:`yyyy-MM-dd HH:mm:ss`,顯示效果就是:2020-04-25 12:00:00。其中連線符可以根據開發需求更換。
上述是時間轉字串,反過來也有字串轉時間。
使用`DateTime.Parse`或者`Convert.ToDateTime`就可以將字串轉換為時間型別。C#並不需要在字串轉日期的時候指定字串的顯示格式,這是因為一個約定優於配置的設計理念。C#通過分析字串,然後將字串轉換成對應的時間型別。當然,在正確解析到時間的時候,C#會丟擲異常。為此,C#提供了`DateTime.TryParse`方法,該方法不會丟擲異常,會返回一個是否正確轉換的bool值。
它的宣告如下:
```c#
public static bool TryParse (string s, out DateTime result);// 使用了result作為實際轉換結果
```
雖然C# 不用提供轉換格式就可以讀取,但是如果時間字串的格式比較少見呢,或者說就想指定一個格式字串,怎麼辦?別急,C#還提供了一個方法:
```c#
public static DateTime ParseExact (string s, string format, IFormatProvider provider);
```
不過,這個方法需要指定一個區域性的格式資訊:provider。這個資訊可以通過`CultureInfo.CurrentCulture`來獲取,這個屬性表示系統的當前區域資訊。
以上是DateTime的基本內容,有興趣的小夥伴可以查閱一下微軟的官方文件繼續深入研究一下。
> 更多內容煩請關注[我的部落格](https://blogs.attachie.club)
![file](https://img2020.cnblogs.com/other/1266612/202004/1266612-20200426061032018-1179323