ruby-on-railsruby

How to calculate the current week in the month in Ruby


My goal is to find the date of a particular day in a given week of that month. Say for example, I want to know the date on May 2nd week's Friday. I can get the following via Time and Date classes.

Week number of current year (considering Sunday as first)

    Time.strftime(%U)

Day of the week (0..7)

    Time.strftime(%w)

But how I get the what week (1st,2nd,3rd,4th or 5th) of the month it is in?

Thanks in advance!


Solution

  • In order to handle the requirements you listed, I would suggest writing a helper function to get the number of the week in a month.

    def get_month_week(date_or_time, start_day = :sunday)
    
      date = date_or_time.to_date
      week_start_format = start_day == :sunday ? '%U' : '%W'
    
      month_week_start = Date.new(date.year, date.month, 1)
      month_week_start_num = month_week_start.strftime(week_start_format).to_i
      month_week_start_num += 1 if month_week_start.wday > 4 # Skip first week if doesn't contain a Thursday
    
      month_week_index = date.strftime(week_start_format).to_i - month_week_start_num
      month_week_index + 1 # Add 1 so that first week is 1 and not 0
    
    end
    

    This can then just be called like so:

    get_month_week(Date.today)
    

    If you really feel like monkey-patching is something you want, you can add to the Date class:

    class Date
    
      def month_week(start_day = :sunday)
    
        week_start_format = start_day == :sunday ? '%U' : '%W'
    
        month_week_start = Date.new(self.year, self.month, 1)
        month_week_start_num = month_week_start.strftime(week_start_format).to_i
        month_week_start_num += 1 if month_week_start.wday > 4 # Skip first week if doesn't contain a Thursday
    
        month_week_index = self.strftime(week_start_format).to_i - month_week_start_num
        month_week_index + 1 # Add 1 so that first week is 1 and not 0
    
      end
    
    end
    

    And this can be called on a date or time like so:

    Date.today.month_week
    

    or

    Time.current.to_date.month_week
    

    I would advise against this since it may collide with other libraries or violate least-surprise for other developers working on the project.