こんにちは!
プログラミング未経験文系出身、Elixirの国に迷い込んだ?!見習いアルケミストのaliceと申します。
今回はDateTimeモジュールについて学んだことをまとめます。
目次
1.DateTimeモジュール で遊んでみたシリーズ① -事前準備編
2.DateTimeモジュール で遊んでみたシリーズ② -DateTime.add ~ DateTime.compare の紹介
3.DateTimeモジュール で遊んでみたシリーズ③ -DateTime.convert ~ DateTime.from_gregorian_seconds の紹介
4.DateTimeモジュール で遊んでみたシリーズ④ -DateTime.from_iso8601 ~ DateTime.from_naive! の紹介(本記事)
5.DateTimeモジュール で遊んでみたシリーズ⑤ -DateTime.from_unix ~ DateTime.new! の紹介
6.DateTimeモジュール で遊んでみたシリーズ⑥ -DateTime.now ~ DateTime.shift_zone! の紹介
7.DateTimeモジュール で遊んでみたシリーズ⑦ -DateTime.to_date ~ DateTime.to_string の紹介
8.DateTimeモジュール で遊んでみたシリーズ⑧ -DateTime.to_time ~ DateTime.utc_now の紹介
9.DateTimeモジュール で遊んでみたシリーズ番外編 -Livebookでtzdata導入
目的
DateTimeモジュールに含まれる関数を触って機能を理解したい
実行環境
Windows 11 + WSL2 + Ubuntu 22.04
Elixir v1.17.3
Erlang v27.0
前提
本記事を手元検証するには、前提としてtzdataの導入が必要です。
まだの場合は下記1.または2.で準備をしてください。
1.local環境でtzdataの導入
2.Livebookでtzdataの導入
DateTime.from_iso8601とは(from_iso8601/2)
DateTime.from_iso8601(string, format_or_calendar \\ Calendar.ISO)
はISO 8601の拡張形式1をDatetime構造体に変換します。
この関数の逆はDateTime.to_iso8601(datetime, format \\ :extended, offset \\ nil)
です。
ISO 8601にタイムゾーン情報は含まれないため、UTCからの時差をISO 8601の書式に則って記載する必要があります。
すなわち、下記で時差を示します。
- UTCなら末尾に記号
Z
を付ける - 他のタイムゾーンなら末尾に
+
または−
で区切り、続けて時差を書く
例: 各タイムゾーンにおける2015年1月23日23:50:07
を示したいとする。
タイムゾーン | 時差 | ISO 8601拡張形式 |
---|---|---|
日本標準時 | UTC+9 | 2015-01-23T23:50:07+09:00 |
UTC | 無し | 2015-01-23T23:50:07Z |
米国東部標準時 | UTC-5 | 2015-01-23T23:50:07-05:00 |
例
時差無しの場合
DateTime.from_iso8601("2015-01-23T23:50:07Z")
{:ok, ~U[2015-01-23 23:50:07Z], 0}
時差ありの場合
DateTime.from_iso8601("2015-01-23T23:50:07+09:00")
時差にあたる+09:00
が9時間分のオフセット(32400秒)として返されます
{:ok, ~U[2015-01-23 14:50:07Z], 32400}
DateTime.from_iso8601("2015-01-23T23:50:07-05:00")
時差にあたる-05:00
が9時間分のオフセット(-18000秒)として返されます
{:ok, ~U[2015-01-24 04:50:07Z], -18000}
小数点以下
小数点以下は秒の後に.
または,
で表記します2
すなわち、下記の2例は同じ値を返します。
DateTime.from_iso8601("2015-01-23T23:50:07.123-05:00")
{:ok, ~U[2015-01-24 04:50:07.123Z], -18000}
DateTime.from_iso8601("2015-01-23T23:50:07,123-05:00")
{:ok, ~U[2015-01-24 04:50:07.123Z], -18000}
紀元前
紀元前は年の前に-
で表記します3
この結果、年の桁数が5桁になり得ます。
DateTime.from_iso8601("-2015-01-23T23:50:07,123-05:00")
{:ok, ~U[-2015-01-24 04:50:07.123Z], -18000}
ISO8601基本形式への対応
format_or_calendar
に:basic
を渡すことでISO8601基本形式へ対応できます。
DateTime.from_iso8601("20150123T235007.123-0500", :basic)
{:ok, ~U[2015-01-24 04:50:07.123Z], -18000}
DateTime.from_iso8601とは(from_iso8601/3)
DateTime.from_iso8601(string, calendar, format)
はISO 8601の拡張形式1をDatetime構造体に変換します。
calendar
とformat
を明示します。
例
DateTime.from_iso8601("2015-01-23T23:50:07.123-05:00", Calendar.ISO, :extended)
{:ok, ~U[2015-01-24 04:50:07.123Z], -18000}
ISO8601基本形式への対応
DateTime.from_iso8601("20150123T235007.123-0500", Calendar.ISO, :basic)
{:ok, ~U[2015-01-24 04:50:07.123Z], -18000}
DateTime.from_naiveとは
DateTime.from_naive(naive_datetime, time_zone, time_zone_database \\ Calendar.get_time_zone_database())
はNaiveDatetime構造体をDatetime構造体に変換します。
タイムゾーンはカレンダーデータベース(今回の場合はtzdata)と照合します。
この関数の逆はDateTime.to_naive(datetime)
です。
例
DateTime.from_naive(~N[2016-05-24 13:26:08.003], "Etc/UTC")
{:ok, ~U[2016-05-24 13:26:08.003Z]}
DateTime.from_naive(~N[2016-05-24 13:26:08.003], "Asia/Tokyo")
{:ok, #DateTime<2016-05-24 13:26:08.003+09:00 JST Asia/Tokyo>}
サマータイム開始/終了時刻をまたぐ場合
米国ニューヨークの次のサマータイム開始時刻は、現地時刻の3/9の02:00です。
このタイミングで時計が1時間進みます
これをまたいで使用する場合{:gap, gap直前の有効な日時, gap直後の有効な日時}
のタプルが返されます。
DateTime.from_naive(~N[2025-03-09 02:00:00], "America/New_York", Tzdata.TimeZoneDatabase)
{:gap, #DateTime<2025-03-09 01:59:59.999999-05:00 EST America/New_York>,
#DateTime<2025-03-09 03:00:00-04:00 EDT America/New_York>}
DateTime.from_naive!とは
DateTime.from_naive!(naive_datetime, time_zone, time_zone_database \\ Calendar.get_time_zone_database())
はNaiveDatetime構造体をDatetime構造体に変換します。
タイムゾーンはカレンダーデータベース(今回の場合はtzdata)と照合します。
例
DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC")
~U[2016-05-24 13:26:08.003Z]
DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Asia/Tokyo")
#DateTime<2016-05-24 13:26:08.003+09:00 JST Asia/Tokyo>
変換に成功した場合DateTime.from_naive
は {:ok, Datetime構造体}
のタプル が返されるが、DateTime.from_naive!
は Datetime構造体 が返されるので注意。
サマータイム開始/終了時刻をまたぐ場合
米国ニューヨークの次のサマータイム開始時刻1は、現地時刻の3/9の02:00です。
このタイミングで時計が1時間進みます2
これをまたいで使用する場合ArgumentError
を返します。
DateTime.from_naive!(~N[2025-03-09 02:00:00], "America/New_York", Tzdata.TimeZoneDatabase)
** (ArgumentError) cannot convert ~N[2025-03-09 02:00:00] to datetime because such instant does not exist in time zone America/New_York as there is a gap between #DateTime<2025-03-09 01:59:59.999999-05:00 EST America/New_York> and #DateTime<2025-03-09 03:00:00-04:00 EDT America/New_York>
(elixir 1.17.3) lib/calendar/datetime.ex:691: DateTime.from_naive!/3
#cell:7rsn2mhh5hf3osdw:1: (file)
~Elixirの国のご案内~
↓Elixirって何ぞや?と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます
↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ!私もエンジニア未経験から学習中です。
↓We Are The Alchemists, my friends!4
Elixirコミュニティは本当に優しくて温かい人たちばかり!
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。5
-
https://ja.wikipedia.org/wiki/ISO_8601#%E5%9F%BA%E6%9C%AC%E5%BD%A2%E5%BC%8F%E3%81%A8%E6%8B%A1%E5%BC%B5%E5%BD%A2%E5%BC%8F ↩ ↩2 ↩3
-
https://ja.wikipedia.org/wiki/ISO_8601#%E5%9B%BD%E5%AE%B6%E8%A6%8F%E6%A0%BC%E3%81%AB%E3%82%88%E3%82%8B%E6%8B%A1%E5%BC%B5 ↩ ↩2
-
https://ja.wikipedia.org/wiki/ISO_8601#%E5%B9%B4%E3%81%AE%E8%A1%A8%E8%A8%98%EF%BC%880000%E5%B9%B4%E3%82%88%E3%82%8A%E5%89%8D%E3%80%819999%E5%B9%B4%E3%82%88%E3%82%8A%E5%BE%8C%EF%BC%89 ↩
-
@torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。 ↩