LoginSignup
6
5

More than 3 years have passed since last update.

Rubyで「ある期間の毎月1日」をDateオブジェクトの配列として取得する方法

Last updated at Posted at 2020-07-30

Rubyの小ネタです。

お題

2020年4月1日から2021年3月1日まで、1年分の「xxxx年xx月1日」のDateオブジェクトを配列として取得するコードを書いてください。

イメージとしてはこんな感じです。

# 見やすいように文字列の配列にしていますが、本当はDateオブジェクトの配列を取得するのがゴールです
[
  "2020-04-01",
  "2020-05-01",
  "2020-06-01",
  "2020-07-01",
  "2020-08-01",
  "2020-09-01",
  "2020-10-01",
  "2020-11-01",
  "2020-12-01",
  "2021-01-01",
  "2021-02-01",
  "2021-03-01"
]

解答例

こんな感じで書けます。

require 'date'
start_date = Date.parse '2020/04/01'
end_date   = Date.parse '2021/03/01'
(start_date..end_date).select{|d| d.day == 1}
#=> [#<Date: 2020-04-01 ((2458941j,0s,0n),+0s,2299161j)>, #<Date: 2020-05-01 ((2458971j,0s,0n),+0s,2299161j)>, (中略), #<Date: 2021-03-01 ((2459275j,0s,0n),+0s,2299161j)>]

RailsであればDate.parseの代わりにto_dateが使えます。

# Railsの場合
start_date = '2020/04/01'.to_date
end_date   = '2021/03/01'.to_date
(start_date..end_date).select{|d| d.day == 1}
#=> [Wed, 01 Apr 2020, Fri, 01 May 2020, (中略), Mon, 01 Mar 2021]

むりやり1行で書くとこんな感じ。(可読性がイマイチなのであまりお勧めしませんが)

# Railsの場合
Range.new(*%w[2020/04/01 2021/03/01].map(&:to_date)).select{|d| d.day == 1}
#=> [Wed, 01 Apr 2020, Fri, 01 May 2020, (中略), Mon, 01 Mar 2021]

いったん335日分のDateオブジェクトの配列を作ってから、毎月1日のDateオブジェクトだけをselectするので若干処理効率が悪いところはありますが、何十年、何百年という期間を対象にしないのであれば、たぶん大きな問題にはならないんじゃないかなー、と思っています。

以上、Rubyの小ネタでした!

おまけ

Railsのnext_monthメソッドとRuby 2.7で導入されたEnumerator.produceを使って、無駄なDateオブジェクトを作らない処理を考えてみました。これもなかなか良さそうです。

# Rails + Ruby 2.7
start_date = '2020/04/01'.to_date
end_date   = '2021/03/01'.to_date
Enumerator.produce(start_date, &:next_month).take_while{|d| d <= end_date}
#=> [Wed, 01 Apr 2020, Fri, 01 May 2020, (中略), Mon, 01 Mar 2021]

素のRubyでも>> 1を使えば1ヶ月後のDateオブジェクトが取得できるので、Ruby 2.7単体でこういう書き方もできます。

# Ruby 2.7
require 'date'
start_date = Date.parse '2020/04/01'
end_date   = Date.parse '2021/03/01'
Enumerator.produce(start_date){|d| d >> 1}.take_while{|d| d <= end_date}
#=> [#<Date: 2020-04-01 ((2458941j,0s,0n),+0s,2299161j)>, #<Date: 2020-05-01 ((2458971j,0s,0n),+0s,2299161j)>, (中略), #<Date: 2021-03-01 ((2459275j,0s,0n),+0s,2299161j)>]
6
5
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
6
5