查看源代码 DateTime (Elixir v1.16.2)

带有时区的日期时间实现。

此日期时间可以看作是在给定时区内日期和时间的快照。为此,它还包括 UTC 和标准偏移量,以及仅用于格式化目的的时区缩写字段。请注意,未来的日期时间不一定保证存在,因为时区可能会因地缘政治原因在将来随时发生变化。有关更多信息,请参阅“日期时间作为快照”部分。

请记住,在 Elixir 中使用 ==/2>/2</2 等进行比较是结构性的,并且基于 DateTime 结构体字段。要对日期时间进行正确的比较,请使用 compare/2 函数。该模块中 compare/2 函数的存在也允许使用 Enum.min/2Enum.max/2 函数来获取 Enum 的最小和最大日期时间。例如

iex> Enum.min([~U[2022-01-12 00:01:00.00Z], ~U[2021-01-12 00:01:00.00Z]], DateTime)
~U[2021-01-12 00:01:00.00Z]

开发人员应避免直接创建 DateTime 结构体,而是依赖于此模块提供的函数以及第三方日历库中的函数。

时区数据库

此模块中的许多函数都需要时区数据库。默认情况下,它使用 Calendar.get_time_zone_database/0 返回的默认时区数据库,该数据库默认为 Calendar.UTCOnlyTimeZoneDatabase,该数据库只处理“Etc/UTC”日期时间,并为任何其他时区返回 {:error, :utc_only_time_zone_database}

也可以配置其他时区数据库。以下是一些可用的选项和库

要使用它们,首先确保将其作为依赖项添加到 mix.exs 中。然后可以通过配置来配置它

config :elixir, :time_zone_database, Tz.TimeZoneDatabase

或者通过调用 Calendar.put_time_zone_database/1

Calendar.put_time_zone_database(Tz.TimeZoneDatabase)

请在库安装说明中查看正确的名称。

日期时间作为快照

在第一节中,我们将日期时间描述为“给定时区内日期和时间的快照”。要确切了解我们的意思,让我们看一个例子。

想象一下,波兰的某个人想在明年与巴西的某个人安排一个会议。会议将在波兰时区的凌晨 2:30 举行。会议将在巴西的什么时候举行?

您可以在一年之前使用此模块中的 API 查询今天的时区数据库,它会给您一个现在有效的答案。但是,这个答案可能在未来无效。为什么?因为巴西和波兰都可能改变它们的时区规则,最终影响结果。例如,一个国家可能会选择进入或放弃“夏令时”,这是一个每年调整一次时钟,将时钟拨快或拨慢一小时的过程。每当规则发生变化时,波兰时间的凌晨 2:30 在巴西的确切时刻都会发生变化。

换句话说,每当处理未来的 DateTime 时,都不能保证您获得的结果始终是正确的,直到事件实际发生为止。因此,当您查询未来时间时,您获得的答案是反映当前时区规则状态的快照。对于过去的日期时间,这不是问题,因为时区规则不会更改过去的事件。

更糟糕的是,波兰时间的凌晨 2:30 实际上可能根本不存在,或者它可能是不确定的。如果某个时区观察“夏令时”,它们会在一年中将时钟拨快一次。当发生这种情况时,将有一整小时不存在。然后,当他们将时钟拨回时,将有一个特定的小时会发生两次。因此,如果您想在时间发生这种变化时安排会议,您需要明确地说出您指的是凌晨 2:30 的哪一次出现:在时间转换之前发生的“夏令时”,还是在时间转换之后发生的“标准时间”。对日期和时间敏感的应用程序需要考虑这些情况,并正确地将它们传达给用户。

好消息是:Elixir 包含解决这些问题所需的所有构建块。Elixir 使用的默认时区数据库 Calendar.UTCOnlyTimeZoneDatabase 只适用于 UTC,不会观察到这些问题。一旦您引入了一个合适的时区数据库,此模块中的函数将查询数据库并返回相关信息。例如,请查看 DateTime.new/4 如何根据本节中描述的情况返回不同的结果。

在时区之间转换

记住上面的注意事项,并假设您已经引入了一个完整的时区数据库,以下是时区之间常见转换的一些示例。

# Local time to UTC
new_york = DateTime.from_naive!(~N[2023-06-26T09:30:00], "America/New_York")
#=> #DateTime<2023-06-26 09:30:00-04:00 EDT America/New_York>

utc = DateTime.shift_zone!(new_york, "Etc/UTC")
#=> ~U[2023-06-26 13:30:00Z]

# UTC to local time
DateTime.shift_zone!(utc, "Europe/Paris")
#=> #DateTime<2023-06-26 15:30:00+02:00 CEST Europe/Paris>

摘要

函数

如果第一个日期时间严格晚于第二个日期时间,则返回 true

如果第一个日期时间严格早于第二个日期时间,则返回 true

比较两个日期时间结构体。

将给定的 datetime 从一个日历转换为另一个日历。

将给定的 datetime 从一个日历转换为另一个日历。

datetime1 中减去 datetime2

将一定数量的格里高利秒转换为 DateTime 结构体。

解析由 ISO 8601:2019 描述的扩展“日期和时间”格式。

从 ISO8601 转换,同时指定日历和模式。

从日期和时间结构体构建日期时间,在出错时引发异常。

返回给定时区中的当前日期时间。

