Getting number of days in a month

This is probably an easy question but I am trying to get at the number
of days that are in a month. I have this calendar that I have built, the
idea being that when a month turns from February to March, for example,
the calendar should redisplay itself properly formated showing the new
month and the correct number of days. I have it so that it starts
counting the days on the right day of the week, but I have to know when
to stop counting. Any ideas, Thanks,

-S

On Thu, Feb 28, 2008 at 01:17:22AM +0900, Shandy N. wrote:

This is probably an easy question but I am trying to get at the number
of days that are in a month. I have this calendar that I have built, the
idea being that when a month turns from February to March, for example,
the calendar should redisplay itself properly formated showing the new
month and the correct number of days. I have it so that it starts
counting the days on the right day of the week, but I have to know when
to stop counting. Any ideas, Thanks,

require ‘date’

def days_in_month(month, year)
month = month.to_i
year = year.to_i
raise ArgumentError.new(“invalid month”) unless (1…12).to_a.include?
month
first = Date.parse sprintf("%04d%02d01", year, month)
next_month = first + 32
(last - last.mday).mday
end

-S
–Greg

On 27/02/2008, Shandy N. [email protected] wrote:

This is probably an easy question but I am trying to get at the number
of days that are in a month. I have this calendar that I have built, the
idea being that when a month turns from February to March, for example,
the calendar should redisplay itself properly formated showing the new
month and the correct number of days. I have it so that it starts
counting the days on the right day of the week, but I have to know when
to stop counting. Any ideas, Thanks,

i have not completely understood your problem, but there is a gem call
‘date_utils’ which does various calendar calculations.

See ruby gem of the week 2007/24 | thopre
for
some examples!

-Thomas


Thomas P.
[email protected]
[email protected]
Büro: 030 - 830 353 88
mobil: 0176 - 75 03 03 04
Privat: 030 - 49 78 37 06

http://www.thopre.com/

On Feb 27, 11:40 am, Gregory S. [email protected]
wrote:

–Greg

might want to try running that before posting

On Thu, Feb 28, 2008 at 02:49:54AM +0900, Brian A. wrote:

-S
–Greg

might want to try running that before posting

Ah, details. Change the last line of the method to:

(next_month + next_month.mday).mday

Anyhow, it’s worth noting that ActiveSupport includes
Time.days_in_month.

–Greg

On Feb 27, 2008, at 11:17 AM, Shandy N. wrote:

This is probably an easy question but I am trying to get at the number
of days that are in a month. I have this calendar that I have
built, the
idea being that when a month turns from February to March, for
example,
the calendar should redisplay itself properly formated showing the new
month and the correct number of days. I have it so that it starts
counting the days on the right day of the week, but I have to know
when
to stop counting. Any ideas, Thanks,

require "Date" d = Date.new(2008, 2, -1) d.day # => 29

You can find the last day of a month by creating a Date object for
day -1.

Regards, Morton

On Feb 27, 11:17 am, Shandy N. [email protected] wrote:

This is probably an easy question but I am trying to get at the number
of days that are in a month. I have this calendar that I have built, the
idea being that when a month turns from February to March, for example,
the calendar should redisplay itself properly formated showing the new
month and the correct number of days. I have it so that it starts
counting the days on the right day of the week, but I have to know when
to stop counting. Any ideas, Thanks,

require ‘date’

def days_in_month year, month
((month < 12) ?
Date.new(year, month + 1) :
Date.new(year + 1, 1)).-(1).mday
end

puts days_in_month(2008,2) # => 29

On Feb 27, 1:00 pm, Gregory S. [email protected]
wrote:

to stop counting. Any ideas, Thanks,
end
Anyhow, it’s worth noting that ActiveSupport includes Time.days_in_month.

–Greg

You still didn’t run it, did you?

Some ideas you may want to consider:

  1. it’s probably reasonable to expect numeric month and day arguments,
    so you can skip the .to_i calls
  2. instead of creating a range, converting it to an array and calling
    include?, wouldn’t it be better to just use a simple comparison such
    as "unless month > 0 && month < 13
  3. sprintf’ing a date just to parse it is unnecessary & inefficient
  4. it’s still broken

On Feb 27, 12:07 pm, Morton G. [email protected] wrote:

when

Regards, Morton

And we have a winner :slight_smile:

I wish I had read your post before posting mine. I need to read the
stdlib doc more carefully.

Shandy N. wrote:

This is probably an easy question but I am trying to get at the number
of days that are in a month. I have this calendar that I have built, the
idea being that when a month turns from February to March, for example,
the calendar should redisplay itself properly formated showing the new
month and the correct number of days. I have it so that it starts
counting the days on the right day of the week, but I have to know when
to stop counting. Any ideas, Thanks,

