Finding the last Sunday of a month

P

Peter Bailey

Hello,
I need to find the date for the last Sunday in January, for any year. I
need this for a budgetary script I'm trying to write. Using the
Date/Time module, I've done this so far.

require 'date'
now = DateTime.now
year = now.year
d = Date.new(now.year, 1, 31)
puts d.wday

yields: 3

This tells me that the last day of January is a Wednesday. But, I need
that last Sunday. Is there a method in 'date' that can give me the date
of the last Sunday? The last Sundays of each month are the boundaries
for my company's budget periods.

Thanks,
Peter
 
R

Robert Dober

Hello,
I need to find the date for the last Sunday in January, for any year. I
need this for a budgetary script I'm trying to write. Using the
Date/Time module, I've done this so far.

require 'date'
now = DateTime.now
year = now.year
d = Date.new(now.year, 1, 31)
puts d.wday

Hmm I believe that
d = Date.new( now.year, 1, 31 )
d - d.wday
should do the trick
HTH
Robert
 
M

Mohit Sindhwani

Peter said:
Hello,
I need to find the date for the last Sunday in January, for any year. I
need this for a budgetary script I'm trying to write. Using the
Date/Time module, I've done this so far.

require 'date'
now = DateTime.now
year = now.year
d = Date.new(now.year, 1, 31)
puts d.wday

yields: 3

The last Sunday of that month can be got this way, I think:

require 'date'
now = DateTime.now
year = now.year
d = Date.new(now.year, 1, 31)
i = d.wday
last_sunday = Date.new(now.year, 1, (31-i))
puts last_sunday

The reference for dates is at:
http://corelib.rubyonrails.org/classes/Date.html

Cheers
mohit.
 
Y

Yossef Mendelssohn

Hello,
I need to find the date for the last Sunday in January, for any year. I
need this for a budgetary script I'm trying to write. Using the
Date/Time module, I've done this so far.

require 'date'
now = DateTime.now
year = now.year
d = Date.new(now.year, 1, 31)
puts d.wday

yields: 3

This tells me that the last day of January is a Wednesday. But, I need
that last Sunday. Is there a method in 'date' that can give me the date
of the last Sunday? The last Sundays of each month are the boundaries
for my company's budget periods.

Thanks,
Peter

Not perfect, but something like this:

Cassady:~ yossef$ irb
irb(main):001:0> require 'date'
=> true
irb(main):002:0> d = Date.new(2007, 2, 1)
=> #<Date: 4908265/2,0,2299161>
irb(main):003:0> d.to_s
=> "2007-02-01"
irb(main):004:0> d -= 1
=> #<Date: 4908263/2,0,2299161>
irb(main):005:0> d.to_s
=> "2007-01-31"
irb(main):006:0> d -= d.wday
=> #<Date: 4908257/2,0,2299161>
irb(main):007:0> d.to_s
=> "2007-01-28"
irb(main):008:0> exit
Cassady:~ yossef$ cal 1 2007
January 2007
S M Tu W Th F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31


The "secret", as I see it, is getting the last day of the month and
subtracting that date's wday from it.

Note that I start by getting the first day of the next month and going
back one day. I'm not sure about a sure-fire way to always get the
last day of a month by going forward (because you can get errors
trying to hit the 31st of September), but going back one day from the
first of the next month should work just fine.
 
P

Peter Bailey

Thanks to all of you. Mohit's worked for me. It's quite ingenious,
actually, because it's simply subtracing the date of the week, which is
3 for Wednesday, from 31, the last day of the month. 31 - 3 = 28, so,
Sunday is the 28th. I love Ruby!

Thanks again,
Peter
 
D

Dale Martenson

Not perfect, but something like this:

Cassady:~ yossef$ irb
irb(main):001:0> require 'date'
=> true
irb(main):002:0> d = Date.new(2007, 2, 1)
=> #<Date: 4908265/2,0,2299161>
irb(main):003:0> d.to_s
=> "2007-02-01"
irb(main):004:0> d -= 1
=> #<Date: 4908263/2,0,2299161>
irb(main):005:0> d.to_s
=> "2007-01-31"
irb(main):006:0> d -= d.wday
=> #<Date: 4908257/2,0,2299161>
irb(main):007:0> d.to_s
=> "2007-01-28"
irb(main):008:0> exit
Cassady:~ yossef$ cal 1 2007
January 2007
S M Tu W Th F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