返回给定时区中的当前日期时间,或者在出错时引发异常

DateTime 转换为 Date

DateTime 结构体转换为格里高利秒和微秒数。

将给定的日期时间转换为 ISO 8601:2019 格式。

将给定的 datetime 转换为 NaiveDateTime

根据其日历将给定的 datetime 转换为字符串。

DateTime 转换为 Time

将给定的 datetime 转换为 Unix 时间。

返回给定的日期时间,其中微秒字段截断到给定的精度(:microsecond:millisecond:second)。

返回 UTC 中的当前日期时间。

返回 UTC 中的当前日期时间,支持特定日历和精度。

类型

@type t() :: %DateTime{
  calendar: Calendar.calendar(),
  day: Calendar.day(),
  hour: Calendar.hour(),
  microsecond: Calendar.microsecond(),
  minute: Calendar.minute(),
  month: Calendar.month(),
  second: Calendar.second(),
  std_offset: Calendar.std_offset(),
  time_zone: Calendar.time_zone(),
  utc_offset: Calendar.utc_offset(),
  year: Calendar.year(),
  zone_abbr: Calendar.zone_abbr()
}

函数

链接到此函数

add(datetime, amount_to_add, unit \\ :second, time_zone_database \\ Calendar.get_time_zone_database())

查看源代码 (自 1.8.0 起)
@spec add(
  Calendar.datetime(),
  integer(),
  :day | :hour | :minute | System.time_unit(),
  Calendar.time_zone_database()
) :: t()

将指定的时间量添加到 DateTime 中。

接受以任何 unit 表示的 amount_to_addunit 可以是 :day:hour:minute:second 或来自 System.time_unit/0 的任何亚秒精度。它默认为 :second。负值将向时间倒退。

此函数始终考虑根据 Calendar.ISO 计算的单位。

此函数依赖于时间的连续表示,忽略墙时间和时区变化。例如,如果您在有夏令时/夏令时变化时添加一天,它还会将时间向前或向后更改一小时,因此经过的时间正好是 24 小时。类似地,在“春季前进”之前将几秒钟添加到日期时间会导致墙时间增加超过一小时。

虽然这意味着该函数在经过时间方面是精确的,但在某些用例中其结果可能会产生误导。例如,如果用户请求每天 15:00 举行会议,并且您使用此函数通过逐日添加来计算所有未来的会议,那么如果当前时区发生更改,此函数可能会将会议时间更改为 14:00 或 16:00。Elixir 的标准库目前不支持重复日期时间的计算,但第三方库可以提供此功能。

示例