-S

If you don’t want to use the Date module, this is the plain old way:

def days_in_month(m=Time.new.month,y=Time.new.year)
return [31,0,31,30,31,30,31,31,30,31,30,31][m-1] unless m == 2
((y % 4 == 0) and ( (!(y % 100 == 0)) or (y % 400 == 0) ) ) ? 29 : 28
end

Dan

On Feb 27, 2008, at 2:17 PM, Gregory S. wrote:

of days that are in a month. I have this calendar that I have
{code removed}
Time.days_in_month.

–Greg

You still didn’t run it, did you?

Don’t sigh at me. I wrote some code off the cuff and fired it off. I
also
didn’t include unit tests. Yes, it was buggy and inefficient, but it
got
across the approach I was using.

The point is applicable to everyone:

“Don’t present code that you haven’t actually
run unless you say that you haven’t run it.”

You’ll just end up confusing the OP or other readers that may benefit
from
the code. If you’re trying to illustrate a point or an approach, say so
or make it quite clear that your code is incomplete or intended as
pseudo-code (particularly if it appears to be valid syntax).

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

Gregory S. wrote:

Don’t sigh at me. I wrote some code off the cuff and fired it off. I
also
didn’t include unit tests. Yes, it was buggy and inefficient, but it got
across the approach I was using.

Thanks for caring, however this isn’t a creative writing forum.

On Thu, Feb 28, 2008 at 03:29:54AM +0900, Brian A. wrote:

month and the correct number of days. I have it so that it starts
next_month = first + 32
(next_month + next_month.mday).mday

Anyhow, it’s worth noting that ActiveSupport includes Time.days_in_month.

–Greg

You still didn’t run it, did you?

Don’t sigh at me. I wrote some code off the cuff and fired it off. I
also
didn’t include unit tests. Yes, it was buggy and inefficient, but it got
across the approach I was using.

Some ideas you may want to consider:

  1. it’s probably reasonable to expect numeric month and day arguments,
    so you can skip the .to_i calls

Given that it was for clarity, I think it’s valuable.

  1. instead of creating a range, converting it to an array and calling
    include?, wouldn’t it be better to just use a simple comparison such
    as "unless month > 0 && month < 13

Arguable. I prefer range inclusion to a pair of comparisons, but that’s
a
matter of taste. The to_a only matters if I hadn’t performed a to_i on
the
month argument previously.

  1. sprintf’ing a date just to parse it is unnecessary & inefficient

True enough. Date.new (a.k.a. Date.civil) takes year, month, and day
arguments. For that matter, as pointed out elsewhere in this thread, a
-1
for the day argument gives the last day of the month, making the rest of
the method moot.

  1. it’s still broken

Typo. The + should have been a - in the correction. The correct, if
unnecessary, method is:

require ‘date’

def days_in_month(month, year)
month = month.to_i
year = year.to_i
raise ArgumentError.new(“invalid month”) unless (1…12).include? month
first = Date.civil(year, month, 1)
next_month = first + 32
(next_month - next_month.mday).mday
end

An even simpler method, taken from elsewhere in the thread:

require ‘date’

def days_in_month(month, year)
Date.civil(year, month, -1).mday
end

–Greg

On Wed, Feb 27, 2008 at 2:14 PM, Rob B.
[email protected] wrote:

-Rob

I frequently write bad code when I use a system where I cannot cut and
paste. All code on a forum, IMHO, should be taken with a grain of
salt. I don’t think posted code needs to be perfect.

2c,
Todd

Morton G. wrote:

require "Date" d = Date.new(2008, 2, -1) d.day # => 29 Regards, Morton

This is what I ened up using and it seems to work. Thanks,

-S

Rob B. wrote:

The point is applicable to everyone:

“Don’t present code that you haven’t actually
run unless you say that you haven’t run it.”

Nah, better to let dubious code pop up now and then so that people are
not lulled into a false sense of security, and will hopefully realize
that, even if someone says they ran and tested the code and assure you
it’s fine, the code may still be bad.


James B.

“In physics the truth is rarely perfectly clear, and that is certainly
universally the case in human affairs. Hence, what is not surrounded
by
uncertainty cannot be the truth.”

  • R. Feynman

On Feb 27, 10:17 am, Shandy N. [email protected] wrote:

Posted viahttp://www.ruby-forum.com/.
Awk (not my code):

function days_in_month( y, m )
{
return m==2 ? 28+!(y%4)-!(y%100)+!(y%400) : 30+(m%2 != (m>7))
}

A more interesting question is how do you get the number of weeks in a
year.
Some years have 52…some have 54. Calendar weeks…not 7 day weeks.

