9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

v1.17の「Duration and shift/2 functions」を触ってみる

Posted at

本記事は、「Elixirのアドベントカレンダー2024」の15日目の記事です。

Elixirのv1.18がもうすぐ出てきそうというタイミングで、久々にローカル環境のElixir環境をみたら、v1.14で止まっていました。
直近で触っていたのはLivebookだったため、Elixir本体を直接触っていませんでした。そのため、随分とバージョンに差があいてしまっていました。とほほ...

さて、遅れてしまったものを嘆いていても仕方ない。
気持ちを切り替えて、新しいバージョンをインストール...と思ったら、少し前にマシンのCPUがAppleシリコン製に変わっていたこともあり、asdfも失敗。
幸いなことに、先人達がAppleシリコン製のインストール方法を残してくださっていますが、手っ取り早く動かしておきたかったので、今回はdockerを頼ることにしました。

Elixir v1.17-otp-27をDocker経由でインストール

Elixirの公式イメージを確認。

2024年12月15日時点では、1.17.3系が最新。
v1.17系であればいいが、optは最新の27系がいいなと思い、「1.17-otp-27」にする。

ひとまず、iexで起動すればいいかなと、以下を実施。

docker run -it --rm elixir:1.17-otp-27

実行結果はこちら。

$docker run -it --rm elixir:1.17-otp-27
Unable to find image 'elixir:1.17-otp-27' locally
1.17-otp-27: Pulling from library/elixir
82312fccb35f: Pull complete
4ac722d9cf93: Pull complete
261351ed796d: Pull complete
a9d319298afc: Pull complete
e094548c0cea: Pull complete
d1a116ea1e30: Pull complete
40d63b8a7c51: Pull complete
94b3c35d2121: Pull complete
Digest: sha256:197b5e195e8413cf898548d71d3023ab8b074f9e5b7ac90c60d37804a9515da1
Status: Downloaded newer image for elixir:1.17-otp-27
Erlang/OTP 27 [erts-15.1.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]

Interactive Elixir (1.17.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>

良かった。起動した。

Duration and shift/2 functionsを試す

さて、起動したのはいいけど、何しようかな...とリリースノートを見ていると、「Adding Duration and shift/2 functions」の文字が。

そういえば、直近お仕事で「起点日からNヶ月後の開始日/終了日を算出する」という小さなロジックを書いてたっけ...と思い出し、興味を持ちました。

なので、リハビリがてら、ここをちょっと触ってみることに。

では、早速。
シジルで、NativeData型を定義

iex> now = ~N[2024-12-15 23:21:11]
~N[2024-12-15 23:21:11]

サンプルに従い、「shift/2」を試してみる。

  • 「Date.shift/2」の場合、当然「時刻」部分はカットされる
  • 「Time.shift/2」の場合、当然「日付」部分はカットされる
  • 「NaiveDateTime.shift/2」の場合、日時は残ったまま
iex> now |> Date.shift(month: 1)
~D[2025-01-15]

iex> now |> Time.shift(hour: 1)
~T[00:21:11]

iex> now |> NaiveDateTime.shift(hour: 1)
~N[2024-12-16 00:21:11]

年月日、時分秒はそれぞれ指定できる。
もちろん、Dateでは「年月日」のみ、Timeでは「時分秒」しか指定できない。
指定すると、怒れる。

iex> now |> NaiveDateTime.shift(year: 2)
~N[2026-12-15 23:21:11]

iex> now |> NaiveDateTime.shift(month: 2)
~N[2025-02-15 23:21:11]

iex> now |> NaiveDateTime.shift(day: 2)
~N[2024-12-17 23:21:11]

iex> now |> NaiveDateTime.shift(hour: 2)
~N[2024-12-16 01:21:11]

iex> now |> NaiveDateTime.shift(minute: 2)
~N[2024-12-15 23:23:11]

iex> now |> NaiveDateTime.shift(second: 2)
~N[2024-12-15 23:21:13]

## Dateの場合

iex> now |> Date.shift(year: 2)
~D[2026-12-15]

iex> now |> Date.shift(month: 2)
~D[2025-02-15]

iex> now |> Date.shift(day: 2)
~D[2024-12-17]

iex> now |> Date.shift(hour: 2)
** (ArgumentError) unsupported unit :hour. Expected :year, :month, :week, :day
    (elixir 1.17.3) lib/calendar/date.ex:819: Date.validate_duration_unit!/1
    (elixir 1.17.3) lib/enum.ex:987: Enum."-each/2-lists^foreach/1-0-"/2
    (elixir 1.17.3) lib/calendar/date.ex:813: Date.__duration__!/1
    (elixir 1.17.3) lib/calendar/date.ex:802: Date.shift/2
    iex:63: (file)

## Timeの場合

iex> now |> Time.shift(hour: 2)
~T[01:21:11]

iex> now |> Time.shift(minute: 2)
~T[23:23:11]

iex> now |> Time.shift(second: 2)
~T[23:21:13]

iex> now |> Time.shift(day: 2)
** (ArgumentError) unsupported unit :day. Expected :hour, :minute, :second, :microsecond
    (elixir 1.17.3) lib/calendar/time.ex:617: Time.validate_duration_unit!/1
    (elixir 1.17.3) lib/enum.ex:987: Enum."-each/2-lists^foreach/1-0-"/2
    (elixir 1.17.3) lib/calendar/time.ex:602: Time.__duration__!/1
    (elixir 1.17.3) lib/calendar/time.ex:584: Time.shift/2
    iex:67: (file)

複数の設定も可能

iex> now |> NaiveDateTime.shift(year: 4, day: 3, hour: 2)
~N[2028-12-19 01:21:11]

マイクロ秒も指定できる。が、指定の仕方は、他の場合と異なり、値と有効桁数の指定になっている

iex> now |> NaiveDateTime.shift(year: 4, day: 3, hour: 2, microsecond: {500, 6})
~N[2028-12-19 01:21:11.000500]

iex> now |> NaiveDateTime.shift(year: 4, day: 3, hour: 2, microsecond: {500, 5})
~N[2028-12-19 01:21:11.00050]

iex> now |> NaiveDateTime.shift(year: 4, day: 3, hour: 2, microsecond: {500, 4})
~N[2028-12-19 01:21:11.0005]

iex> now |> NaiveDateTime.shift(year: 4, day: 3, hour: 2, microsecond: {500, 3})
~N[2028-12-19 01:21:11.000]

iex> now |> NaiveDateTime.shift(year: 4, day: 3, hour: 2, microsecond: {500, 2})
~N[2028-12-19 01:21:11.00]

iex> now |> NaiveDateTime.shift(year: 4, day: 3, hour: 2, microsecond: {500, 1})
~N[2028-12-19 01:21:11.0]

iex> now |> NaiveDateTime.shift(year: 4, day: 3, hour: 2, microsecond: {500, 0})
~N[2028-12-19 01:21:11]

0指定や逆算もできるようです。

iex> now |> NaiveDateTime.shift(day: 0)
~N[2024-12-15 23:21:11]

iex> now |> NaiveDateTime.shift(day: -2)
~N[2024-12-13 23:21:11]

解説にもあるように、shift/2を2回実施するのと、shift/2で2つ分を一気にずらるのとでは、進み方が違います。
ただ、これについては、影響を受けるのは、「月末+年または月のshift」という気がしています。

影響を受けない場合(どちらも変わらない)

iex> now |> NaiveDateTime.shift(month: 1) |> NaiveDateTime.shift(month: 1)
~N[2025-02-15 23:21:11]

iex> now |> NaiveDateTime.shift(month: 2)
~N[2025-02-15 23:21:11]

影響を受ける場合

iex> ~N[2024-01-31 23:21:11] |> NaiveDateTime.shift(month: 1) |> NaiveDateTime.shift(month: 1) |> NaiveDateTime.shift(month: 1)
~N[2024-04-29 23:21:11]

iex> ~N[2024-01-31 23:21:11] |> NaiveDateTime.shift(month: 3)
~N[2024-04-30 23:21:11]


iex> ~N[2024-02-29 23:21:11] |> NaiveDateTime.shift(year: 1) |> NaiveDateTime.shift(year: 1) |> NaiveDateTime.shift(year: 1) |> NaiveDateTime.shift(year: 1)
~N[2028-02-28 23:21:11]

iex> ~N[2024-02-29 23:21:11] |> NaiveDateTime.shift(year: 4)
~N[2028-02-29 23:21:11]

タイムゾーン周りの設定もあるようだけど、そこはまたの機会に。

9
0
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
9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?