iex> dt = DateTime.from_naive!(~N[2018-11-15 10:00:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> dt |> DateTime.add(3600, :second, FakeTimeZoneDatabase)
#DateTime<2018-11-15 11:00:00+01:00 CET Europe/Copenhagen>

iex> DateTime.add(~U[2018-11-15 10:00:00Z], 3600, :second)
~U[2018-11-15 11:00:00Z]

在“春季向前”之前添加 3 秒时,我们会从 1:59:59 变为 3:00:02

iex> dt = DateTime.from_naive!(~N[2019-03-31 01:59:59.123], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> dt |> DateTime.add(3, :second, FakeTimeZoneDatabase)
#DateTime<2019-03-31 03:00:02.123+02:00 CEST Europe/Copenhagen>

在“春季向前”期间添加 1 天,小时也会改变

iex> dt = DateTime.from_naive!(~N[2019-03-31 01:00:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> dt |> DateTime.add(1, :day, FakeTimeZoneDatabase)
#DateTime<2019-04-01 02:00:00+02:00 CEST Europe/Copenhagen>

此操作将原始日期时间精度与给定单位合并

iex> result = DateTime.add(~U[2014-10-02 00:29:10Z], 21, :millisecond)
~U[2014-10-02 00:29:10.021Z]
iex> result.microsecond
{21000, 3}
链接到此函数

after?(datetime1, datetime2)

查看源代码 (自 1.15.0 起)
@spec after?(Calendar.datetime(), Calendar.datetime()) :: boolean()

如果第一个日期时间严格晚于第二个日期时间,则返回 true

示例

iex> DateTime.after?(~U[2022-02-02 11:00:00Z], ~U[2021-01-01 11:00:00Z])
true
iex> DateTime.after?(~U[2021-01-01 11:00:00Z], ~U[2021-01-01 11:00:00Z])
false
iex> DateTime.after?(~U[2021-01-01 11:00:00Z], ~U[2022-02-02 11:00:00Z])
false
链接到此函数

before?(datetime1, datetime2)

查看源代码 (自 1.15.0 起)
@spec before?(Calendar.datetime(), Calendar.datetime()) :: boolean()

如果第一个日期时间严格早于第二个日期时间,则返回 true

示例

iex> DateTime.before?(~U[2021-01-01 11:00:00Z], ~U[2022-02-02 11:00:00Z])
true
iex> DateTime.before?(~U[2021-01-01 11:00:00Z], ~U[2021-01-01 11:00:00Z])
false
iex> DateTime.before?(~U[2022-02-02 11:00:00Z], ~U[2021-01-01 11:00:00Z])
false
链接到此函数

compare(datetime1, datetime2)

查看源代码 (自 1.4.0 起)
@spec compare(Calendar.datetime(), Calendar.datetime()) :: :lt | :eq | :gt

比较两个日期时间结构体。

如果第一个日期时间晚于第二个日期时间,则返回 :gt,反之返回 :lt。如果两个日期时间相等,则返回 :eq

请注意,比较时将考虑 UTC 和标准偏移量。

示例

iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT",
...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                 utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"}
iex> dt2 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET",
...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                 utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"}
iex> DateTime.compare(dt1, dt2)
:gt
链接到此函数

convert(datetime, calendar)

查看源代码 (自 1.5.0 起)
@spec convert(Calendar.datetime(), Calendar.calendar()) ::
  {:ok, t()} | {:error, :incompatible_calendars}

将给定的 datetime 从一个日历转换为另一个日历。

如果无法在日历之间进行明确的转换(请参阅 Calendar.compatible_calendars?/2),则返回 {:error, :incompatible_calendars} 元组。

示例

假设有人实现了 Calendar.Holocene,这是一个基于公历的日历,它将当前公历年份增加了正好 10000 年

iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT",
...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                 utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"}
iex> DateTime.convert(dt1, Calendar.Holocene)
{:ok, %DateTime{calendar: Calendar.Holocene, day: 29, hour: 23,
                microsecond: {0, 0}, minute: 0, month: 2, second: 7, std_offset: 0,
                time_zone: "America/Manaus", utc_offset: -14400, year: 12000,
                zone_abbr: "AMT"}}
链接到此函数

convert!(datetime, calendar)

查看源代码 (自 1.5.0 起)
@spec convert!(Calendar.datetime(), Calendar.calendar()) :: t()

将给定的 datetime 从一个日历转换为另一个日历。

如果无法在日历之间进行明确的转换(请参阅 Calendar.compatible_calendars?/2),则会引发 ArgumentError。

示例

假设有人实现了 Calendar.Holocene,这是一个基于公历的日历,它将当前公历年份增加了正好 10000 年

iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT",
...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                 utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"}
iex> DateTime.convert!(dt1, Calendar.Holocene)
%DateTime{calendar: Calendar.Holocene, day: 29, hour: 23,
          microsecond: {0, 0}, minute: 0, month: 2, second: 7, std_offset: 0,
          time_zone: "America/Manaus", utc_offset: -14400, year: 12000,
          zone_abbr: "AMT"}
链接到此函数

diff(datetime1, datetime2, unit \\ :second)

查看源代码 (自 1.5.0 起)
@spec diff(
  Calendar.datetime(),
  Calendar.datetime(),
  :day | :hour | :minute | System.time_unit()
) :: integer()

datetime1 中减去 datetime2

答案可以以任何 :day:hour:minute 或任何来自 System.time_unit/0unit 返回。该单位根据 Calendar.ISO 测量,默认值为 :second

不支持小数结果,并将其截断。

示例

iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT",
...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                 utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"}
iex> dt2 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET",
...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                 utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"}
iex> DateTime.diff(dt1, dt2)
18000
iex> DateTime.diff(dt2, dt1)
-18000
iex> DateTime.diff(dt1, dt2, :hour)
5
iex> DateTime.diff(dt2, dt1, :hour)
-5
链接到此函数

from_gregorian_seconds(seconds, arg \\ {0, 0}, calendar \\ Calendar.ISO)

查看源代码 (自 1.11.0 起)
@spec from_gregorian_seconds(integer(), Calendar.microsecond(), Calendar.calendar()) ::
  t()

将一定数量的格里高利秒转换为 DateTime 结构体。

返回的 DateTime 将具有 UTC 时区,如果您想要其他时区,请使用 DateTime.shift_zone/3

示例

iex> DateTime.from_gregorian_seconds(1)
~U[0000-01-01 00:00:01Z]
iex> DateTime.from_gregorian_seconds(63_755_511_991, {5000, 3})
~U[2020-05-01 00:26:31.005Z]
iex> DateTime.from_gregorian_seconds(-1)
~U[-0001-12-31 23:59:59Z]
链接到此函数

from_iso8601(string, format_or_calendar \\ Calendar.ISO)

查看源代码 (自 1.4.0 起)
@spec from_iso8601(String.t(), Calendar.calendar() | :extended | :basic) ::
  {:ok, t(), Calendar.utc_offset()} | {:error, atom()}

解析由 ISO 8601:2019 描述的扩展“日期和时间”格式。

由于 ISO 8601 不包含正确的时区,因此给定字符串将转换为 UTC,其秒偏移量将作为此函数的一部分返回。因此,字符串中必须存在偏移信息。

如标准中所述,如果需要,可以省略分隔符“T”,因为在此函数中没有歧义。

请注意,内置的 Calendar.ISO 不支持闰秒。

示例

iex> {:ok, datetime, 0} = DateTime.from_iso8601("2015-01-23T23:50:07Z")
iex> datetime
~U[2015-01-23 23:50:07Z]

iex> {:ok, datetime, 9000} = DateTime.from_iso8601("2015-01-23T23:50:07.123+02:30")
iex> datetime
~U[2015-01-23 21:20:07.123Z]

iex> {:ok, datetime, 9000} = DateTime.from_iso8601("2015-01-23T23:50:07,123+02:30")
iex> datetime
~U[2015-01-23 21:20:07.123Z]

iex> {:ok, datetime, 0} = DateTime.from_iso8601("-2015-01-23T23:50:07Z")
iex> datetime
~U[-2015-01-23 23:50:07Z]

iex> {:ok, datetime, 9000} = DateTime.from_iso8601("-2015-01-23T23:50:07,123+02:30")
iex> datetime
~U[-2015-01-23 21:20:07.123Z]

iex> {:ok, datetime, 9000} = DateTime.from_iso8601("20150123T235007.123+0230", :basic)
iex> datetime
~U[2015-01-23 21:20:07.123Z]

iex> DateTime.from_iso8601("2015-01-23P23:50:07")
{:error, :invalid_format}
iex> DateTime.from_iso8601("2015-01-23T23:50:07")
{:error, :missing_offset}
iex> DateTime.from_iso8601("2015-01-23 23:50:61")
{:error, :invalid_time}
iex> DateTime.from_iso8601("2015-01-32 23:50:07")
{:error, :invalid_date}
iex> DateTime.from_iso8601("2015-01-23T23:50:07.123-00:00")
{:error, :invalid_format}
链接到此函数

from_iso8601(string, calendar, format)

查看源代码
@spec from_iso8601(String.t(), Calendar.calendar(), :extended | :basic) ::
  {:ok, t(), Calendar.utc_offset()} | {:error, atom()}

从 ISO8601 转换,同时指定日历和模式。

有关更多信息,请参阅 from_iso8601/2

示例

iex> {:ok, datetime, 9000} = DateTime.from_iso8601("2015-01-23T23:50:07,123+02:30", Calendar.ISO, :extended)
iex> datetime
~U[2015-01-23 21:20:07.123Z]

iex> {:ok, datetime, 9000} = DateTime.from_iso8601("20150123T235007.123+0230", Calendar.ISO, :basic)
iex> datetime
~U[2015-01-23 21:20:07.123Z]
链接到此函数

from_naive(naive_datetime, time_zone, time_zone_database \\ Calendar.get_time_zone_database())

查看源代码 (自 1.4.0 起)
@spec from_naive(
  Calendar.naive_datetime(),
  Calendar.time_zone(),
  Calendar.time_zone_database()
) ::
  {:ok, t()}
  | {:ambiguous, first_datetime :: t(), second_datetime :: t()}
  | {:gap, t(), t()}
  | {:error,
     :incompatible_calendars
     | :time_zone_not_found
     | :utc_only_time_zone_database}

将给定的 NaiveDateTime 转换为 DateTime

它期望一个时区来放置 NaiveDateTime。如果时区为“Etc/UTC”,则始终成功。否则,将根据作为 time_zone_database 给出的时区数据库检查 NaiveDateTime。请参阅模块文档中的“时区数据库”部分。

示例

iex> DateTime.from_naive(~N[2016-05-24 13:26:08.003], "Etc/UTC")
{:ok, ~U[2016-05-24 13:26:08.003Z]}

当日期时间不明确时 - 例如在从夏季时间转换为冬季时间期间 - 两个可能的有效日期时间将以元组形式返回。第一个日期时间也是时间顺序上第一个的日期时间,而第二个日期时间则是最后一个。

iex> {:ambiguous, first_dt, second_dt} = DateTime.from_naive(~N[2018-10-28 02:30:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> first_dt
#DateTime<2018-10-28 02:30:00+02:00 CEST Europe/Copenhagen>
iex> second_dt
#DateTime<2018-10-28 02:30:00+01:00 CET Europe/Copenhagen>

当存在墙壁时间间隙时 - 例如在春季将时钟拨快时 - 间隙之前的最新有效日期时间和间隙之后的第一个有效日期时间。

iex> {:gap, just_before, just_after} = DateTime.from_naive(~N[2019-03-31 02:30:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> just_before
#DateTime<2019-03-31 01:59:59.999999+01:00 CET Europe/Copenhagen>
iex> just_after
#DateTime<2019-03-31 03:00:00+02:00 CEST Europe/Copenhagen>

大多数情况下,在特定时区内,特定日期和时间的有效日期时间只有一个。

iex> {:ok, datetime} = DateTime.from_naive(~N[2018-07-28 12:30:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> datetime
#DateTime<2018-07-28 12:30:00+02:00 CEST Europe/Copenhagen>

此函数接受任何包含至少与 NaiveDateTime 结构相同的字段的映射或结构。最常见的示例是 DateTime。在这种情况下,完全忽略有关该 DateTime 时区的信息。这与将 DateTime 传递给 Date.to_iso8601/2 的原理相同。 Date.to_iso8601/2 仅提取给定结构的日期特定字段(日历、年份、月份和日期),并忽略所有其他字段。

这样,如果您在某个时区内有一个 DateTime,则可以在另一个时区内获得相同的墙壁时间。例如,如果您在哥本哈根拥有 2018-08-24 10:00:00,并且想要一个 DateTime 用于 UTC 时间的 2018-08-24 10:00:00,则可以执行以下操作

iex> cph_datetime = DateTime.from_naive!(~N[2018-08-24 10:00:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> {:ok, utc_datetime} = DateTime.from_naive(cph_datetime, "Etc/UTC", FakeTimeZoneDatabase)
iex> utc_datetime
~U[2018-08-24 10:00:00Z]

如果您想要一个 DateTime 用于不同时区内的相同时间点,请参阅 DateTime.shift_zone/3 函数,该函数会将哥本哈根的 2018-08-24 10:00:00 转换为 UTC 的 2018-08-24 08:00:00。

链接到此函数

from_naive!(naive_datetime, time_zone, time_zone_database \\ Calendar.get_time_zone_database())

查看源代码 (自 1.4.0 起)

将给定的 NaiveDateTime 转换为 DateTime

它期望一个时区来放置 NaiveDateTime。如果时区为“Etc/UTC”,则始终成功。否则,将根据作为 time_zone_database 给出的时区数据库检查 NaiveDateTime。请参阅模块文档中的“时区数据库”部分。

示例

iex> DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC")
~U[2016-05-24 13:26:08.003Z]

iex> DateTime.from_naive!(~N[2018-05-24 13:26:08.003], "Europe/Copenhagen", FakeTimeZoneDatabase)
#DateTime<2018-05-24 13:26:08.003+02:00 CEST Europe/Copenhagen>
链接到此函数

from_unix(integer, unit \\ :second, calendar \\ Calendar.ISO)

查看源代码
@spec from_unix(integer(), :native | System.time_unit(), Calendar.calendar()) ::
  {:ok, t()} | {:error, atom()}

将给定的 Unix 时间转换为 DateTime

整数可以根据 System.convert_time_unit/3 以不同的单位给出,它将在内部转换为微秒。支持最多 253402300799 秒。

Unix 时间始终为 UTC,因此将以 UTC 返回 DateTime。

示例

iex> {:ok, datetime} = DateTime.from_unix(1_464_096_368)
iex> datetime
~U[2016-05-24 13:26:08Z]

iex> {:ok, datetime} = DateTime.from_unix(1_432_560_368_868_569, :microsecond)
iex> datetime
~U[2015-05-25 13:26:08.868569Z]

iex> {:ok, datetime} = DateTime.from_unix(253_402_300_799)
iex> datetime
~U[9999-12-31 23:59:59Z]

iex> {:error, :invalid_unix_time} = DateTime.from_unix(253_402_300_800)

该单位也可以是整数,如 System.time_unit/0 中所示

iex> {:ok, datetime} = DateTime.from_unix(143_256_036_886_856, 1024)
iex> datetime
~U[6403-03-17 07:05:22.320312Z]

支持负 Unix 时间,最长可达 -377705116800 秒

iex> {:ok, datetime} = DateTime.from_unix(-377_705_116_800)
iex> datetime
~U[-9999-01-01 00:00:00Z]

iex> {:error, :invalid_unix_time} = DateTime.from_unix(-377_705_116_801)
链接到此函数

from_unix!(integer, unit \\ :second, calendar \\ Calendar.ISO)

查看源代码
@spec from_unix!(integer(), :native | System.time_unit(), Calendar.calendar()) :: t()

将给定的 Unix 时间转换为 DateTime

整数可以根据 System.convert_time_unit/3 以不同的单位给出,它将在内部转换为微秒。

Unix 时间始终为 UTC,因此将以 UTC 返回 DateTime。

示例

# An easy way to get the Unix epoch is passing 0 to this function
iex> DateTime.from_unix!(0)
~U[1970-01-01 00:00:00Z]

iex> DateTime.from_unix!(1_464_096_368)
~U[2016-05-24 13:26:08Z]

iex> DateTime.from_unix!(1_432_560_368_868_569, :microsecond)
~U[2015-05-25 13:26:08.868569Z]

iex> DateTime.from_unix!(143_256_036_886_856, 1024)
~U[6403-03-17 07:05:22.320312Z]
链接到此函数

new(date, time, time_zone \\ "Etc/UTC", time_zone_database \\ Calendar.get_time_zone_database())

查看源代码 (自 1.11.0 起)
@spec new(Date.t(), Time.t(), Calendar.time_zone(), Calendar.time_zone_database()) ::
  {:ok, t()}
  | {:ambiguous, first_datetime :: t(), second_datetime :: t()}
  | {:gap, t(), t()}
  | {:error,
     :incompatible_calendars
     | :time_zone_not_found
     | :utc_only_time_zone_database}

从日期和时间结构体构建日期时间。

它期望一个时区来放置 DateTime。如果没有传递时区,则默认为 "Etc/UTC",这始终成功。否则,将根据作为 time_zone_database 给出的时区数据库检查 DateTime。请参阅模块文档中的“时区数据库”部分。

示例

iex> DateTime.new(~D[2016-05-24], ~T[13:26:08.003], "Etc/UTC")
{:ok, ~U[2016-05-24 13:26:08.003Z]}

当日期时间不明确时 - 例如在从夏季时间转换为冬季时间期间 - 两个可能的有效日期时间将以元组形式返回。第一个日期时间也是时间顺序上第一个的日期时间,而第二个日期时间则是最后一个。

iex> {:ambiguous, first_dt, second_dt} = DateTime.new(~D[2018-10-28], ~T[02:30:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> first_dt
#DateTime<2018-10-28 02:30:00+02:00 CEST Europe/Copenhagen>
iex> second_dt
#DateTime<2018-10-28 02:30:00+01:00 CET Europe/Copenhagen>

当存在墙壁时间间隙时 - 例如在春季将时钟拨快时 - 间隙之前的最新有效日期时间和间隙之后的第一个有效日期时间。

iex> {:gap, just_before, just_after} = DateTime.new(~D[2019-03-31], ~T[02:30:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> just_before
#DateTime<2019-03-31 01:59:59.999999+01:00 CET Europe/Copenhagen>
iex> just_after
#DateTime<2019-03-31 03:00:00+02:00 CEST Europe/Copenhagen>

大多数情况下,在特定时区内,特定日期和时间的有效日期时间只有一个。

iex> {:ok, datetime} = DateTime.new(~D[2018-07-28], ~T[12:30:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> datetime
#DateTime<2018-07-28 12:30:00+02:00 CEST Europe/Copenhagen>
链接到此函数

new!(date, time, time_zone \\ "Etc/UTC", time_zone_database \\ Calendar.get_time_zone_database())

查看源代码 (自 1.11.0 起)

从日期和时间结构体构建日期时间,在出错时引发异常。

它期望一个时区来放置 DateTime。如果没有传递时区,则默认为 "Etc/UTC",这始终成功。否则,将根据作为 time_zone_database 给出的时区数据库检查 DateTime。请参阅模块文档中的“时区数据库”部分。

示例

iex> DateTime.new!(~D[2016-05-24], ~T[13:26:08.003], "Etc/UTC")
~U[2016-05-24 13:26:08.003Z]

当日期时间不明确时 - 例如在从夏季时间转换为冬季时间期间 - 会引发错误。

iex> DateTime.new!(~D[2018-10-28], ~T[02:30:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
** (ArgumentError) cannot build datetime with ~D[2018-10-28] and ~T[02:30:00] because such instant is ambiguous in time zone Europe/Copenhagen as there is an overlap between #DateTime<2018-10-28 02:30:00+02:00 CEST Europe/Copenhagen> and #DateTime<2018-10-28 02:30:00+01:00 CET Europe/Copenhagen>

当存在墙壁时间间隙时 - 例如在春季将时钟拨快时 - 会引发错误。

iex> DateTime.new!(~D[2019-03-31], ~T[02:30:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
** (ArgumentError) cannot build datetime with ~D[2019-03-31] and ~T[02:30:00] because such instant does not exist in time zone Europe/Copenhagen as there is a gap between #DateTime<2019-03-31 01:59:59.999999+01:00 CET Europe/Copenhagen> and #DateTime<2019-03-31 03:00:00+02:00 CEST Europe/Copenhagen>

大多数情况下,在特定时区内,特定日期和时间的有效日期时间只有一个。

iex> datetime = DateTime.new!(~D[2018-07-28], ~T[12:30:00], "Europe/Copenhagen", FakeTimeZoneDatabase)
iex> datetime
#DateTime<2018-07-28 12:30:00+02:00 CEST Europe/Copenhagen>
链接到此函数

now(time_zone, time_zone_database \\ Calendar.get_time_zone_database())

查看源代码 (自 1.8.0 起)
@spec now(Calendar.time_zone(), Calendar.time_zone_database()) ::
  {:ok, t()} | {:error, :time_zone_not_found | :utc_only_time_zone_database}

返回给定时区中的当前日期时间。

默认情况下,它使用 Calendar.get_time_zone_database/0 返回的默认时区,该时区默认为 Calendar.UTCOnlyTimeZoneDatabase,它只处理“Etc/UTC”日期时间。其他时区数据库可以作为参数传递或全局设置。请参阅模块文档中的“时区数据库”部分。

示例

iex> {:ok, datetime} = DateTime.now("Etc/UTC")
iex> datetime.time_zone
"Etc/UTC"

iex> DateTime.now("Europe/Copenhagen")
{:error, :utc_only_time_zone_database}

iex> DateTime.now("bad timezone", FakeTimeZoneDatabase)
{:error, :time_zone_not_found}
链接到此函数

now!(time_zone, time_zone_database \\ Calendar.get_time_zone_database())

查看源代码 (自 1.10.0 起)

返回给定时区中的当前日期时间,或者在出错时引发异常

有关更多信息,请参阅 now/2

示例

iex> datetime = DateTime.now!("Etc/UTC")
iex> datetime.time_zone
"Etc/UTC"

iex> DateTime.now!("Europe/Copenhagen")
** (ArgumentError) cannot get current datetime in "Europe/Copenhagen" time zone, reason: :utc_only_time_zone_database

iex> DateTime.now!("bad timezone", FakeTimeZoneDatabase)
** (ArgumentError) cannot get current datetime in "bad timezone" time zone, reason: :time_zone_not_found
链接到此函数

shift_zone(datetime, time_zone, time_zone_database \\ Calendar.get_time_zone_database())

查看源代码 (自 1.8.0 起)
@spec shift_zone(t(), Calendar.time_zone(), Calendar.time_zone_database()) ::
  {:ok, t()} | {:error, :time_zone_not_found | :utc_only_time_zone_database}

更改 DateTime 的时区。

返回一个 DateTime,其时间点相同,但时区不同。 假设 DateTime 在给定的时区和日历中有效且存在。

默认情况下,它使用 Calendar.get_time_zone_database/0 返回的默认时区数据库,默认值为 Calendar.UTCOnlyTimeZoneDatabase,它只处理 "Etc/UTC" 日期时间。 其他时区数据库可以作为参数传递或全局设置。 请参阅模块文档中的 "时区数据库" 部分。

示例

iex> {:ok, pacific_datetime} = DateTime.shift_zone(~U[2018-07-16 10:00:00Z], "America/Los_Angeles", FakeTimeZoneDatabase)
iex> pacific_datetime
#DateTime<2018-07-16 03:00:00-07:00 PDT America/Los_Angeles>

iex> DateTime.shift_zone(~U[2018-07-16 10:00:00Z], "bad timezone", FakeTimeZoneDatabase)
{:error, :time_zone_not_found}
链接到此函数

shift_zone!(datetime, time_zone, time_zone_database \\ Calendar.get_time_zone_database())

查看源代码 (自 1.10.0 起)
@spec shift_zone!(t(), Calendar.time_zone(), Calendar.time_zone_database()) :: t()

更改 DateTime 的时区,或者在出错时引发异常。

有关更多信息,请参阅 shift_zone/3

示例

iex> DateTime.shift_zone!(~U[2018-07-16 10:00:00Z], "America/Los_Angeles", FakeTimeZoneDatabase)
#DateTime<2018-07-16 03:00:00-07:00 PDT America/Los_Angeles>

iex> DateTime.shift_zone!(~U[2018-07-16 10:00:00Z], "bad timezone", FakeTimeZoneDatabase)
** (ArgumentError) cannot shift ~U[2018-07-16 10:00:00Z] to "bad timezone" time zone, reason: :time_zone_not_found
@spec to_date(Calendar.datetime()) :: Date.t()

DateTime 转换为 Date

因为 Date 不包含时间或时区信息,所以数据将在转换期间丢失。

示例

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"}
iex> DateTime.to_date(dt)
~D[2000-02-29]
链接到此函数

to_gregorian_seconds(datetime)

查看源代码 (自 1.11.0 起)
@spec to_gregorian_seconds(Calendar.datetime()) :: {integer(), non_neg_integer()}

DateTime 结构体转换为格里高利秒和微秒数。

示例

iex> dt = %DateTime{year: 0000, month: 1, day: 1, zone_abbr: "UTC",
...>                hour: 0, minute: 0, second: 1, microsecond: {0, 0},
...>                utc_offset: 0, std_offset: 0, time_zone: "Etc/UTC"}
iex> DateTime.to_gregorian_seconds(dt)
{1, 0}

iex> dt = %DateTime{year: 2020, month: 5, day: 1, zone_abbr: "UTC",
...>                hour: 0, minute: 26, second: 31, microsecond: {5000, 0},
...>                utc_offset: 0, std_offset: 0, time_zone: "Etc/UTC"}
iex> DateTime.to_gregorian_seconds(dt)
{63_755_511_991, 5000}

iex> dt = %DateTime{year: 2020, month: 5, day: 1, zone_abbr: "CET",
...>                hour: 1, minute: 26, second: 31, microsecond: {5000, 0},
...>                utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"}
iex> DateTime.to_gregorian_seconds(dt)
{63_755_511_991, 5000}
链接到此函数

to_iso8601(datetime, format \\ :extended, offset \\ nil)

查看源代码
@spec to_iso8601(Calendar.datetime(), :basic | :extended, nil | integer()) ::
  String.t()

将给定的日期时间转换为 ISO 8601:2019 格式。

默认情况下,DateTime.to_iso8601/2 以 "扩展" 格式返回日期时间,以提高人类可读性。 它还通过传递 :basic 选项来支持 "基本" 格式。

只支持转换处于 ISO 日历中的日期时间,尝试转换来自其他日历的日期时间将引发错误。 您还可以选择为格式化字符串指定偏移量。

警告:ISO 8601 日期时间格式不包含时区或其缩写,这意味着在转换为此格式时会丢失信息。

示例

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"}
iex> DateTime.to_iso8601(dt)
"2000-02-29T23:00:07+01:00"

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "UTC",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: 0, std_offset: 0, time_zone: "Etc/UTC"}
iex> DateTime.to_iso8601(dt)
"2000-02-29T23:00:07Z"

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"}
iex> DateTime.to_iso8601(dt, :extended)
"2000-02-29T23:00:07-04:00"

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"}
iex> DateTime.to_iso8601(dt, :basic)
"20000229T230007-0400"

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"}
iex> DateTime.to_iso8601(dt, :extended, 3600)
"2000-03-01T04:00:07+01:00"

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"}
iex> DateTime.to_iso8601(dt, :extended, 0)
"2000-03-01T03:00:07+00:00"

iex> dt = %DateTime{year: 2000, month: 3, day: 01, zone_abbr: "UTC",
...>                hour: 03, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: 0, std_offset: 0, time_zone: "Etc/UTC"}
iex> DateTime.to_iso8601(dt, :extended, 0)
"2000-03-01T03:00:07Z"

iex> {:ok, dt, offset} = DateTime.from_iso8601("2000-03-01T03:00:07Z")
iex> "2000-03-01T03:00:07Z" = DateTime.to_iso8601(dt, :extended, offset)
@spec to_naive(Calendar.datetime()) :: NaiveDateTime.t()

将给定的 datetime 转换为 NaiveDateTime

因为 NaiveDateTime 不包含时区信息,所以任何与时区相关的数据将在转换期间丢失。

示例

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 1},
...>                utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"}
iex> DateTime.to_naive(dt)
~N[2000-02-29 23:00:07.0]
@spec to_string(Calendar.datetime()) :: String.t()

根据其日历将给定的 datetime 转换为字符串。

示例

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"}
iex> DateTime.to_string(dt)
"2000-02-29 23:00:07+01:00 CET Europe/Warsaw"

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "UTC",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: 0, std_offset: 0, time_zone: "Etc/UTC"}
iex> DateTime.to_string(dt)
"2000-02-29 23:00:07Z"

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 0},
...>                utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"}
iex> DateTime.to_string(dt)
"2000-02-29 23:00:07-04:00 AMT America/Manaus"

iex> dt = %DateTime{year: -100, month: 12, day: 19, zone_abbr: "CET",
...>                hour: 3, minute: 20, second: 31, microsecond: {0, 0},
...>                utc_offset: 3600, std_offset: 0, time_zone: "Europe/Stockholm"}
iex> DateTime.to_string(dt)
"-0100-12-19 03:20:31+01:00 CET Europe/Stockholm"
@spec to_time(Calendar.datetime()) :: Time.t()

DateTime 转换为 Time

因为 Time 不包含日期或时区信息,所以数据将在转换期间丢失。

示例

iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET",
...>                hour: 23, minute: 0, second: 7, microsecond: {0, 1},
...>                utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"}
iex> DateTime.to_time(dt)
~T[23:00:07.0]
链接到此函数

to_unix(datetime, unit \\ :second)

查看源代码
@spec to_unix(Calendar.datetime(), System.time_unit()) :: integer()

将给定的 datetime 转换为 Unix 时间。

预期 datetime 使用 ISO 日历,年份大于或等于 0。

它将根据 System.convert_time_unit/3 返回具有给定单位的整数。

示例

iex> 1_464_096_368 |> DateTime.from_unix!() |> DateTime.to_unix()
1464096368

iex> dt = %DateTime{calendar: Calendar.ISO, day: 20, hour: 18, microsecond: {273806, 6},
...>                minute: 58, month: 11, second: 19, time_zone: "America/Montevideo",
...>                utc_offset: -10800, std_offset: 3600, year: 2014, zone_abbr: "UYST"}
iex> DateTime.to_unix(dt)
1416517099

iex> flamel = %DateTime{calendar: Calendar.ISO, day: 22, hour: 8, microsecond: {527771, 6},
...>                minute: 2, month: 3, second: 25, std_offset: 0, time_zone: "Etc/UTC",
...>                utc_offset: 0, year: 1418, zone_abbr: "UTC"}
iex> DateTime.to_unix(flamel)
-17412508655
链接到此函数

truncate(datetime, precision)

查看源代码 (自 1.6.0 起)
@spec truncate(Calendar.datetime(), :microsecond | :millisecond | :second) :: t()

返回给定的日期时间,其中微秒字段截断到给定的精度(:microsecond:millisecond:second)。

如果给定的日期时间已经具有比给定精度低的精度,则返回该日期时间不变。

示例

iex> dt1 = %DateTime{year: 2017, month: 11, day: 7, zone_abbr: "CET",
...>                 hour: 11, minute: 45, second: 18, microsecond: {123456, 6},
...>                 utc_offset: 3600, std_offset: 0, time_zone: "Europe/Paris"}
iex> DateTime.truncate(dt1, :microsecond)
#DateTime<2017-11-07 11:45:18.123456+01:00 CET Europe/Paris>

iex> dt2 = %DateTime{year: 2017, month: 11, day: 7, zone_abbr: "CET",
...>                 hour: 11, minute: 45, second: 18, microsecond: {123456, 6},
...>                 utc_offset: 3600, std_offset: 0, time_zone: "Europe/Paris"}
iex> DateTime.truncate(dt2, :millisecond)
#DateTime<2017-11-07 11:45:18.123+01:00 CET Europe/Paris>

iex> dt3 = %DateTime{year: 2017, month: 11, day: 7, zone_abbr: "CET",
...>                 hour: 11, minute: 45, second: 18, microsecond: {123456, 6},
...>                 utc_offset: 3600, std_offset: 0, time_zone: "Europe/Paris"}
iex> DateTime.truncate(dt3, :second)
#DateTime<2017-11-07 11:45:18+01:00 CET Europe/Paris>
链接到此函数

utc_now(calendar_or_time_unit \\ Calendar.ISO)

查看源代码
@spec utc_now(Calendar.calendar() | :native | :microsecond | :millisecond | :second) ::
  t()

返回 UTC 中的当前日期时间。

如果您想要以 Unix 秒为单位的当前时间,请改用 System.os_time/1

您还可以传递一个时间单位以自动截断生成的日期时间。 此功能自 v1.15.0 起可用。

示例

iex> datetime = DateTime.utc_now()
iex> datetime.time_zone
"Etc/UTC"

iex> datetime = DateTime.utc_now(:second)
iex> datetime.microsecond
{0, 0}
链接到此函数

utc_now(time_unit, calendar)

查看源代码 (自 1.15.0 起)
@spec utc_now(:native | :microsecond | :millisecond | :second, Calendar.calendar()) ::
  t()

返回 UTC 中的当前日期时间,支持特定日历和精度。

如果您想要以 Unix 秒为单位的当前时间,请改用 System.os_time/1

示例

iex> datetime = DateTime.utc_now(:microsecond, Calendar.ISO)
iex> datetime.time_zone
"Etc/UTC"

iex> datetime = DateTime.utc_now(:second, Calendar.ISO)
iex> datetime.microsecond
{0, 0}