class Time

一个 Time 对象代表一个日期和时间。

Time.new(2000, 1, 1, 0, 0, 0) # => 2000-01-01 00:00:00 -0600

尽管它的值可以表示为单个数字(请参见下面的 Epoch Seconds),但按部分处理该值可能会很方便。

t = Time.new(-2000, 1, 1, 0, 0, 0.0)
# => -2000-01-01 00:00:00 -0600
t.year # => -2000
t.month # => 1
t.mday # => 1
t.hour # => 0
t.min # => 0
t.sec # => 0
t.subsec # => 0

t = Time.new(2000, 12, 31, 23, 59, 59.5)
# => 2000-12-31 23:59:59.5 -0600
t.year # => 2000
t.month # => 12
t.mday # => 31
t.hour # => 23
t.min # => 59
t.sec # => 59
t.subsec # => (1/2)

Epoch Seconds

Epoch seconds 是自 Unix Epoch(1970 年 1 月 1 日)以来的精确秒数(包括小数秒)。

您可以使用方法 Time.to_r 精确检索该值。

Time.at(0).to_r        # => (0/1)
Time.at(0.999999).to_r # => (9007190247541737/9007199254740992)

其他检索方法,如 Time#to_iTime#to_f,可能会返回一个四舍五入或截断小数秒的值。

Time Resolution

从系统时钟派生的 Time 对象(例如,通过方法 Time.now)具有系统支持的分辨率。

Time Internal Representation

概念上,Time 类使用有理数来表示自 Epoch(1970-01-01 00:00:00 UTC)以来的秒数。没有边界或分辨率限制。可以使用 Time#to_r 获取该值。

Time 类始终使用格里高利历。即使用预演格里高利历。不支持其他历法,例如儒略历。

实现使用带符号的 63 位整数、Integer(Bignum)对象或有理数对象来表示有理数。 (无论 32 位还是 64 位环境,都使用带符号的 63 位整数。)该值表示自Epoch以来的纳秒数。带符号的 63 位整数可以表示 1823-11-12 到 2116-02-20。当使用 IntegerRational 对象时(1823 年之前、2116 年之后、纳秒精度),Time 的运行速度比使用带符号的 63 位整数时慢。

Ruby 使用 C 函数 `localtime` 和 `gmtime` 来映射数字和 6 元组(年、月、日、时、分、秒)之间的关系。`localtime` 用于本地时间,`gmtime` 用于 UTC。

IntegerRational 没有范围限制,但 localtime 和 gmtime 由于 C 类型 `time_t` 和 `struct tm` 而存在范围限制。如果超出该限制,Ruby 会外推 localtime 函数。

如果 `time_t` 是 32 位带符号整数,则可以表示 1901-12-14 到 2038-01-19;如果它是 64 位带符号整数,则可以表示 -292277022657-01-27 到 292277026596-12-05。但是,某些平台上的 `localtime` 不支持负数 `time_t`(1970 年之前)。

struct tm 有一个 `tm_year` 成员来表示年份。(`tm_year = 0` 表示 1900 年。)它在 C 标准中定义为 `int`。如果 `int` 是 32 位,`tm_year` 可以表示 -2147481748 到 2147485547 之间的年份。

只要 C 函数 `localtime` 和 `gmtime` 支持,Ruby 就支持闰秒。它们在大多数 Unix 系统中使用 tz 数据库。tz 数据库包含支持闰秒的时区。例如,“Asia/Tokyo”不支持闰秒,但“right/Asia/Tokyo”支持闰秒。因此,在大多数 Unix 系统中,如果 TZ 环境变量设置为“right/Asia/Tokyo”,Ruby 就支持闰秒。

示例

所有这些示例均使用 EST 时区(GMT-5)进行。

创建新的 Time 实例

您可以使用 Time.new 创建一个新的 Time 实例。这将使用当前系统时间。Time.now 是它的别名。您还可以将时间的部分参数传递给 Time.new,例如年份、月份、分钟等。当您想以这种方式构建时间时,至少必须传递一个年份。如果您只传递年份而没有其他参数,时间将默认设置为该年的 1 月 1 日,00:00:00,并使用当前的系统时区。以下是一些示例:

Time.new(2002)         #=> 2002-01-01 00:00:00 -0500
Time.new(2002, 10)     #=> 2002-10-01 00:00:00 -0500
Time.new(2002, 10, 31) #=> 2002-10-31 00:00:00 -0500

您可以传递 UTC 偏移量

Time.new(2002, 10, 31, 2, 2, 2, "+02:00") #=> 2002-10-31 02:02:02 +0200

时区对象

zone = timezone("Europe/Athens")      # Eastern European Time, UTC+2
Time.new(2002, 10, 31, 2, 2, 2, zone) #=> 2002-10-31 02:02:02 +0200