The "secret", as I see it, is getting the last day of the month and
subtracting that date's wday from it.

Note that I start by getting the first day of the next month and going
back one day. I'm not sure about a sure-fire way to always get the
last day of a month by going forward (because you can get errors
trying to hit the 31st of September), but going back one day from the
first of the next month should work just fine.

I think using -1 as the day of month gets you the last day of the
month.

irb(main):002:0> d = Date.new(2007, 1, -1)
=> #<Date: 4908263/2,0,2299161>
irb(main):003:0> d.to_s
=> "2007-01-31"
irb(main):004:0> (d - d.wday).to_s
=> "2007-01-28"

--Dale
 
M

Mohit Sindhwani

Peter said:
Thanks to all of you. Mohit's worked for me. It's quite ingenious,
actually, because it's simply subtracing the date of the week, which is
3 for Wednesday, from 31, the last day of the month. 31 - 3 = 28, so,
Sunday is the 28th. I love Ruby!

Thanks again,
Peter

Actually, I think mine just reached your first but everyone had
essentially the same suggestion. By the way, the suggestion about
subtracting from the 1st of the next month is perhaps smarter! That
way, you don't hv to worry about what the last day of the month is (31,
30, 28, 29?) I think it's really smart to just avoid all of that and go
back from the start of the next month!

Cheers,
Mohit.
9/26/2007 | 10:11 PM.
 
P

Peter Bailey

Yes, thanks Joseff. That's what worked for me. Subtracting the "weekday"
from the "monthday."
 
P

Peter Bailey

Actually, I think mine just reached your first but everyone had
essentially the same suggestion. By the way, the suggestion about
subtracting from the 1st of the next month is perhaps smarter! That
way, you don't hv to worry about what the last day of the month is (31,
30, 28, 29?) I think it's really smart to just avoid all of that and go
back from the start of the next month!

Cheers,
Mohit.
9/26/2007 | 10:11 PM.


Point taken. You're right. Thanks.
 
Y

Yossef Mendelssohn

I think using -1 as the day of month gets you the last day of the
month.

irb(main):002:0> d = Date.new(2007, 1, -1)
=> #<Date: 4908263/2,0,2299161>
irb(main):003:0> d.to_s
=> "2007-01-31"
irb(main):004:0> (d - d.wday).to_s
=> "2007-01-28"

--Dale

Hey, you're right! At least that seems to work.

Thanks!

