# **第 20 章 Time 類與 Date 類**
在本章中,我們將會介紹操作時間的 `Time` 類、以及操作日期的 `Date` 類。
-
**Time 類與 Date 類**
對 `Time` 類以及 `Date` 類的概要進行說明
-
**時間、日期的獲取**
介紹獲取當前時間、日期的方法。
-
**時間、日期的計算**
介紹時間、日期的比較及運算方法。
-
**轉換為字符串**
介紹把時間、日期轉換為字符串的方法。
-
**解析字符串**
介紹把表示時間、日期的字符串分別轉換為 `Time` 對象、`Date` 對象的方法。
### **20.1 Time 類與 Date 類**
`Time` 類用于表示時間。時間除了表示年月日時分秒的信息以外,還包含了表示地域時差的時區(time zone)信息。例如我們可以計算中國當前時間是國際協調時間的幾點。
`Date` 類只用于表示年月日。因此,相對于 `Time` 類以秒為單位計算時間,`Date` 類則是以天為單位進行計算的。`Date` 類還可以求下個月的同一天、本月末等日期。
`Time` 類與 `Date` 類表示時間、日期時并沒有什么特別限制(前提是現在的日歷能一直用下去,甚至“西歷 100 億年”這樣的時間、日期也都是可以表示的)。但實際文件的時間戳、程序的運行時間等系統內的時間、以及數據庫中的時間類型數據等的情況下,有時候就會受到執行環境的限制。
### **20.2 時間的獲取**
-
**`Time.new`
`Time.now`**
通過 `Time.new` 方法或者 `Time.now` 方法獲取表示當前時間的 `Time` 對象。
~~~
p Time.new #=> 2013-03-30 03:06:00 +0900
sleep 1 #=> 等待1 秒
p Time.now #=> 2013-03-30 03:06:01 +0900
~~~
-
***t*.`year`
*t*.`month`
*t*.`day`**
也可以獲取時間對象中的年、月、日。
~~~
t = Time.now
p t #=> 2013-03-30 03:07:13 +0900
p t.year #=> 2013
p t.month #=> 3
p t.day #=> 30
~~~
表 20.1 列舉了時間的相關方法。
**表 20.1 時間的相關方法**
| 方法名 | 意義 |
|-----|-----|
| `year` | 年 |
| `month` | 月 |
| `day` | 日 |
| `hour` | 時 |
| `min` | 分 |
| `sec` | 秒 |
| `usec` | 秒以下的位數(以毫秒為單位) |
| `to_i` | 從 1970 年 1 月 1 日到當前時間的秒數 |
| `wday` | 一周中的第幾天(0 表示星期天) |
| `mday` | 一個月中的第幾天(與 `day` 方法一樣) |
| `yday` | 一年中的第幾天(1 表示 1 月 1 日) |
| `zone` | 時區(`JST` 等) |
-
**`Time.mktime`(
*year*[*, month*[*,* day[*, hour* [*, min*[*, sec*[*, usec*]]]]]]])**
通過 `Time.mktime` 方法可以根據指定時間獲取 `Time` 對象。
~~~
t = Time.mktime(2013, 5, 30, 3, 11, 12)
p t #=> 2013-05-30 03:11:12 +900
~~~
文件的創建時間、更新時間等也都能以 `Time` 對象的形式獲取。詳情請參考 18.3 節。
### **20.3 時間的計算**
`Time` 對象之間可以互相比較、運算。
~~~
t1 = Time.now
sleep(10) # 等10 秒
t2 = Time.now
p t1 < t2 #=> true
p t2 - t1 #=> 10.005073
~~~
還可以增加或減少 `Time` 對象的秒數。
~~~
t = Time.now
p t #=> 2013-03-30 03:11:44 +0900
t2 = t + 60 * 60 * 24 #=> 增加24 小時的秒數
p t2 #=> 2013-03-31 03:11:44 +0900
~~~
### **20.4 時間的格式**
-
***t*.`strftime`(*format*)
*t*.`to_s`**
通過 `Time#strftime` 方法可以把時間轉換為遵循某種格式的字符串。表 20.2 為格式(*format*)中可以使用的字符串。
**表 20.2 Time#strftime 中的格式字符串**
| 格式 | 意義與范圍 |
|-----|-----|
| `%A` | 星期的名稱(`Sunday`、 `Monday`……) |
| `%a` | 星期的縮寫名稱(`Sun`、 `Mon`……) |
| `%B` | 月份的名稱(`January`、 `February`……) |
| `%b` | 月份的縮寫(`Jan`、 `Feb`……) |
| `%c` | 日期與時間 |
| `%d` | 日(01 ~ 31) |
| `%H` | 24 小時制(00 ~ 23) |
| `%I` | 12 小時制(01 ~ 12) |
| `%j` | 一年中的天(001 ~ 366) |
| `%M` | 分(00 ~ 59) |
| `%m` | 表示月的數字(01 ~ 12) |
| `%p` | 上午或下午(AM、PM) |
| `%S` | 秒(00 ~ 60) |
| `%U` | 表示周的數字。以星期天為一周的開始(00 ~ 53) |
| `%W` | 表示周的數字。以星期一為一周的開始(00 ~ 53) |
| `%w` | 表示星期的數字。0 表示星期天(0 ~ 6) |
| `%X` | 時間 |
| `%x` | 日期 |
| `%Y` | 表示西歷的數字 |
| `%y` | 西歷的后兩位(00 ~ 99) |
| `%Z` | 時區( `JST` 等) |
| `%z` | 時區(+0900 等) |
| `%%` | 原封不動地輸出 `%` |
例如,`Time#to_s` 方法得到的字符串格式與 `"%Y-%m-%d %H:%M:%S %z"` 是等價的。
~~~
t = Time.now
p t.to_s #=> 2013-03-30 03:13:14 +0900
p t.strftime("%Y-%m-%d %H:%M:%S %z") #=> 2013-03-30 03:13:14 +0900
~~~
> **備注** `Time#strftime` 方法的格式是與平臺相關的,不同平臺下的執行結果可能不一樣。例如,在 Windows 中,`"%Z"` 的執行結果會顯示“中國標準時間”。
-
***t*.`rfc2822`**
通過 `Time#rfc2822` 方法可以生成符合電子郵件頭部信息中的 Date :字段格式的字符串。在互聯網的相關文檔 RFC(Request For Comments)中,有一個關于電子郵件形式定義的 RFC 2822 文檔,`rfc2822` 這個方法名就來自于此。使用這個方法前,需要預先通過 `require "time"` 引用 `time` 庫。
~~~
require "time"
t = Time.now
p t.rfc2822 #=> "Sat, 30 Mar 2013 03:13:34 +0900"
~~~
-
***t*.`iso8601`**
通過 `Time#iso8691` 方法生成符合 ISO 8601 國際標準的時間格式的字符串。使用這個方法時也需要引用 `time` 庫。
~~~
require "time"
t = Time.now
p t.iso8601 #=> "2013-03-30T03:13:34+09:00"
~~~
### **20.5 本地時間**
世界各地都有時差。大家的計算機中也設有時區,一般計算機中的時間都是根據時區來設定的。
-
***t*.`utc`
*t*.`localtime`**
我們可以用 `Time#utc` 方法把 `Time` 對象的時區變更為國際協調時間(UTC)。反之,用 `Time#localtime` 方法則可以把 UTC 變更為本地時間。
~~~
t = Time.now
p t #=> 2013-03-30 03:15:19 +0900
t.utc
p t #=> 2013-03-29 18:15:19 UTC
t.localtime
p t #=> 2013-03-30 03:15:19 +0900
~~~
### **20.6 從字符串中獲取時間**
可以將以字符串形式表示的時間轉換為 `Time` 對象。
-
**`Time.parse`(*str*)**
通過使用 `require "time"`,我們就可以使用 `Time.parse` 方法,來操作以字符串形式表現的時間。`Time.parse` 方法會解析參數字符串 *str*,返回對應的 `Time` 對象。
`Time.parse` 方法除了可以返回與 `Time#to_s` 方法相同的格式,還可以返回 "*yyyy/mm/dd*" 等多種格式。
~~~
require "time"
p Time.parse("Sat Mar 30 03:54:15 UTC 2013")
#=> 2013-03-30 03:54:15 UTC
p Time.parse("Sat, 30 Mar 2013 03:54:15 +0900")
#=> 2013-03-30 03:54:15 +0900
p Time.parse("2013/03/30")
#=> 2013-03-30 00:00:00 +0900
p Time.parse("2013/03/30 03:54:15")
#=> 2013-03-30 03:54:15 +0900
p Time.parse("H25.03.31")
#=> 2013-03-31 00:00:00 +0900
p Time.parse("S48.9.28")
#=> 1973-09-28 00:00:00 +0900
~~~
### **20.7 日期的獲取**
`Date` 類用于處理不包含時間的日期。使用 `Date.today` 方法可以得到表示當前日期的 `Date` 對象。使用 `Date` 類需要引用 `date` 庫。
~~~
require "date"
d = Date.today
puts d #=> 2013-03-30
~~~
與 Time 類一樣,日期也有其相關的方法。
~~~
require "date"
d = Date.today
p d.year # 年 => 2013
p d.month # 月 => 3
p d.day # 日 => 30
p d.wday # 一周中的第幾天(0 表示星期天) => 6
p d.mday # 一個月中的第幾天(與 day 方法一樣) => 30
p d.yday # 一年中的第幾天(1 表示 1 月 1 日) => 89
~~~
還可以用指定日期生成 `Date` 對象。
~~~
require "date"
d = Date.new(2013, 3, 30)
puts d #=> 2013-03-30
~~~
`Date` 類有一個特點是,可以對月末的日期做-1 處理(-2 表示月末的前一天)。當然也可以應對閏年。
~~~
require "date"
d = Date.new(2013,2,-1)
puts d #=> 2013-02-28
d = Date.new(2016, 2, -1)
puts d #=> 2016-02-29
~~~
### **20.8 日期的運算**
`Date` 對象之間的運算以天為單位。因此,`Date` 對象之間進行減法運算時,返回的是兩者之間的天數。日期減法運算的結果不是整數,而是 `Rational` 對象。此外,還可以將 `Date` 對象與整數進行加法、減法等運算,這時會返回該對象前后的日期。
~~~
require "date"
d1 = Date.new(2013, 1, 1)
d2 = Date.new(2013, 1, 4)
puts d2 - d1 #=> 3/1 (3 天的意思)
d = Date.today
puts d #=> 2013-03-30
puts d + 1 #=> 2013-03-31
puts d + 100 #=> 2013-07-08
puts d - 1 #=> 2013-03-29
puts d -100 #=> 2012-12-20
~~~
通過使用 `>>` 運算符,我們就可以獲取后一個月相同日期的 `Date` 對象。同理,使用 `<<` 運算符得到的是表示前一個月相同日期的 `Date` 對象。如果該月中沒有相同的日期(例如 2 月 30 日),則會返回月末的日期。
~~~
require "date"
d = Date.today
puts d #=> 2013-03-30
puts d >> 1 #=> 2013-04-30
puts d >> 100 #=> 2021-07-30
puts d << 1 #=> 2013-02-28
puts d << 100 #=> 2004-11-30
~~~
### **20.9 日期的格式**
與 `Time` 類一樣,通過 `strftime` 方法也可以將日期按指定的格式轉換為字符串。但結果中時間的部分會全部變為 0。
~~~
require "date"
t = Date.today
p t.strftime("%Y/%m/%d %H:%M:%S")
#=> "2013/03/30 00:00:00"
p t.strftime("%a %b %d %H:%M:%S %Z %Y")
#=> "Sat Mar 30 00:00:00 +00:00 2013"
p t.to_s #=> "2013-03-30"
~~~
### **20.10 從字符串中獲取日期**
使用 `Date.parse` 方法可以將字符串轉換為日期。這個方法可以應對多種日期格式。
~~~
require "date"
puts Date.parse("Sat Mar 30 03:50:12 JST 2013") #=> 2013-03-30
puts Date.parse("H25.05.30") #=> 2013-05-30
puts Date.parse("S48.9.28") #=> 1973-09-28
~~~
### **練習題**
1. 定義 `cparsedate` 方法,把“2013 年 5 月 30 日下午 8 點 17 分 50 秒”這種使用了“年月日時分秒”的字符串轉換為 `Time` 對象。
2. 定義 `ls_t` 方法,把指定目錄下的文件按時間順序排列,就像 Unix 的 ls -t 命令那樣。這個方法只有一個參數。
**`ls_t`( 目錄名)**
將指定目錄下的文件名按照時間從小到大的順序排列并輸出。
3. 使用 `Date` 類獲取本月中每天所對應的星期,并按以下日歷格式輸出結果。
~~~
May 2013
Su Mo Tu We Th Fr Sa
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
~~~
> 參考答案:請到圖靈社區本書的“隨書下載”處下載([http://www.ituring.com.cn/book/1237](http://www.ituring.com.cn/book/1237))。
- 推薦序
- 譯者序
- 前言
- 本書的讀者對象
- 第 1 部分 Ruby 初體驗
- 第 1 章 Ruby 初探
- 第 2 章 便利的對象
- 第 3 章 創建命令
- 第 2 部分 Ruby 的基礎
- 第 4 章 對象、變量和常量
- 第 5 章 條件判斷
- 第 6 章 循環
- 第 7 章 方法
- 第 8 章 類和模塊
- 第 9 章 運算符
- 第 10 章 錯誤處理與異常
- 第 11 章 塊
- 第 3 部分 Ruby 的類
- 第 12 章 數值類
- 第 13 章 數組類
- 第 14 章 字符串類
- 第 15 章 散列類
- 第 16 章 正則表達式類
- 第 17 章 IO 類
- 第 18 章 File 類與 Dir 類
- 第 19 章 Encoding 類
- 第 20 章 Time 類與 Date 類
- 第 21 章 Proc 類
- 第 4 部分 動手制作工具
- 第 22 章 文本處理
- 第 23 章 檢索郵政編碼
- 附錄
- 附錄 A Ruby 運行環境的構建
- 附錄 B Ruby 參考集
- 后記
- 謝辭