S

On 2/28/08, Serg K. [email protected] wrote:

A more interesting question is how do you get the number of weeks in a
year.
Some years have 52…some have 54. Calendar weeks…not 7 day weeks.

I assume you mean here how many 7 day weeks starting on a particular
week day have at least one day in a given year.

If this is the case then in all but one case every year has 53
‘weeks.’ The only exception is a leap year which starts on the last
day of the week which has 54 weeks.

for start in (1…7) do
for days in (365…366) do
s = “a #{{365 => ‘normal’, 366 => ‘leap’}[days]} year starting on
weekday #{start} starts with "
start_week_days = start == 1 ? 0 : (8 - start)
s << “a ‘week’ of #{start_week_days} days then " unless
start_week_days == 0
days_remaining = days - start_week_days
full_weeks = days_remaining / 7
end_week_days = days_remaining % 7
s << “#{full_weeks} full weeks”
s << " and ends with a ‘week’ of #{end_week_days} days” unless
end_week_days == 0
s << " a total of #{(start_week_days > 0 ? 1 : 0) + full_weeks +
(end_week_days > 0 ? 1 : 0)} ‘weeks.’”
puts s
end
puts
end

a normal year starting on weekday 1 starts with 52 full weeks and ends
with a ‘week’ of 1 days a total of 53 ‘weeks.’
a leap year starting on weekday 1 starts with 52 full weeks and ends
with a ‘week’ of 2 days a total of 53 ‘weeks.’

a normal year starting on weekday 2 starts with a ‘week’ of 6 days
then 51 full weeks and ends with a ‘week’ of 2 days a total of 53
‘weeks.’
a leap year starting on weekday 2 starts with a ‘week’ of 6 days then
51 full weeks and ends with a ‘week’ of 3 days a total of 53 ‘weeks.’

a normal year starting on weekday 3 starts with a ‘week’ of 5 days
then 51 full weeks and ends with a ‘week’ of 3 days a total of 53
‘weeks.’
a leap year starting on weekday 3 starts with a ‘week’ of 5 days then
51 full weeks and ends with a ‘week’ of 4 days a total of 53 ‘weeks.’

a normal year starting on weekday 4 starts with a ‘week’ of 4 days
then 51 full weeks and ends with a ‘week’ of 4 days a total of 53
‘weeks.’
a leap year starting on weekday 4 starts with a ‘week’ of 4 days then
51 full weeks and ends with a ‘week’ of 5 days a total of 53 ‘weeks.’

a normal year starting on weekday 5 starts with a ‘week’ of 3 days
then 51 full weeks and ends with a ‘week’ of 5 days a total of 53
‘weeks.’
a leap year starting on weekday 5 starts with a ‘week’ of 3 days then
51 full weeks and ends with a ‘week’ of 6 days a total of 53 ‘weeks.’

a normal year starting on weekday 6 starts with a ‘week’ of 2 days
then 51 full weeks and ends with a ‘week’ of 6 days a total of 53
‘weeks.’
a leap year starting on weekday 6 starts with a ‘week’ of 2 days then
52 full weeks a total of 53 ‘weeks.’

a normal year starting on weekday 7 starts with a ‘week’ of 1 days
then 52 full weeks a total of 53 ‘weeks.’
a leap year starting on weekday 7 starts with a ‘week’ of 1 days then
52 full weeks and ends with a ‘week’ of 1 days a total of 54 ‘weeks.’

Or did you mean something else.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Brian A. wrote:

the calendar should redisplay itself properly formated showing the new

This may be a bit of a silly question, but this problem came up for me
recently and I wasn’t able to solve it actually. I did it another way
and I’ll put the code at the end.

If you look at the documentation for the Time class -
http://www.ruby-doc.org/core/classes/Time.html
it has the following:

LeapYearMonthDays = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30,
31]
CommonYearMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31,
30, 31]

Why can’t I access these constants directly? Perhaps, my Ruby knowledge
is a bit lacking, but I guessed that if I could access that, I could
have just used that :-S

Anyway, this is a snippet of what I used eventually for getting the
number of days in a month. It’s not as short as some of the others, but
I like it :slight_smile:

require ‘time’
require ‘date’

#t is a full date from which we use t.month to find the month for which
you want the number of days
LeapYearMonthDays = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30,
31]
CommonYearMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if Date.gregorian_leap?(t.year)
days_of_months = LeapYearMonthDays
else
days_of_months = CommonYearMonthDays
end

puts “There are #{days_of_months[t.month]} days in this month.”

Yes, it’s not tested - it’s been snipped out of a running application,
though.

Cheers,
Mohit.
2/29/2008 | 1:35 PM.