TimexとElixir標準日時①：現在日時取得（now）を比べる

[Elixir実装の芽を愛でるコミュニティ「Elixir Digitalization Implementors」
福岡Elixirコミュニティ「fukuoka.ex」
小倉Elixirコミュニティ「kokura.ex」](https://fukuokaex.connpass.com)

https://fukuokaex.connpass.com

上記Elixirコミュニティ運営／所属の [piacere](https://twitter.com/piacere_ex) です、ご覧いただいてありがとございます :bow:

[elixir.jp Slackのスレッド](https://elixirjp.slack.com/archives/CTGEFMJA0/p1627522398039400)で、Timexをescriptで使おうとしたところ、フォルダを掘らないと動かない … という問題が提起されて、以前、私もこの問題（Timexのdepsである[tzdataのETSテーブルロード問題](https://github.com/bitwalker/timex/issues/86)）に引っかかり、[対処方法のコラム](https://qiita.com/piacerex/items/7ebaa107ad7a7f6cec46)を残していましたが、現在のElixir／OTPの構成だと動かなくなっていました

そこで、今まで数年単位でサボり続けてた、Timexと日時系Elixir標準モジュールの比較を改めて行おうと思います

そこそこボリュームありそうなので、何回かに分けて整理します

内容が、面白かったり、役に立ったら、「いいね」よろしくお願いします :wink:

<h3>:shamrock::shamrock::shamrock: ひさびさに主催イベント以外で登壇します :shamrock::shamrock::shamrock:</h3>

来週8/5（木）19時から、ハイスキルエンジニア転職サービス「Findy」の下記イベントで、RubyとElixirについてパネルディスカッションします

私がElixirを始めたきっかけと、Rubyに感じ続けた課題、それと最近、Elixir案件でやたら求人募集してる背景などについて、どこまで話せるかは分かりませんが、可能な限り、情報共有したいと思います

https://findy.connpass.com/event/218661
[![image.png](https://connpass-tokyo.s3.amazonaws.com/thumbs/01/5e/015ea4ba4dca2e56c37b5956d3404e1b.png)](https://findy.connpass.com/event/218661)

# 本コラムの検証環境

本コラムは、以下環境で検証しています（Windows WSL2で実施していますが、LinuxやMacでも動作する想定です）

- Windows 10
- WSL2 + Ubuntu 18.04
- OTP 24.0
- Elixir 1.12.0

環境構築が未だの方は、下記コラムをご参考ください

https://qiita.com/piacerex/items/6b64dfe70f48c89d8385

なおZoneinfoが、Windows WSL2だと動きますが、Windowsネイティブだと動かない（≒OSが管理するタイムゾーンデータベースを利用する関係で）ため、Windowsの方は、上記環境構築に記載しているWSL2＋Ubuntu 18.04でお試ししてください

Elixir PJは、下記にて構築／REPL起動します

```
mix new basic
cd basic
```

```elixir:mix.exs
defmodule Basic.MixProject do
  use Mix.Project
…
  defp deps do
    [
      {:timex, "~> 3.7"},
      {:zoneinfo, "~> 0.1"},
…
```

```
mix deps.get
iex -S mix
```

# ①両方のnowを叩く

まず、現在日時の取得からいきましょう

```elixir:Timex版
iex> Timex.now
~U[2021-07-30 02:14:20.217490Z]
```

```elixir:Elixir標準モジュール版
iex> DateTime.now!("Etc/UTC")
~U[2021-07-30 02:16:03.809943Z]
```

標準モジュールは、タイムゾーン指定が必須なので、ちょっちめんどいですね

# ②日本日時でのnowを叩く

次に、日本日時でのnowです

まずは、各自のタイムゾーンDBの確認です

```elixir
iex> Tzdata.zone_list
["Africa/Abidjan", "Africa/Accra", "Africa/Addis_Ababa", "Africa/Algiers",
 "Africa/Asmara", "Africa/Asmera", "Africa/Bamako", "Africa/Bangui",
 "Africa/Banjul", "Africa/Bissau", "Africa/Blantyre", "Africa/Brazzaville",
 "Africa/Bujumbura", "Africa/Cairo", "Africa/Casablanca", "Africa/Ceuta",
 "Africa/Conakry", "Africa/Dakar", "Africa/Dar_es_Salaam", "Africa/Djibouti",
 "Africa/Douala", "Africa/El_Aaiun", "Africa/Freetown", "Africa/Gaborone",
 "Africa/Harare", "Africa/Johannesburg", "Africa/Juba", "Africa/Kampala",
 "Africa/Khartoum", "Africa/Kigali", "Africa/Kinshasa", "Africa/Lagos",
 "Africa/Libreville", "Africa/Lome", "Africa/Luanda", "Africa/Lubumbashi",
 "Africa/Lusaka", "Africa/Malabo", "Africa/Maputo", "Africa/Maseru",
 "Africa/Mbabane", "Africa/Mogadishu", "Africa/Monrovia", "Africa/Nairobi",
 "Africa/Ndjamena", "Africa/Niamey", "Africa/Nouakchott", "Africa/Ouagadougou",
 "Africa/Porto-Novo", "Africa/Sao_Tome", ...]
iex> Tzdata.zone_list |> Enum.filter(& String.contains?(&1, "Japan"))
["Japan"]
iex> Tzdata.zone_list |> Enum.filter(& String.contains?(&1, "Asia/Tokyo"))
["Asia/Tokyo"]
```

```elixir
iex> Zoneinfo.time_zones
["Africa/Abidjan", "Africa/Accra", "Africa/Addis_Ababa", "Africa/Algiers",
 "Africa/Bangui", "Africa/Bissau", "Africa/Blantyre", "Africa/Casablanca",
 "Africa/Ceuta", "Africa/El_Aaiun", "Africa/Johannesburg", "Africa/Juba",
 "Africa/Khartoum", "Africa/Monrovia", "Africa/Ndjamena", "Africa/Sao_Tome",
 "Africa/Tunis", "Africa/Windhoek", "America/Adak", "America/Anchorage",
 "America/Anguilla", "America/Araguaina", "America/Argentina/La_Rioja",
 "America/Argentina/Rio_Gallegos", "America/Argentina/Salta",
 "America/Argentina/San_Juan", "America/Argentina/San_Luis",
 "America/Argentina/Tucuman", "America/Argentina/Ushuaia", "America/Aruba",
 "America/Asuncion", "America/Atikokan", "America/Bahia",
 "America/Bahia_Banderas", "America/Barbados", "America/Belem",
 "America/Belize", "America/Blanc-Sablon", "America/Boa_Vista",
 "America/Bogota", "America/Boise", "America/Buenos_Aires",
 "America/Cambridge_Bay", "America/Campo_Grande", "America/Cancun",
 "America/Caracas", "America/Catamarca", "America/Cayenne", "America/Cayman",
 "America/Chicago", ...]
iex> Zoneinfo.time_zones |> Enum.filter(& String.contains?(&1, "Japan"))
["Japan", "right/Japan"]
iex> Zoneinfo.time_zones |> Enum.filter(& String.contains?(&1, "Asia/Tokyo"))
```

どうやらZoneinfoの方は、「Asia/Tokyo」が存在しないようなので、「Japan」で検証していきます

さて、タイムゾーンも確認できたので、日本日時を取得してみます

```elixir:Timex版
iex> Timex.now("Japan")
#DateTime<2021-07-30 19:50:58.878171+09:00 JST Japan>
```

```elixir:Elixir標準モジュール版
iex> DateTime.now!("Japan")
#DateTime<2021-07-30 19:50:17.137880+09:00 JST Japan>
```

# タイムゾーン設定のタネ明かし

Timexをインストールしている状況下だと、下記の通り、Elixir標準モジュールもTimex（つまりtzdata）をタイムゾーンDBとして利用するようです

```elixir
iex> Calendar.get_time_zone_database
Timex.Timezone.Database
```

ちなみに、Timex未インストールだと、下記のようになっており、UTCしか対応していません（コレがElixir標準モジュールのデフォルト）

```elixir
iex> Calendar.get_time_zone_database
Calendar.UTCOnlyTimeZoneDatabase
```

ちなみに、DateTime.now!()の第2引数で指定している、タイムゾーンDBの指定は、configでデフォルト指定することも可能です

なお、下記ファイルは、デフォルトではフォルダ毎、存在しないため、フォルダ作成とファイル作成を行ってください

```elixir:config/runtime.exs
import Config

config :elixir, time_zone_database: Zoneinfo.TimeZoneDatabase
```

設定後、iexを再起動すると、下記のようになります

```elixir
iex> Calendar.get_time_zone_database
Zoneinfo.TimeZoneDatabase
iex> Zoneinfo.time_zones |> Enum.filter(& String.contains?(&1, "Japan"))
["Japan", "right/Japan"]
iex> timex = Timex.now("Japan"); datetime = DateTime.now!("Japan")
#DateTime<2021-07-30 20:54:13.158207+09:00 JST Japan>
iex> timex
#DateTime<2021-07-30 20:54:13.124480+09:00 JST Japan>
iex> datetime
#DateTime<2021-07-30 20:54:13.158207+09:00 JST Japan>
```

# 最後に

ひとまず、タイムゾーン変更がTimexでもできることが分かり、解決の光がちょっと見えてきた気がします

次回は、上記タイムゾーン変更した後のTimexをescriptで動かし、エラー解消できるかトライします

# p.s.このコラムが、面白かったり、役に立ったら…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/67568d54-6584-ad33-77c7-b3b3afe70287.png) や ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/f5b819ef-d655-ef72-294c-b1a9d2c5b563.png) にて、どうぞ応援よろしくお願いします:bow: