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

More than 1 year has passed since last update.

【Ruby】イベント期間など、特定の期間に現在時刻が含まれるか判定する関数を作る

Posted at

前提

現在時刻が、特定の期間に含まれるか判定する関数を定義する必要がありました。
実装の過程でアドバイスをいただいて改善されたので、前後でどのように変わったのかまとめます。
Railsで実装しています。

元々実装していたコード

def event_period?()
  now = Time.now
  # 1月1日から1月31日まで
  event_start_day = Time.new(2023, 1, 1, 0, 0, 0, "+00:00")
  event_end_day = Time.new(2023, 2, 1, 0, 0, 0, "+00:00")
  now >= event_start_day && now < event_end_day
end

現在の日時が event_start_day より後かつ event_end_day より前である場合に true が返され、そうでない場合にfalseが返されます。

最終的なコード

  def event_period?(now: Time.zone.now)
    Range
      .new(
        Time.zone.parse('2023-01-01 00:00:00'),
        Time.zone.parse('2023-02-01 00:00:00'),
        true
      )
      .cover?(now)
  end

タイムゾーンに関して

元のコードでは、Time#newを使用してイベントの開始日と終了日を定義していました。

最終的なコードでは、Time.zone.parse()メソッドを使用して、Railsアプリケーションのタイムゾーンに設定されているタイムゾーンを考慮した時間を取得しています。

範囲をRangeクラスを使って表現する

また、Rangeクラスを使用して期間を表現することで、期間が直感的に理解できるようになりました。
最初のコードでは、開始日と終了日を定義して、さらに別の行で日付が含まれているか判定する手間がありました。

※備考

Range#newの第三引数にtrueを指定すると、終端を含まないようにできます。(2023-02-01 00:00:00は含まれない)
Range.new (Ruby 3.2 リファレンスマニュアル)

現在時刻を扱うため、デフォルト引数を指定

この関数は、現在時刻が特定の期間に含まれるかを判定します。
引数を取っていますが、デフォルトの値はTime.zone.nowにしています。

理由としては、この関数が単体で使用される場合はそのまま呼び出して問題ないのですが、仮に複数の現在時刻を扱う関数と一緒に呼び出されたり、ループ処理の中で呼び出された際に現在時刻がずれないように、外側からも渡せるようにするためです。

ですから、引数の名前はtimeではなくnowになっています。

コードを見た方がわかりやすいと思うため、以下に例を書いておきました。

  • 時間がずれるパターン
def current_time(now = Time.now)
    now
end

result = []
100000.times { result << current_time }

p result.first # 2023-05-16 02:50:10.53720954 +0000
p result.last  # 2023-05-16 02:50:10.621344667 +0000 微妙にずれる

関数の内部で現在時刻を定義するとこのようなことが起こります。
もちろん、レアなケースだとは思うので気にならなければ良いのですが、外部から現在時刻を渡せるようにすると、以下のように改善されます。

  • 時間がずれないパターン
def current_time(now = Time.now)
    now
end

now = Time.now

result = []
100000.times { result << current_time(now) }

p result.first # 2023-05-16 02:51:53.278507445 +0000
p result.last  # 2023-05-16 02:51:53.278507445 +0000 一致

外側から渡しているので、一致していますね。
使い所に応じて変更できるので便利です。

詳しくは参考リンクの記事がわかりやすいので、是非一度読んでみてください。

以上です。

参考リンク

現在時刻を扱うメソッドはデフォルト引数を使いましょうという話 - けんちゃんくんさんのWeb日記

「現在時刻」を外部入力とする設計と、その実装のこと - クックパッド開発者ブログ

4
1
1

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