Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby(with ActiveSupport)で指定日が第何、何曜日かを取得するときのMEMO

第2、第4火曜日だけなんかしらの処理を実行したいとき等、指定日が第何火曜日を知りたいケースの場合に、RubyとかActiveSupportにこういう系のメソッドが無いかなと思ったんですが、 曜日判定は出来ても第何曜日の判定を行うようなメソッドは見当たらず、ちょっと迷って色々考えたのでメモしておきます✍

やりかた(with ActiveSupport)

下記のような方針で考えてみました📅

  • 曜日に関してはDate#wdayを使って曜日を表す数字を取得して、hashで文字列を取得
  • 何番目に関しては対象の日付と月初の日付の週数をDate#cweekを使って取得して差分を取得

実際のコードはこちら

def nth_day_of_week(now: Time.current)
  wdays = { 0 => "", 1 => "", 2 => "", 3 => "", 4 => "", 5 => "", 6 => "" }
  # NOTE: 月初と現在が同じ週だった場合に1としたいので、月の最初の週は0とするためcweekから1を引く
  beginning_of_month_cweek = now.beginning_of_month.to_date.cweek - 1
  nth = now.to_date.cweek - beginning_of_month_cweek
  # NOTE: 年跨ぎの場合、nthが上記方針だとマイナスになるケースがあるので、その場合は前週の結果に+1する方針とする
  # 例) "2019/12/31".in_time_zone.to_date.cweek => 1, "2019/12/1".in_time_zone.to_date.cweek => 48
  nth = now.ago(1.week).to_date.cweek - beginning_of_month_cweek if nth.negative?
  return { nth: nth, wday: wdays[now.wday] }
end

nth_day_of_week
# => {:nth=>2, :wday=>"日"}

nth_day_of_week(now: 1.week.ago)
# => {:nth=>1, :wday=>"日"}

考慮漏れとかもあるかもですが、一旦こんな感じで取れそうでした・・・!(考えてみると意外と難しい・・・🤔💦)

追記: 月初の週数を取得せずに週数を取得する

Twitterで教えてもらった方法、月初を取得しないのでシンプル✨

def nth_day_of_week(now: Time.current)
  wdays = { 0 => "", 1 => "", 2 => "", 3 => "", 4 => "", 5 => "", 6 => "" }
  nth =  now.day / 8 + 1
  return { nth: nth, wday: wdays[now.wday] }
end

この辺の考慮は別途必要・・・!(割と大変)※でもこの辺の年末の考え方は、12月が12月として扱いたいとかありそうなので、要件によって変わるかも?

具体例を以下に示す。年初において以下の曜日に該当する場合、その日は新年第1週の日としてではなく、旧年最終週の日として扱う。
* 1月1日金曜日・1月2日土曜日・1月3日日曜日
* 1月1日土曜日・1月2日日曜日
* 1月1日日曜日
同様に、年末において以下の曜日に該当する場合、その日は旧年最終週の日としてではなく、新年第1週の日として扱う。
* 12月31日月曜日
* 12月30日月曜日・12月31日火曜日
* 12月29日月曜日・12月30日火曜日・12月31日水曜日
https://ja.wikipedia.org/wiki/ISO_8601

それにしても年またぎとかの考慮難しい・・・。

参考

shuzo-kino.hateblo.jp

指定された日付が、その月において何週目にあたるのかを計算する Ruby のメソッド · GitHub