(Note: Getting this from you is apparently easier than reading the
documentation for Date.new (really Date.civil), which says "m and d
can be negative, in which case they count backwards from the end of
the year and the end of the month respectively.")
 
P

Peter Bailey

OK. Now, I've got that last Sunday's date in January. And, I've now
delineated all of the successive Sundays thereafter. Each of them is a
budgetary fencepost for me. So, can someone help me to determine what
budget period, out of all 13 of them, that today's date, or any day for
that matter, would fall into? I think that all of my budget dates below
are actually strings, so, they don't parse with dates as they are.

Thanks,
Peter

Here's what I have now. It works. I just need to see what today, or any
day, would fall into.

require 'date'
now = DateTime.now
year = now.year
d = Date.new(now.year, 2, 1)
d.to_s
d -= 1
d.to_s
d -= d.wday
i = d.wday
d.to_s
firstbudgetfence = d

t = Time.now
t = t.strftime("%Y-%m-%d")
budget1 = Date.new(now.year, 1, 1)
budget2 = firstbudgetfence
budget3 = firstbudgetfence + 28
budget4 = budget3 + 28
budget5 = budget4 + 28
budget6 = budget5 + 28
budget7 = budget6 + 28
budget8 = budget7 + 28
budget9 = budget8 + 28
budget10 = budget9 + 28
budget11 = budget10 + 28
budget12 = budget11 + 28
budget13 = budget12 + 28
 
M

Mohit Sindhwani

OK, I'm confused - is your budget fencepost the last Sunday or the
Sunday every 4 weeks from the end of Jan?

Cheers,
Mohit.
9/26/2007 | 10:56 PM.
 
P

Peter Bailey

Mohit said:
OK, I'm confused - is your budget fencepost the last Sunday or the
Sunday every 4 weeks from the end of Jan?

Cheers,
Mohit.
9/26/2007 | 10:56 PM.

It's a 28-day cycle, like a lunar cycle. The last Sunday in January is
the first fencepost, with the 1st budgetary period being from January 1
to that Sunday. Then, that Sunday is the first day of the 2nd budget
period, and so on.

But, I think I've got it now. My problem was my use of Time.now instead
of DateTime.now. DateTime.now allows me to compare these budgetary dates
with today's date. Thanks for everything.

Cheers,
Peter
 
M

Mohit Sindhwani

Anyway, if you have:

now = DateTime.now
this_month = now.month
this_budget_fencepost = \\\ based on what we discussed earlier ///

then, you can find the budget fencepost for today using that..

If your budget posts are every 4 weeks from the last Sunday of January,
you should be able to get the number of days since the first
num_of_days = this_budget_fencepost - first_fencepost
fencepost_number = num_of_days/ 28

You need to put in some check if the date is earlier than the first
fencepost and check the numbers it actually produces, but roughly that
should do it for you.

Cheers,
Mohit.
9/26/2007 | 10:59 PM.
 
P

Peter Bailey

Mohit said:
Anyway, if you have:

now = DateTime.now
this_month = now.month
this_budget_fencepost = \\\ based on what we discussed earlier ///

then, you can find the budget fencepost for today using that..

If your budget posts are every 4 weeks from the last Sunday of January,
you should be able to get the number of days since the first
num_of_days = this_budget_fencepost - first_fencepost
fencepost_number = num_of_days/ 28

You need to put in some check if the date is earlier than the first
fencepost and check the numbers it actually produces, but roughly that
should do it for you.

Cheers,
Mohit.
9/26/2007 | 10:59 PM.

I basically just did a comparsion for the time.now between each of the
budget periods. If between 0 and 1, then budget1; if between 1 and 2,
then budget2, and so on. A little painful, but it's done with about 12
lines of code. I can live with that. Thanks.
 
W

William James

Hello,
I need to find the date for the last Sunday in January, for any year. I
need this for a budgetary script I'm trying to write. Using the
Date/Time module, I've done this so far.

require 'date'
now = DateTime.now
year = now.year
d = Date.new(now.year, 1, 31)
puts d.wday

yields: 3

Just for fun:

y=`cal`[/\d+/]
d = `cal 1 #{y}`.scan(/^.{20}$/)[-1].
split[-1].to_i
 
M

Mohit Sindhwani

Peter said:
I basically just did a comparsion for the time.now between each of the
budget periods. If between 0 and 1, then budget1; if between 1 and 2,
then budget2, and so on. A little painful, but it's done with about 12
lines of code. I can live with that. Thanks.

Whatever works, I guess :)

I've always preferred a calculation to 12 comparisons. That way, it
scales well when the periods change - you just need to change a division
factor :) but like I said, whatever works for you!

By the way, are you calculating all 12 budget fenceposts every time you
need to find out which one the current day falls in?

There are numerous optimizations possible...
* You could consider putting all the budget posts in an array and
iterating over the array using a smaller loop code.
* You could check what month it is and check only the budget posts
(month-1) and (month) and (month+1). If I'm not wrong, no more than 3
budget periods will fall in the same month - it's a bit convoluted though :p
* If you are in fact creating the budget fenceposts as you go along, you
don't need to generate all 12.. just generate till you find the one you
are looking for.

Anyway, there are a few options - enjoy!

Cheers,
Mohit.
9/26/2007 | 11:38 PM.
 
L

Lloyd Linklater

I was at work and am getting into this one late, but there it is.

I would like to have something that handles the different month lengths,
and not just February. I checked to see what the value of a day was
this way:

p Time.gm(2007, 'feb', 2, 1, 1, 1) - Time.gm(2007, 'feb', 1, 1, 1, 1)

returns 86400 which is the number for exactly one day.

Therefore, I have this approach to get the day:

t = Time.gm(2007, 'feb', 1, 1, 1, 1) # to find for January
p (t - (one_day * t.wday)).day

:)
 
L

Lloyd Linklater

caveat time!

If the first of the month is Sunday, my code does not work. Here is a
working version:

one_day = 86400
t = Time.gm(2008, 'jun', 1, 1, 1, 1)
if t.wday == 0
t -= one_day
end
p (t - (one_day * t.wday)).day

Someone else can golf it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,008
Messages
2,570,270
Members
46,874
Latest member
CyberGateway

Latest Threads

Top