8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TimexとElixir標準日時①:現在日時取得(now)を比べる

Last updated at Posted at 2021-07-30

Elixir実装の芽を愛でるコミュニティ「Elixir Digitalization Implementors」
福岡Elixirコミュニティ「fukuoka.ex」
小倉Elixirコミュニティ「kokura.ex」

上記Elixirコミュニティ運営/所属の piacere です、ご覧いただいてありがとございます :bow:

elixir.jp Slackのスレッドで、Timexをescriptで使おうとしたところ、フォルダを掘らないと動かない … という問題が提起されて、以前、私もこの問題(TimexのdepsであるtzdataのETSテーブルロード問題)に引っかかり、対処方法のコラムを残していましたが、現在のElixir/OTPの構成だと動かなくなっていました

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

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

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

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

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

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

https://findy.connpass.com/event/218661
image.png

本コラムの検証環境

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

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

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

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

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

mix new basic
cd basic
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を叩く

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

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

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

②日本日時でのnowを叩く

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

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

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"]
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」で検証していきます

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

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

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

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

iex> Calendar.get_time_zone_database
Timex.Timezone.Database

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

iex> Calendar.get_time_zone_database
Calendar.UTCOnlyTimeZoneDatabase

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

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

config/runtime.exs
import Config

config :elixir, time_zone_database: Zoneinfo.TimeZoneDatabase

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

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.pngimage.png にて、どうぞ応援よろしくお願いします:bow:

8
4
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
8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?