Trouble advancing date attribute

I’m trying to update the ‘date_due’ attribute of a ‘client’ object with
the following function:

    new_date_due = @client.date_due + 1.month
    @ client.update_attribute(: date_due, new_date_due)

Instead of simply advancing date_due a month from it’s present date
(2007-11-11) it advances it 7 millennia into the future (9104-07-08).
Given the rate the dollar’s falling, my clients probably can’t afford to
wait that long to collect payments. I’m guessing there’s something wrong
with the date formats I’m trying to add. Any idea how I could fix this?

Thanks,

Peter

Try this:

@client.update_attribute(: date_due, new_date_due.to_s(:db))

-Bill

William P. wrote:

Try this:

@client.update_attribute(: date_due, new_date_due.to_s(:db))

-Bill

Same result I’m afraid. But thanks for the idea Bill.

For what it’s worth, I’m using a MySQL db with this app.

Try this

@ client.update_attribute(:date_due => new_date_due)

That is odd. I am using MySQL as well and I have no issues using the
same code. If you send the new_date_due to the log using:

logger.debug “The new date is #{new_date_due.to_s(:long)}”

Do you see the proper date being logged? That will at least tell us if
the problem is in your date calculation or in the update_attribute.

-Bill

Abhi M. wrote:

Try this

@ client.update_attribute(:date_due => new_date_due)

@client.update_attribute(:date_due => new_date_due)

is actually what I had (typoed on the colin space), but thanks Abhi.

It looks like my problem is in the “+ 30.days” part as this code returns
as 9104-07-08 in my view.

Yes, I was just looking at that. The + method for dates takes an
argument of days, so I bet this works:

new_date_due = @client.date_due + 30
@client.update_attribute(: date_due, new_date_due)

-Bill

Hi
one more thing have u used in the code like

@client = “database name”.find(“id”)
(fill the database name and primary key(id)). I think then only will it
be updated

Hi
one more thing have u used in the code like

@client = “database name”.find(“id”)
(fill the database name and primary key(id)). I think then only will it
be updated

Any way all the best and please tell what was the prob when you find
solution

Thanks guys. The “+ 30.days” was indeed the problem. “+ 30”, as you
suggested Bill, took care of that. Ideally I would like to advance
date_due in terms of months (not sure if that’s practical) and limit the
initial date_due to between the 1st and the 28th of a month. Anyone know
of a clean way to do this?

Thanks again for the help guys. This will work for now anyway :slight_smile:

If you need it one month to the day rather than x days, this works

old_due = @client.date_due
@client.update_attribute(: date_due, Date.new(old_due.year,
old_due.month + 1, old_due.day))

-Bill

Peter M. wrote:

William P. wrote:

If you need it one month to the day rather than x days, this works

old_due = @client.date_due
@client.update_attribute(: date_due, Date.new(old_due.year,
old_due.month + 1, old_due.day))

-Bill

Ha, you read my mind! This is a great start. I’ll need to tweak this to
manage a new year, but thanks!

Peter

Perhaps not the most elegant chunk of code, but this seems to work:

old_due = @ client.date_due
if old_due.month == 12
@client.update_attribute(:date_due, Date.new(old_due.year + 1, 1,
old_due.day))
else
@client.update_attribute(:date_due, Date.new(old_due.year,
old_due.month + 1, old_due.day))
end

William P. wrote:

If you need it one month to the day rather than x days, this works

old_due = @client.date_due
@client.update_attribute(: date_due, Date.new(old_due.year,
old_due.month + 1, old_due.day))

-Bill

Ha, you read my mind! This is a great start. I’ll need to tweak this to
manage a new year, but thanks!

Peter

Yep, I was just writing up another email about the year bug I added. I
do something similar when generating saved reports using date ranges.
I use mysql’s built in date functions like this one:

select DATE_ADD(‘2007-01-02’, INTERVAL 1 MONTH);

You can see a full list here:
http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_adddate

I actually pass in a string something like:

