# Time类与Date类

## Time 类与 Date 类

***

* <https://www.kancloud.cn/imxieke/ruby-base/107308>

***

## Time 类与 Date 类说明

`Time` 类用于表示时间。时间除了表示年月日时分秒的信息以外，还包含了表示地域时差的时区（time zone）信息。例如我们可以计算中国当前时间是国际协调时间的几点。

`Date` 类只用于表示年月日。因此，相对于 `Time` 类以秒为单位计算时间，`Date` 类则是以天为单位进行计算的。`Date` 类还可以求下个月的同一天、本月末等日期。

`Time` 类与 `Date` 类表示时间、日期时并没有什么特别限制（前提是现在的日历能一直用下去，甚至“西历 100 亿年”这样的时间、日期也都是可以表示的）。但实际文件的时间戳、程序的运行时间等系统内的时间、以及数据库中的时间类型数据等的情况下，有时候就会受到执行环境的限制。

## 时间的获取

* `Time.new`
* `Time.now`

  通过 `Time.new` 方法或者 `Time.now` 方法获取表示当前时间的 `Time` 对象。

  ```ruby
  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`

  也可以获取时间对象中的年、月、日。

  ```ruby
  t = Time.now
  p t        #=> 2013-03-30 03:07:13 +0900
  p t.year   #=> 2013
  p t.month  #=> 3
  p t.day    #=> 30
  ```

  时间的相关方法

  方法名 | 意义

  * ```
      | -
    ```

  `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` 对象。

  ```ruby
  t = Time.mktime(2013, 5, 30, 3, 11, 12)
  p t    #=> 2013-05-30 03:11:12 +900
  ```

  文件的创建时间、更新时间等也都能以 `Time` 对象的形式获取。

## 时间的计算

`Time` 对象之间可以互相比较、运算。

```ruby
t1 = Time.now
sleep(10)    # 等10 秒
t2 = Time.now
p t1 < t2    #=> true
p t2 - t1    #=> 10.005073
```

还可以增加或减少 `Time` 对象的秒数。

```ruby
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
```

## 时间的格式

* `t.strftime(format)`
* `t.to_s`

  通过 `Time#strftime` 方法可以把时间转换为遵循某种格式的字符串。

  格式（format）中可以使用的字符串。 格式 | 意义与范围

  * ```
      | -
    ```

  `%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"` 是等价的。

  ```ruby
  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 库。

  ```ruby
  require "time"
  　
  t = Time.now
  p t.rfc2822    #=> "Sat, 30 Mar 2013 03:13:34 +0900"
  ```
* `t.iso8601`

  通过 `Time#iso8691` 方法生成符合 ISO 8601 国际标准的时间格式的字符串。使用这个方法时也需要引用 `time` 库。

  ```ruby
  require "time"
  　
  t = Time.now
  p t.iso8601    #=> "2013-03-30T03:13:34+09:00"
  ```

## 本地时间

世界各地都有时差。大家的计算机中也设有时区，一般计算机中的时间都是根据时区来设定的。

* `t.utc`
* `t.localtime`

  我们可以用 `Time#utc` 方法把 `Time` 对象的时区变更为国际协调时间（UTC）。反之，用 `Time#localtime` 方法则可以把 UTC 变更为本地时间。

  ```ruby
  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
  ```

## 从字符串中获取时间

可以将以字符串形式表示的时间转换为 `Time` 对象。

* `Time.parse(str)`

  通过使用 `require "time"`，我们就可以使用 `Time.parse` 方法，来操作以字符串形式表现的时间。`Time.parse` 方法会解析参数字符串 str，返回对应的 `Time` 对象。

  `Time.parse` 方法除了可以返回与 `Time#to_s` 方法相同的格式，还可以返回 "yyyy/mm/dd" 等多种格式。

  ```ruby
  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
  ```

## 日期的获取

`Date` 类用于处理不包含时间的日期。使用 `Date.today` 方法可以得到表示当前日期的 `Date` 对象。使用 `Date` 类需要引用 `date` 库。

```ruby
require "date"

d = Date.today
puts d    #=> 2013-03-30
```

与 `Time` 类一样，日期也有其相关的方法。

```ruby
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` 对象。

```ruby
require "date"

d = Date.new(2013, 3, 30)
puts d    #=> 2013-03-30
```

`Date` 类有一个特点是，可以对月末的日期做-1 处理（-2 表示月末的前一天）。当然也可以应对闰年。

```ruby
require "date"

d = Date.new(2013,2,-1)
puts d    #=> 2013-02-28

d = Date.new(2016, 2, -1)
puts d    #=> 2016-02-29
```

## 日期的运算

`Date` 对象之间的运算以天为单位。因此，`Date` 对象之间进行减法运算时，返回的是两者之间的天数。日期减法运算的结果不是整数，而是 `Rational` 对象。此外，还可以将 `Date` 对象与整数进行加法、减法等运算，这时会返回该对象前后的日期。

```ruby
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 日），则会返回月末的日期。

```ruby
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
```

## 日期的格式

与 `Time` 类一样，通过 `strftime` 方法也可以将日期按指定的格式转换为字符串。但结果中时间的部分会全部变为 0。

```ruby
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"
```

## 从字符串中获取日期

使用 `Date.parse` 方法可以将字符串转换为日期。这个方法可以应对多种日期格式。

```ruby
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
```
