DateTimeモジュール で遊んでみたシリーズ② -DateTime.add ~ DateTime.compare の紹介

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回はDateTimeモジュールについて学んだことをまとめます。


# 目次
1.[DateTimeモジュール で遊んでみたシリーズ① -事前準備編](https://qiita.com/Alicesky2127/items/71d6905684f6f0f936c2)
2.DateTimeモジュール で遊んでみたシリーズ② -DateTime.add ~ DateTime.compare の紹介(本記事)
3.[DateTimeモジュール で遊んでみたシリーズ③ -DateTime.convert ~ DateTime.from_gregorian_seconds の紹介](https://qiita.com/Alicesky2127/items/74e646264c7a55ea6f81)
4.[DateTimeモジュール で遊んでみたシリーズ④ -DateTime.from_iso8601 ~ DateTime.from_naive! の紹介](https://qiita.com/Alicesky2127/items/79869efcf8bb5cee9d82)
5.[DateTimeモジュール で遊んでみたシリーズ⑤ -DateTime.from_unix ~ DateTime.new! の紹介](https://qiita.com/Alicesky2127/items/6ce1eb3071880db5dec2)
6.[DateTimeモジュール で遊んでみたシリーズ⑥ -DateTime.now ~ DateTime.shift_zone! の紹介](https://qiita.com/Alicesky2127/items/b706801a887ceb5427ee)
7.[DateTimeモジュール で遊んでみたシリーズ⑦ -DateTime.to_date ~ DateTime.to_string の紹介](https://qiita.com/Alicesky2127/items/a3fcf13bd2577d57b431)
8.[DateTimeモジュール で遊んでみたシリーズ⑧ -DateTime.to_time ~ DateTime.utc_now の紹介](https://qiita.com/Alicesky2127/items/ebd5b063c041adf2d1d0)
9.[DateTimeモジュール で遊んでみたシリーズ番外編 -Livebookでtzdata導入](https://qiita.com/Alicesky2127/items/4ad2072cbca04193a3d4)



# 目的 
DateTimeモジュールに含まれる関数を触って機能を理解したい

https://hexdocs.pm/elixir/DateTime.html

## 実行環境
Windows 11 ＋ WSL2 ＋ Ubuntu 22.04
Elixir v1.17.3
Erlang v27.0

# 前提
本記事を手元検証するには、前提としてtzdataの導入が必要です。
まだの場合は下記1.または2.で準備をしてください。

1.local環境でtzdataの導入

https://qiita.com/Alicesky2127/items/71d6905684f6f0f936c2

2.Livebookでtzdataの導入

https://qiita.com/Alicesky2127/items/4ad2072cbca04193a3d4




# DateTime.addとは
`DateTime.add(datetime, amount_to_add, unit \\ :second, time_zone_database \\ Calendar.get_time_zone_database())`は`datetime`に`unit`単位の`amount_to_add`を加えます。

## 例
### タイムゾーン無しの場合
```diff_elixir:iex
DateTime.add(~U[2018-11-15 10:00:00Z], 3600, :second)
```
3600秒 = 1時間後の値を返します。
```
~U[2018-11-15 11:00:00Z]
```

### タイムゾーンありの場合
```diff_elixir:iex
# datetimeにあたる変数の定義
dt = DateTime.from_naive!(~N[2018-11-15 10:00:00], "Europe/Copenhagen", Tzdata.TimeZoneDatabase) 
```
```
#DateTime<2018-11-15 10:00:00+01:00 CET Europe/Copenhagen>
```

1日後の値を返します。
```diff_elixir:iex
dt |> DateTime.add(1, :day, Tzdata.TimeZoneDatabase)
```
```
#DateTime<2018-11-16 10:00:00+01:00 CET Europe/Copenhagen>
```

### サマータイム開始／終了時刻をまたぐ場合
米国ニューヨークの次のサマータイム開始時刻[^1]は、現地時刻の3/9の02:00です。
このタイミングで時計が1時間進みます[^2]
これをまたいで使用する場合自動調整が入ります。
```diff_elixir:iex
# datetimeにあたる変数の定義
dt = DateTime.from_naive!(~N[2025-03-09 01:59:59.123], "America/New_York", Tzdata.TimeZoneDatabase)
```
この時点では"EST"(米国東部標準時)の表示になっています。
```
#DateTime<2025-03-09 01:59:59.123-05:00 EST America/New_York>
```

サマータイム開始時刻をまたいで3秒後にしてみましょう。
```diff_elixir:iex
dt |> DateTime.add(3, :second, Tzdata.TimeZoneDatabase)
```
サマータイム開始時刻の1時間+3秒後の値を返します。
また、"EDT"(米国東部夏時間)の表示になっています。
```
#DateTime<2025-03-09 03:00:02.123-04:00 EDT America/New_York>
```


# DateTime.after?とは
`DateTime.after?(datetime1, datetime2)`は`datetime1`が`datetime2`より後の日時であるか否かをチェックします。


## 例
```diff_elixir:iex
DateTime.after?(~U[2021-01-01 11:00:01Z], ~U[2021-01-01 11:00:00Z])
```
```
true
```

```diff_elixir:iex
DateTime.after?(~U[2021-01-01 11:00:00Z], ~U[2021-01-01 11:00:01Z])
```
```
false
```

`datetime1`と`datetime2`が同じ場合
falseを返します。
```diff_elixir:iex
DateTime.after?(~U[2021-01-01 11:00:00Z], ~U[2021-01-01 11:00:00Z])
```
```
false
```


# DateTime.before?とは
`DateTime.after?(datetime1, datetime2)`は`datetime1`が`datetime2`より前の日時であるか否かをチェックします。


## 例
```diff_elixir:iex
DateTime.before?(~U[2021-01-01 11:00:00Z], ~U[2021-01-01 11:00:01Z])
```
```
true
```

```diff_elixir:iex
DateTime.before?(~U[2021-01-01 11:00:01Z], ~U[2021-01-01 11:00:00Z])
```
```
false
```

`datetime1`と`datetime2`が同じ場合
falseを返します。
```diff_elixir:iex
DateTime.before?(~U[2021-01-01 11:00:00Z], ~U[2021-01-01 11:00:00Z])
```
```
false
```

# DateTime.compareとは
`DateTime.compare(datetime1, datetime2)`は`datetime1`と`datetime2`を比較します。
次のいずれかを返します。
- :gt `datetime1`が`datetime2`より後の日時である場合[^3]
- :lt `datetime1`が`datetime2`より前の日時である場合
‐ :eq `datetime1`と`datetime2`が同じ場合

## 例
```diff_elixir: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"}

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"}

dt3= %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"}
```

```diff_elixir:iex
DateTime.compare(dt1, dt2)
```
```
:gt
```

```diff_elixir:iex
DateTime.compare(dt2, dt1)
```
```
:lt
```

```diff_elixir:iex
DateTime.compare(dt2, dt3)
```
```
:eq
```


# ～Elixirの国のご案内～
↓Elixirって何ぞや？と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます:laughing::sparkles::sparkles:

https://qiita.com/piacerex/items/09876caa1e17169ec5e1

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

https://elixir-lang.info/topics/entry_column


↓[We Are The Alchemists, my friends!:bouquet:](https://qiita.com/torifukukaiou/items/6bcd5bbb80df9e594e9e "Awesome-san's Awesome article")[^10]
Elixirコミュニティは本当に優しくて温かい人たちばかり！
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。[^11]


https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian

[^1]:サマータイム開始時刻を"Spring Forward", サマータイム終了時刻を"fall back"と呼びます。エラーハンドリングのfallbackと混同する！紛らわしい！https://aupairjapanese.com/?p=513

[^2]:https://www.timeanddate.com/time/change/usa?year=2025

[^3]: `:gt` means "greater than", `:lt` means "less than", `:eq` means "equal to" https://tobe-happy.com/lt_gt/#google_vignette

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


[^11]: @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中！