您还可以使用 Time.localTime.utc 来推断本地时间和 UTC 时间,而不是使用当前的系统设置。

您还可以使用 Time.at 创建一个新时间,它接受自 Unix Epoch 以来的秒数(包含小数秒)。

Time.at(628232400) #=> 1989-11-28 00:00:00 -0500

使用 Time 实例进行操作

一旦您拥有一个 Time 实例,您就可以对其执行各种操作。以下是一些示例。对于以下所有示例,我们将假设您已执行以下操作:

t = Time.new(1993, 02, 24, 12, 0, 0, "+09:00")

那天是星期一吗?

t.monday? #=> false

那天是哪一年?

t.year #=> 1993

那时是夏令时吗?

t.dst? #=> false

一年后是哪一天?

t + (60*60*24*365) #=> 1994-02-24 12:00:00 +0900

自 Unix Epoch 以来有多少秒?

t.to_i #=> 730522800

您还可以执行标准的函数,例如比较两个时间。

t1 = Time.new(2010)
t2 = Time.new(2011)

t1 == t2 #=> false
t1 == t1 #=> true
t1 <  t2 #=> true
t1 >  t2 #=> false

Time.new(2010,10,31).between?(t1, t2) #=> true

这里有什么

首先,其他内容。类 Time

在这里,类 Time 提供了对以下方面有用的方法:

创建方法

获取元素的方法

查询方法

比较方法

转换方法

四舍五入方法

关于参数 `zone` 的形式,请参阅 Timezone Specifiers

Timezone Specifiers

某些 Time 方法接受指定时区的参数。

使用以上任何一种方法给出的值必须是以下之一(每种都将详细说明):

小时/分钟偏移量

zone 值可以是字符串形式的 UTC 偏移量,格式为 `'+HH:MM'` 或 `'-HH:MM'`,其中:

示例

t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
Time.at(t, in: '-23:59')            # => 1999-12-31 20:16:01 -2359
Time.at(t, in: '+23:59')            # => 2000-01-02 20:14:01 +2359

单字母偏移量

zone 值可以是 'A'..'I' 或 'K'..'Z' 范围内的字母;请参阅 军事时区列表

t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
Time.at(t, in: 'A')                 # => 2000-01-01 21:15:01 +0100
Time.at(t, in: 'I')                 # => 2000-01-02 05:15:01 +0900
Time.at(t, in: 'K')                 # => 2000-01-02 06:15:01 +1000
Time.at(t, in: 'Y')                 # => 2000-01-01 08:15:01 -1200
Time.at(t, in: 'Z')                 # => 2000-01-01 20:15:01 UTC

整数偏移量

zone 值可以是 -86399..86399 范围内的整数秒数。

t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
Time.at(t, in: -86399)              # => 1999-12-31 20:15:02 -235959
Time.at(t, in: 86399)               # => 2000-01-02 20:15:00 +235959

时区对象

zone 值可以是一个响应某些时区方法的对象,例如 TimezoneTZInfo 的实例。

时区方法是:

自定义时区类可能具有这些实例方法,如果已定义,它们将被调用:

Time-Like Objects

一个 Time-like object 是一个能够与时区库进行接口以进行时区转换的容器对象。

上面时区转换方法的参数将具有与 Time 相似的属性,只是与时区相关的属性无意义。

时区对象的 `local_to_utc` 和 `utc_to_local` 方法返回的对象可能是与其参数相同的类、任意对象类或 Integer 类。

对于返回的类(非 Integer),该类必须具有以下方法:

对于返回的 Integer,其组件(以 UTC 分解)被解释为指定时区中的时间。

Timezone Names

如果类(类方法的接收者,或实例方法的接收者的类)具有 `find_timezone` 单例方法,则调用此方法以从时区名称获取相应的时区对象。

例如,使用 Timezone

class TimeWithTimezone < Time
  require 'timezone'
  def self.find_timezone(z) = Timezone[z]
end

TimeWithTimezone.now(in: "America/New_York")        #=> 2023-12-25 00:00:00 -0500
TimeWithTimezone.new("2023-12-25 America/New_York") #=> 2023-12-25 00:00:00 -0500

或者,使用 TZInfo

class TimeWithTZInfo < Time
  require 'tzinfo'
  def self.find_timezone(z) = TZInfo::Timezone.get(z)
end

TimeWithTZInfo.now(in: "America/New_York")          #=> 2023-12-25 00:00:00 -0500
TimeWithTZInfo.new("2023-12-25 America/New_York")   #=> 2023-12-25 00:00:00 -0500

您可以为每个子类定义此方法,或者在顶层的 Time 类上定义。