檢視原始碼 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 在巴西的確切時間可能會變更。

換句話說,每當使用未來的日期時間時,在事件實際發生之前,無法保證您獲得的結果始終正確。因此,當您詢問未來時間時,您獲得的答案是反映時區規則目前狀態的快照。對於過去的日期時間,這不是問題,因為時區規則不會變更過去的事件。

更糟的是,波蘭時間的凌晨 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>

摘要

函式

如果第一個 datetime 嚴格晚於第二個,則傳回 true

如果第一個 datetime 嚴格早於第二個,則傳回 true

比較兩個 datetime 結構。

將給定的 datetime 從一個日曆轉換到另一個日曆。

將給定的 datetime 從一個日曆轉換到另一個日曆。

datetime1 減去 datetime2

解析 ISO 8601:2019 所描述的「日期和時間」格式。

從 ISO8601 轉換,同時指定日曆和模式。

從日期和時間結構建立 datetime,並在發生錯誤時引發錯誤。

傳回提供時區中的目前日期時間。

傳回提供時區中的目前日期時間,或在發生錯誤時引發錯誤。

DateTime 結構轉換成格里曆秒數和微秒數。

將指定的 datetime 轉換成 NaiveDateTime

根據其日曆將指定的 datetime 轉換成字串。

將指定的 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:secondSystem.time_unit/0 中的任何子秒精度。它預設為 :second。負值將在時間上向後移動。

此函數始終考慮根據 Calendar.ISO 計算的單位。

此函數依賴於時間的連續表示,忽略牆上時間和時區變化。例如,如果您在夏令時間/日光節約時間變更時增加一天,它還會將時間向前或向後更改一小時,因此經過時間恰好為 24 小時。同樣,在「春季前進」之前僅將幾秒鐘添加到日期時間可能會導致牆上時間增加超過一小時。

雖然這表示此函數在經過時間方面很精確,但其結果在某些使用案例中可能會產生誤導。例如,如果使用者要求每天下午 3:00 舉行會議,並且您使用此函數通過逐日添加來計算所有未來的會議,那麼如果當前時區發生變化,此函數可能會將會議時間更改為下午 2:00 或下午 4: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()

如果第一個 datetime 嚴格晚於第二個,則傳回 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()

如果第一個 datetime 嚴格早於第二個,則傳回 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

比較兩個 datetime 結構。

如果第一個日期時間晚於第二個,則傳回 :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,這是一個基於格里曆的日曆,會在目前的格里曆年中增加正好 10,000 年

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,這是一個基於格里曆的日曆,會在目前的格里曆年中增加正好 10,000 年

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 或任何 unitSystem.time_unit/0 中取得。單位根據 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 時區的資訊。這與傳遞 DateTimeDate.to_iso8601/2 的原則相同。 Date.to_iso8601/2 僅擷取給定結構的日期特定欄位(日曆、年、月和日),並忽略所有其他欄位。

這樣一來,如果你在一個時區中有一個 DateTime,你可以取得另一個時區中相同的牆上時間。例如,如果你在哥本哈根有 2018-08-24 10:00:00,並想要一個在 UTC 中 2018-08-24 10:00:00 的 DateTime,你可以執行

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,因此 DateTime 會以 UTC 傳回。

範例

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,因此 DateTime 會以 UTC 傳回。

範例

# 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。

它預期一個時區來放置 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,並在發生錯誤時引發錯誤。

它預期一個時區來放置 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(時區, 時區資料庫 \\ 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!(時區, 時區資料庫 \\ 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(日期時間, 時區, 時區資料庫 \\ 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!(日期時間, 時區, 時區資料庫 \\ 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(日期時間)

檢視原始碼 (自 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(日期時間, 格式 \\ :extended, 偏移 \\ 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(日期時間, 單位 \\ :second)

檢視原始碼
@spec to_unix(Calendar.datetime(), System.time_unit()) :: integer()

將指定的 datetime 轉換成 Unix 時間。

預期 datetime 會使用大於或等於 0 的年份的 ISO 日曆。

它會根據 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(日期時間, 精確度)

檢視原始碼 (自 1.6.0 起)
@spec truncate(Calendar.datetime(), :microsecond | :millisecond | :second) :: t()

傳回指定的日期時間,其微秒欄位已截斷至指定的精確度 (:microsecond:millisecond:second)。

如果給定的 datetime 精度已經低於給定的精度,則會傳回未變更的 datetime。

範例

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.ISO)

檢視原始碼
@spec utc_now(Calendar.calendar() | :native | :microsecond | :millisecond | :second) ::
  t()

傳回 UTC 中的目前日期時間。

如果您想要 Unix 秒中的目前時間,請改用 System.os_time/1

您也可以傳遞時間單位以自動截斷結果 datetime。此功能自 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(時間單位, 日曆)

檢視原始碼 (自 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}