How to add one month or one week to a given Time?

Hi,

I want to add a given time difference to an Time object. My first idea was
to calculate the number of seconds of this time difference. This works for
values like hours or days, but when I want to add a month, the number of
seconds depends on the number of days in the given month.
My second idea was to use a vector to add the time:

@@sec = Vector[ 0, 0, 0, 0, 0, 1 ]
@@min = Vector[ 0, 0, 0, 0, 1, 0 ]
@@hour = Vector[ 0, 0, 0, 1, 0, 0 ]
@@day = Vector[ 0, 0, 1, 0, 0, 0 ]
@@week = Vector[ 0, 0, 7, 0, 0, 0 ]
@@month = Vector[ 0, 1, 0, 0, 0, 0 ]
@@year = Vector[ 1, 0, 0, 0, 0, 0 ]

def next! ( distance = @@year )
  return @next if ( 0 == distance )
  now = Time.now()
  values = Vector[ @next.year, @next.mon, @next.day,
   @next.hour, @next.min, @next.sec ]
  while ( @next.to_i() < now.to_i() )
   values += distance
   @next = Time.local( *values.to_a )
  end
  return @next
end

But this can result in an "argument out of range" error.

Has someone a simple solution for this problem?

Thanks,
Sven

Quoteing svenbauhan@web.de, on Mon, Jan 31, 2005 at 06:10:47AM +0900:

Hi,

I want to add a given time difference to an Time object. My first idea was
to calculate the number of seconds of this time difference. This works for
values like hours or days, but when I want to add a month, the number of
seconds depends on the number of days in the given month.

Yep, not as simple as you might hope.

I extend Time in my vPim package to do this. Here's the code, note that
it uses Date (since Date knows about oddities of leap minutes, days in
a month, leap years, etc.). Note the rounding effects.

If you are doing more stuff with dates and times, you might find other
useful code in vPim.

Cheers,
Sam

=begin
  $Id: time.rb,v 1.4 2004/11/17 05:06:27 sam Exp $

  Copyright (C) 2005 Sam Roberts

  This library is free software; you can redistribute it and/or modify it
  under the same terms as the ruby language itself, see the file COPYING for
  details.
=end

require 'date'

# Extensions to builtin Time allowing addition to Time by multiples of other
# intervals than a second.

class Time
    # Returns a new Time, +years+ later than this time. Feb 29 of a
    # leap year will be rounded up to Mar 1 if the target date is not a leap
    # year.
    def plus_year(years)
      Time.local(year + years, month, day, hour, min, sec, usec)
    end

    # Returns a new Time, +months+ later than this time. The day will be
    # rounded down if it is not valid for that month.
    # 31 plus 1 month will be on Feb 28!
    def plus_month(months)
      d = Date.new(year, month, day)
      d >>= months
      Time.local(d.year, d.month, d.day, hour, min, sec, usec)
    end

    # Returns a new Time, +days+ later than this time.
    # Does this do as I expect over DST? What if the hour doesn't exist
    # in the next day, due to DST changes?
    def plus_day(days)
      d = Date.new(year, month, day)
      d += days
      Time.local(d.year, d.month, d.day, hour, min, sec, usec)
    end
end

"Sven Bauhan" <svenbauhan@web.de> schrieb im Newsbeitrag news:3650khF4tato3U1@individual.net...

Hi,

I want to add a given time difference to an Time object. My first idea was
to calculate the number of seconds of this time difference. This works for
values like hours or days, but when I want to add a month, the number of
seconds depends on the number of days in the given month.
My second idea was to use a vector to add the time:

@@sec = Vector[ 0, 0, 0, 0, 0, 1 ]
@@min = Vector[ 0, 0, 0, 0, 1, 0 ]
@@hour = Vector[ 0, 0, 0, 1, 0, 0 ]
@@day = Vector[ 0, 0, 1, 0, 0, 0 ]
@@week = Vector[ 0, 0, 7, 0, 0, 0 ]
@@month = Vector[ 0, 1, 0, 0, 0, 0 ]
@@year = Vector[ 1, 0, 0, 0, 0, 0 ]

def next! ( distance = @@year )
return @next if ( 0 == distance )
now = Time.now()
values = Vector[ @next.year, @next.mon, @next.day,
  @next.hour, @next.min, @next.sec ]
while ( @next.to_i() < now.to_i() )
  values += distance
  @next = Time.local( *values.to_a )
end
return @next
end

But this can result in an "argument out of range" error.

Has someone a simple solution for this problem?

You can use the array representation of Time for some of the manipulations:

t = Time.now

=> Sun Jan 30 23:47:24 GMT+1:00 2005

a = t.to_a

=> [24, 47, 23, 30, 1, 2005, 0, 30, false, "GMT+1:00"]

a[4] += 1

=> 2

a

=> [24, 47, 23, 30, 2, 2005, 0, 30, false, "GMT+1:00"]

t2 = Time.local *a

=> Wed Mar 02 23:47:24 GMT+1:00 2005

Regards

    robert