Forum: Ruby [newbie] this month, the next month, and the one after that

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Mason K. (Guest)
on 2006-01-16 21:45
What I want to do is simple.

I'd like code that prints out the name of this month (January) the next
month (February) and the one after that (March)

I've been able to print this month:

<% t = Time.now %>
<%= t.strftime(" This Month is: %B") %>

But I can't figure out how to get the next months to print out!
Detlef R. (Guest)
on 2006-01-17 02:24
(Received via mailing list)
Am Dienstag, den 17.01.2006, 04:45 +0900 schrieb Mason K.:
> But I can't figure out how to get the next months to print out!
>

Try this:

irb(main):040:0* t = Time.now
=> Mon Jan 16 21:27:58 CET 2006
irb(main):041:0> m = t.mon
=> 1
irb(main):042:0> nt = Time.mktime 2006, m + 1
=> Wed Feb 01 00:00:00 CET 2006
irb(main):043:0> p nt.strftime("%B")
"February"
=> nil
irb(main):044:0> nt = Time.mktime 2006, m + 2
=> Wed Mar 01 00:00:00 CET 2006
irb(main):045:0> p nt.strftime("%B")
"March"
=> nil


Cheers
detlef
David V. (Guest)
on 2006-01-17 02:42
(Received via mailing list)
On Mon, 16 Jan 2006 21:42:52 +0100, Detlef R.
<removed_email_address@domain.invalid>
wrote:

>>
> => Wed Feb 01 00:00:00 CET 2006
> Cheers
> detlef
>
>


Time#mktime. D'oh. I feel so dense for not remembering that one.

David V.
Jonathan L. (Guest)
on 2006-01-17 03:16
(Received via mailing list)
On Tue, 2006-01-17 at 04:45 +0900, Mason K. wrote:
> But I can't figure out how to get the next months to print out!
Well you'd add the month, expressed in seconds, to the current time.
That would be:

irb(main):001:0> puts (Time.now + 60 * 60 * 24 * 30).strftime("Next
month is %B")
Next month is February
=> nil

(Assuming a month is thirty days)

You are probably using Rails (I assume), so you can do this instead:

irb(main):002:0> require_gem 'activerecord'
=> true
irb(main):003:0> puts (Time.now + 1.month).strftime("Next month is %B")
Next month is February
=> nil

Again, that assumes a month is thirty days. A more reliable way would be
to find the next month, work out its length in seconds (precisely), and
then add it to Time.now.

Jon
David V. (Guest)
on 2006-01-17 03:16
(Received via mailing list)
On Mon, 16 Jan 2006 20:45:18 +0100, Mason K.
<removed_email_address@domain.invalid> wrote:

> But I can't figure out how to get the next months to print out!
>


My first guess would be requiring "datetime", and then looking up the
month name per DateTime::MONTHNAMES[t.month + 1].

Mind you, DateTime::MONTHNAMES is one-indexed, starting from January, so
you'll have to do some index-shiftingto wrap around the end of the array
correctly. And since there's very little I hate more than shifting array
indices around, the exercise is left to the reader ;P

When I think about it, DateTime::MONTHNAMES[1..12][t.month % 12] should
work perfectly for the next month, with (t.month + 1) for the one after
that, etc.

David V.
A LeDonne (Guest)
on 2006-01-17 18:07
(Received via mailing list)
On 1/16/06, Detlef R. <removed_email_address@domain.invalid> wrote:
> >
> => Wed Feb 01 00:00:00 CET 2006
> Cheers
> detlef
>

Along with Time.mktime, there are Date methods to shift dates by a
number of months... Date#>> and Date#<< . Which you use depends on
whether you need Dates or Times.

irb(main):022:0> require 'date'
=> true
irb(main):023:0> bob = Date.today()
=> #<Date: 4907505/2,0,2299161>
irb(main):024:0> puts bob.strftime()
2006-01-17
=> nil
irb(main):025:0> puts bob.strftime("%B")
January
=> nil
irb(main):026:0> nextmonth = bob >> 1
=> #<Date: 4907567/2,0,2299161>
irb(main):027:0> puts nextmonth.strftime()
2006-02-17
=> nil
irb(main):028:0> puts nextmonth.strftime("%B")
February
=> nil
irb(main):029:0> one_after_that = bob >> 2
=> #<Date: 4907623/2,0,2299161>
irb(main):030:0> puts one_after_that.strftime()
2006-03-17
=> nil
irb(main):031:0> puts one_after_that.strftime("%B")
March
=> nil

-A
unknown (Guest)
on 2006-01-21 16:40
(Received via mailing list)
On Tue, 17 Jan 2006, Detlef R. wrote:

> => nil
> irb(main):044:0> nt = Time.mktime 2006, m + 2
> => Wed Mar 01 00:00:00 CET 2006
> irb(main):045:0> p nt.strftime("%B")
> "March"
> => nil

but

   harp:~ > ruby -e'  p(Time::mktime(2006,13))  '
   -e:1:in `mktime': argument out of range (ArgumentError)
           from -e:1


i prefer the stupid approach:

     harp:~ > cat a.rb
     class Time
       def this_month
         strftime '%b'
       end
       def next_month n = 1
         t = dup
         s = 60 * 60 * 24
         n.times{ m = t.month; t += s until t.month != m }
         t.strftime '%b'
       end
     end

     t = Time::mktime 2006, 12
     p t.this_month
     p t.next_month
     p t.next_month(2)


     harp:~ > ruby a.rb
     "Dec"
     "Jan"
     "Feb"


regards.

-a
Detlef R. (Guest)
on 2006-01-21 16:40
(Received via mailing list)
Am Dienstag, den 17.01.2006, 07:06 +0900 schrieb 
removed_email_address@domain.invalid:
> > irb(main):043:0> p nt.strftime("%B")
>    harp:~ > ruby -e'  p(Time::mktime(2006,13))  '
>    -e:1:in `mktime': argument out of range (ArgumentError)
>            from -e:1
>
>
OK

â?º: p(Time::mktime(2006,(13%12)))
Sun Jan 01 00:00:00 CET 2006


>          n.times{ m = t.month; t += s until t.month != m }
Outch :-) found no good logic? who cares, lets do it with brute force
James G. (Guest)
on 2006-01-21 16:40
(Received via mailing list)
On Jan 16, 2006, at 2:29 PM, David V. wrote:

