Module: NthWeekday

Defined in:
lib/nth_weekday.rb

Overview

NthWeekday module - Get specific weekdays (like 3rd Wednesday) from any year/month

Constant Summary collapse

WEEKDAY_MAP =

Mapping of weekday symbols to Date’s wday values (0-6, Sunday is 0)

{
    su: 0, # Sunday
    mo: 1, # Monday
    tu: 2, # Tuesday
    we: 3, # Wednesday
    th: 4, # Thursday
    fr: 5, # Friday
    sa: 6  # Saturday
}.freeze

Class Method Summary collapse

Class Method Details

.get(year:, month:, weekday:, nth:, format: nil) ⇒ Date, ...

Get the nth weekday of a specific month and year

Parameters:

  • year (Integer)

    Year (e.g., 2025)

  • month (Integer)

    Month (1-12)

  • weekday (Symbol)

    Weekday symbol (:mo, :tu, :we, :th, :fr, :sa, :su)

  • nth (Integer)

    The occurrence of the weekday (1-5, or -1 for last occurrence)

  • format (String, Symbol, nil) (defaults to: nil)

    Optional output format. String uses Date#strftime, :unix returns UTC midnight timestamp.

Returns:

  • (Date, String, Integer, nil)

    Date object, formatted string, UNIX timestamp, or nil when no matching date exists

Raises:

  • (ArgumentError)

    If parameters are invalid



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/nth_weekday.rb', line 27

def get(year:, month:, weekday:, nth:, format: nil)
  validate_params(year, month, weekday, nth, format)

  wday = WEEKDAY_MAP[weekday.to_sym]
  raise ArgumentError, 'Invalid weekday symbol' unless wday

  first_day = Date.new(year, month, 1)
  last_day = first_day.next_month.prev_day

  days = (first_day..last_day).select { |date| date.wday == wday }

  date = if nth == -1
           days.last
         else
           days[nth - 1]
         end

  format_date(date, format)
end