Client.update(@client.id, “date_due =
DATE_ADD(‘#{@client.date_due.to_s(:db)}’, INTERVAL 1 MONTH)”)

I don’t actually use it with update_attributes, but rather with a
select, but this should work. Note that update skips any validation or
other callbacks, but if that doesn’t matter and you don’t care that
this ties you to mysql, this will do what you want. There are bound to
be other ways, but this is pretty easy.

-Bill

William P. wrote:

Yep, I was just writing up another email about the year bug I added. I
do something similar when generating saved reports using date ranges.
I use mysql’s built in date functions like this one:

select DATE_ADD(‘2007-01-02’, INTERVAL 1 MONTH);

You can see a full list here:
http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_adddate

I actually pass in a string something like:

Client.update(@client.id, “date_due =
DATE_ADD(‘#{@client.date_due.to_s(:db)}’, INTERVAL 1 MONTH)”)

I don’t actually use it with update_attributes, but rather with a
select, but this should work. Note that update skips any validation or
other callbacks, but if that doesn’t matter and you don’t care that
this ties you to mysql, this will do what you want. There are bound to
be other ways, but this is pretty easy.

-Bill

Nice Bill. I’ll play around with that. Thanks for your continued support
and advice. Because of people like you, my first rails app (which is far
too large and ambitious) is coming along great.

-Peter

On 12 Nov 2007, at 04:22, Peter M. wrote:

Perhaps not the most elegant chunk of code, but this seems to work:

old_due = @ client.date_due
if old_due.month == 12
@client.update_attribute(:date_due, Date.new(old_due.year + 1, 1,
old_due.day))
else
@client.update_attribute(:date_due, Date.new(old_due.year,
old_due.month + 1, old_due.day))
end

I think i’d rather do
new_due = old_due >> 1

If you are going to roll your own version you need to worry about
things like adding a month to the 31st of august (your code will try
and set the date to the 31st of september, which will fail.
:slight_smile:

Fred

Thank you Mr.William P. for sharing that great link with us. I have
been reading your posts and hope you will continue this good work of
replying the post in coming days

Thanks, thats great. I knew there had to be a way to do it, but I have
missed that operator when looking at the docs. Thanks again.

-Bill

Frederick C. wrote:

@client.update_attribute(:date_due, Date.new(old_due.year + 1, 1,
If you are going to roll your own version you need to worry about
things like adding a month to the 31st of august (your code will try
and set the date to the 31st of september, which will fail.
:slight_smile:

Fred


Sincerely,

William P.

On Nov 11, 2007 10:58 PM, Peter M. [email protected]
wrote:

Thanks guys. The “+ 30.days” was indeed the problem. “+ 30”, as you
suggested Bill, took care of that. Ideally I would like to advance
date_due in terms of months (not sure if that’s practical) and limit the
initial date_due to between the 1st and the 28th of a month. Anyone know
of a clean way to do this?

Thanks again for the help guys. This will work for now anyway :slight_smile:

Try new_date_due = @client.date_due >> 1

Date#+ takes a number of days as the argument.

Date#>> returns a new date “right shifted” some number of months.
use Date#<< to get a date some number of months ago.

shadowfax:~/Documents/terralien/dltsolutions/enrollnow rick$ qri
“Date#>>”
---------------------------------------------------------------- Date#>>
>>(n)

 Return a new Date object that is n months later than the current
 one.

 If the day-of-the-month of the current Date is greater than the
 last day of the target month, the day-of-the-month of the returned
 Date will be the last day of the target month.

shadowfax:~/Documents/terralien/dltsolutions/enrollnow rick$ qri
“Date#<<”
---------------------------------------------------------------- Date#<<
<<(n)

 Return a new Date object that is n months earlier than the current
 one.

 If the day-of-the-month of the current Date is greater than the
 last day of the target month, the day-of-the-month of the returned
 Date will be the last day of the target month.

shadowfax:~/Documents/terralien/dltsolutions/enrollnow rick$ qri
“Date#+”
----------------------------------------------------------------- Date#+
+(n)

 Return a new Date object that is n days later than the current one.

 n may be a negative value, in which case the new Date is earlier
 than the current one; however, #-() might be more intuitive.

 If n is not a Numeric, a TypeError will be thrown. In particular,
 two Dates cannot be added to each other.


Rick DeNatale

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

On 12 Nov 2007, at 03:47, Peter M. wrote:

It looks like my problem is in the “+ 30.days” part as this code
returns
as 9104-07-08 in my view.

That is definitely the problem

30.days evaluates to the number of seconds in 30 days (ie 30*86400 =
2592000)

This is great when you’re working with an instance of Time because +
is used to mean ‘add this many seconds’. However, for Date, + means
‘add this many days’.
So Date.new(2007,11,12) + 30.days is actually add 2592000 days (around
7100 years).

Fred