> Mind you, DateTime::MONTHNAMES is one-indexed, starting from January,

We can fix that.  ;)

> so you'll have to do some index-shiftingto wrap around the end of
> the array correctly. And since there's very little I hate more than
> shifting array indices around, the exercise is left to the reader ;P

Okay, I'll bite:

 >> current = Time.now.strftime("%B")
=> "January"
 >> require "date"
=> true
 >> months = (Date::MONTHNAMES + Date::MONTHNAMES).compact
=> ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December", "January",
"February", "March", "April", "May", "June", "July", "August",
"September", "October", "November", "December"]
 >> three_months = months[months.index(current), 3]
=> ["January", "February", "March"]

James Edward G. II
David V. (Guest)
on 2006-01-21 16:40
(Received via mailing list)
On Mon, 16 Jan 2006 21:55:40 +0100, James Edward G. II
<removed_email_address@domain.invalid> wrote:

> Okay, I'll bite:
>  >> three_months = months[months.index(current), 3]
> => ["January", "February", "March"]
>
> James Edward G. II
>
>


Ye gods, that's so idiot-proof it ain't pretty anymore amd I let my
brain
spin around index shifts.. I've been doing WAAAY too much Java at work.
Help, my 1337 Rüby h@xx0r skills are disappearing! *sic*

David V.
unknown (Guest)
on 2006-01-21 16:44
(Received via mailing list)
On Tue, 17 Jan 2006, Detlef R. wrote:

> OK
>
> â?º: p(Time::mktime(2006,(13%12)))
> Sun Jan 01 00:00:00 CET 2006

   harp:~ > irb
   irb(main):001:0> p(Time::mktime(2006,(48%12)))
   ArgumentError: argument out of range
           from (irb):1:in `mktime'
           from (irb):1


you need

     t = Time::now
     n = 48
     n = (t.month + n) % 12
     (n == 0 ? t : Time::mktime(1970, n)).strftime('%b')

sorry, couldn't resist!  ;-)

>>          s = 60 * 60 * 24
>>          n.times{ m = t.month; t += s until t.month != m }
>
> Outch :-) found no good logic? who cares, lets do it with brute force

hey!  i said it was stupid ;-)

cheers.

-a
unknown (Guest)
on 2006-01-21 16:44
(Received via mailing list)
On Tue, 17 Jan 2006, James Edward G. II wrote:

> Okay, I'll bite:
>>> three_months = months[months.index(current), 3]
> => ["January", "February", "March"]

but

   irb(main):005:0> months[months.index(current), 42].size
   => 24

not good if the app is a mortage calculator!  ;-)

-a
Detlef R. (Guest)
on 2006-01-21 16:44
(Received via mailing list)
Am Dienstag, den 17.01.2006, 05:55 +0900 schrieb James Edward G. II:
> Okay, I'll bite:
>  >> three_months = months[months.index(current), 3]
> => ["January", "February", "March"]
>
i don't like redundant data...


irb(main):042:0* current = Time.now.mon
=> 1
irb(main):043:0> require "date"
=> false
irb(main):044:0> months = Date::MONTHNAMES.compact
=> ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"]
irb(main):045:0> three_month = []
=> []
irb(main):046:0> (0..2).each {|i| three_month << months[(i+current-1) %
12]}
=> 0..2
irb(main):047:0> p three_month
["January", "February", "March"]
=> nil

detlef
David B. (Guest)
on 2006-01-21 16:44
(Received via mailing list)
removed_email_address@domain.invalid wrote:

>   irb(main):005:0> months[months.index(current), 42].size
>   => 24
>
> not good if the app is a mortage calculator!  ;-)

Sorry if this response is too late to be useful to anyone, but here's a
solution that surprised me with its elegance.  I read the OP and
immediately thought, "Oh, just spin forward 86,400 (seconds per day)
until the month changes" and, of course, someone had already posted this
reply.  However, I wrote some code as a youth that played with dates
using division and moduli, and this post got me reminiscing on that.
Here's a resurrected version.  I was very pleased to discover it handles
negative numbers, which made writing Time#prev_month trivial and
elegant.

class Time
  def next_month n=1
    t = Time::mktime year + Integer(n)/12, ((month+n-1)%12)+1
    t.strftime "%B"
  end

  def prev_month n=1
    next_month -n
  end
end

Cheers, and thanks for asking an interesting question!

-dB
This topic is locked and can not be replied to.