6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DateTimeモジュール で遊んでみたシリーズ④ -DateTime.from_iso8601 ~ DateTime.from_naive! の紹介

Last updated at Posted at 2024-12-22

こんにちは!
プログラミング未経験文系出身、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

時差無しの場合

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

時差ありの場合

iex
DateTime.from_iso8601("2015-01-23T23:50:07+09:00")

時差にあたる+09:00が9時間分のオフセット(32400秒)として返されます

{:ok, ~U[2015-01-23 14:50:07Z], 32400}
iex
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例は同じ値を返します。

iex
DateTime.from_iso8601("2015-01-23T23:50:07.123-05:00")
{:ok, ~U[2015-01-24 04:50:07.123Z], -18000}
iex
DateTime.from_iso8601("2015-01-23T23:50:07,123-05:00")
{:ok, ~U[2015-01-24 04:50:07.123Z], -18000}

紀元前

紀元前は年の前に-で表記します3
この結果、年の桁数が5桁になり得ます。

iex
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基本形式へ対応できます。

iex
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構造体に変換します。
calendarformatを明示します。

iex
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基本形式への対応

iex
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)です。

iex
DateTime.from_naive(~N[2016-05-24 13:26:08.003], "Etc/UTC")
{:ok, ~U[2016-05-24 13:26:08.003Z]}
iex
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直後の有効な日時}のタプルが返されます。

iex
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)と照合します。

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[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を返します。

iex
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は先端のアレコレをだいたい全部できちゃいます:laughing::sparkles::sparkles:

↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ!私もエンジニア未経験から学習中です。

We Are The Alchemists, my friends!:bouquet:4
Elixirコミュニティは本当に優しくて温かい人たちばかり!
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。5

  1. 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

  2. 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

  3. 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

  4. @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。

  5. @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中!

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?