61

I'm sure there's a good simple elegant one-liner in Ruby to give you the number of days in a given month, accounting for year, such as "February 1997". What is it?

Joe Doyle
  • 6,363
  • 3
  • 42
  • 45
Teflon Ted
  • 8,696
  • 19
  • 64
  • 78

13 Answers13

137

If you're working in Rails, chances are you'll get hamstrung eventually if you switch among Time, Date, and DateTime, especially when it comes to dealing with UTC/time zones, daylight savings, and the like. My experience has been it's best to use Time, and stick with it everywhere.

So, assuming you're using Rails's Time class, there are two good options, depending on context:

  1. If you have a month m and year y, use the class method on Time:

    days = Time.days_in_month(m, y)
    
  2. If you have a Time object t, cleaner to ask the day number of the last day of the month:

    days = t.end_of_month.day
    
Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
mkosma
  • 1,487
  • 2
  • 9
  • 5
  • 8
    Thanks! but not really -- OP asked about ruby, not rails. I'd be interested to know how many folks are working in Ruby Off Rails, though. – mkosma Oct 17 '12 at 22:19
  • 14
    I use ruby outside rails and this answer would be no good for me. – SteveRawlinson Sep 06 '13 at 14:37
  • 1
    @SteveRawlingson Get your career on track then! :P – Starkers Feb 22 '14 at 20:44
  • 2
    I'm implementing a gem where this is needed, and I cannot assume the user would use the gem inside Rails. So I really think that, although cleaner, this should not be the accepted answer. It's very nice to have it here in context as well, cause lots of people would prefer this option when in Rails. – Ernesto Oct 02 '14 at 15:04
  • Working on Ruby project do not forbid you using activesupport gem. Source : https://github.com/rails/rails/tree/master/activesupport – OmniBus Feb 05 '15 at 06:56
  • I don't use Rails, but generally I find the time stuff from ActiveSupport is worth cherry-picking into any project that deals with dates and times like this. – Andrew Feb 09 '17 at 22:21
75
require 'date'

def days_in_month(year, month)
  Date.new(year, month, -1).day
end

# print number of days in February 2012
puts days_in_month(2012, 2)
coreyward
  • 77,547
  • 20
  • 137
  • 166
crantok
  • 1,333
  • 11
  • 18
27

This is the implementation from ActiveSupport (a little adapted):

COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

def days_in_month(month, year = Time.now.year)
   return 29 if month == 2 && Date.gregorian_leap?(year)
   COMMON_YEAR_DAYS_IN_MONTH[month]
end
andre-r
  • 2,685
  • 19
  • 23
24

How about:

require 'date'

def days_in_month(year, month)
  (Date.new(year, 12, 31) << (12-month)).day
end

# print number of days in Feburary 2009
puts days_in_month(2009, 2)

You may also want to look at Time::days_in_month in Ruby on Rails.

13

In Rails project for current date

Time.days_in_month(Time.now.month, Time.now.year)

For any date t which is instance of Time

Time.days_in_month(t.month, t.year)

or

t.end_of_month.day

.
If you have UTC seconds, you need to get an instance of Time first

Time.at(seconds).end_of_month.day
Sergiy Seletskyy
  • 16,236
  • 7
  • 69
  • 80
9

For a given Date object I feel like the easiest is:

Date.today.all_month.count
pierrea
  • 1,368
  • 14
  • 18
  • 1
    Docs for `all_month` can be found [here](https://api.rubyonrails.org/classes/DateAndTime/Calculations.html#method-i-all_month). – Marian13 Oct 19 '20 at 01:28
7

Use Time.days_in_month(month) where month = 1 for January, 2 for Feb, etc.

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
Henley
  • 21,258
  • 32
  • 119
  • 207
4

revise the input for other format

def days_in_a_month(date = "2012-02-01")
  date.to_date.end_of_month.day
end
CloudyMarble
  • 36,908
  • 70
  • 97
  • 130
Mr Bohr
  • 125
  • 3
  • 8
3

as of rails 3.2... there's a built in version: http://api.rubyonrails.org/classes/Time.html#method-c-days_in_month

(alas, it shows up after this answer, which takes folks on a long hike)

aabes
  • 208
  • 1
  • 12
3

Time.now.end_of_month.day - for current month

Date.parse("2014-07-01").end_of_month.day - use date of first day in month.

Depends on ActiveSupport

Piotr Karbownik
  • 201
  • 1
  • 4
3

A simple way using Date:

def days_of_month(month, year)
  Date.new(year, month, -1).day
end
Alex
  • 503
  • 4
  • 7
2

I think it's the simplest way to get it

def get_number_of_days(date = Date.today)
  Date.new(date.year, date.month, -1).mday
end
alek
  • 331
  • 1
  • 5
1

Since the time is irrelevant for this purpose then you just need a date object:

[*Date.today.all_month].size
Andres Leon
  • 131
  • 1
  • 8
  • Time is not irrelevant, the OP wants to know the number of days *in a given month, such as february 1997* – Nino Filiu Jan 02 '19 at 17:35
  • What I meant is that since we don't need either hours, minutes or seconds then a Time object is not necessary. Therefore, a Date object is more than enough in this case. – Andres Leon Jan 03 '19 at 10:33
  • I prefer to use a Time object when I can, so as not to have to pull the Date object from the library. – BobRodes Mar 07 '19 at 20:47