# A clean way to edit a time?

**URL:** <https://www.ruby-forum.com/t/a-clean-way-to-edit-a-time/171923>\
**Category:** Ruby\
**Created:** [July 11, 2009, 4:02pm UTC](https://www.ruby-forum.com/t/a-clean-way-to-edit-a-time/171923 "2009-07-11T16:02:47Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![cmaxvv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/85f322/32.png) [@cmaxvv](https://www.ruby-forum.com/u/cmaxvv)\
**Post date:** [July 11, 2009, 4:02pm UTC](https://www.ruby-forum.com/t/a-clean-way-to-edit-a-time/171923/1 "2009-07-11T16:02:47Z")

</div>

Hi all

I have a method, created\_at=, which takes a time or a string, and  
changes a Time field, created\_at, accordingly. If we get a time, then  
it’s easy: just set created\_at to be the given time.

However, if we get a string, it’s going to be only a date, like  
“11/07/09”, and in this case i want to update only the day, month and  
year of created\_at, and leave the rest alone. In some cases, like when  
a new record is made, then there will be no value in created\_at, so the  
method should cope with the current value of created\_at being nil (i do  
this by setting the time to Time.now before updating it with the new  
values).

Currently i have this which feels like a bit of a hacky mess. Can  
anyone show me a cleaner solution?

```
def created_at=(time)
  if time.kind_of?(Time)
    self[:created_at] = time
  elsif time.kind_of?(String)
    begin
      parsed_time = DateTime.strptime(time, "%d/%m/%y")
      old_time = self.created_at || Time.now
      return self[:created_at] = Time.local(parsed_time.year,

```

parsed\_time.month, parsed\_time.day, old\_time.hour, old\_time.min,  
old\_time.sec)  
rescue  
return false  
end  
end  
end

Also, i can’t get it to return the new time value, and it doesn’t return  
false if it raises the exception. In either case it just returns the  
string that i passed to it. It’s not vital that it return the new  
created\_at value (or false) but it would be nice.

I’m doing this in a framework based on Ramaze so maybe the last point is  
due to something inherited from that.

thanks!  
max

---

<div class="post-metadata">

**Author:** ![cmaxvv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/85f322/32.png) [@cmaxvv](https://www.ruby-forum.com/u/cmaxvv)\
**Post date:** [July 12, 2009, 3:15pm UTC](https://www.ruby-forum.com/t/a-clean-way-to-edit-a-time/171923/2 "2009-07-12T15:15:36Z")

</div>

Hi –

On Sat, 11 Jul 2009, Max W. wrote:

> method should cope with the current value of created\_at being nil (i do  
> elsif time.kind\_of?(String)  
> end
> 
> Also, i can’t get it to return the new time value, and it doesn’t return  
> false if it raises the exception. In either case it just returns the  
> string that i passed to it. It’s not vital that it return the new  
> created\_at value (or false) but it would be nice.

To start with the last point: the setter methods are engineered to  
look like and behave like assignments. So when you do this:

obj.x = y

it always returns y. It’s emulating assignment semantics:

x = y # always returns y

So using ‘return’ with an argument in those methods doesn’t work.

As for your main question: I’m not sure whether this does exactly what  
you want (though I’ve got some tests that suggest perhaps it does),  
but here’s a version that might at least give you some ideas:

require ‘time’

class Thing  
attr\_reader :created\_at

def created\_at=(new\_time)  
if new\_time == new\_time.to\_s  
now = Time.now  
str = “#{new\_time} #{now.strftime(’%H:%M:%S’)}”  
@created\_at = Time.parse(str)  
else  
@created\_at = new\_time  
end  
end  
end

The idea, as you can see, is to piece together a string that contains  
the year, month, and day from the string that was passed in, plus the  
hour, minute, and second from Time.now. I think it does what you want  
with correct input, though some further checking for correctness might  
be in order.

David

---

<div class="post-metadata">

**Author:** ![cmaxvv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/85f322/32.png) [@cmaxvv](https://www.ruby-forum.com/u/cmaxvv)\
**Post date:** [July 12, 2009, 4:08pm UTC](https://www.ruby-forum.com/t/a-clean-way-to-edit-a-time/171923/3 "2009-07-12T16:08:46Z")

</div>

On Sun, Jul 12, 2009 at 9:14 AM, David A. Black[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> To start with the last point: the setter methods are engineered to  
> look like and behave like assignments. So when you do this:
> 
> obj.x = y
> 
> it always returns y. It’s emulating assignment semantics:
> 
> x = y # always returns y
> 
> So using ‘return’ with an argument in those methods doesn’t work.

I think to be brutally correct, it’s not that a return in a setter  
method doesn’t work it’s that

obj.x = y

will call the setter method with y as the argument, and discard any  
return value. The value of the assignment expression will always be  
the value of y, not the value returned by the setter method.

whereas obj.send(“x=”, y) will evaluate to the return value of the  
setter.

class Foo  
attr\_reader :x\_squared  
def x=(value)  
@x\_squared = value \* value  
end  
end

obj = Foo.new

obj.x = 4 # =\> 4  
obj.x\_squared # =\> 16

obj.send(“x=”, 3) # =\> 9  
obj.x\_squared # =\> 9

–  
Rick DeNatale

Blog: [http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)  
Twitter: [http://twitter.com/RickDeNatale](http://twitter.com/RickDeNatale)  
WWR: [http://www.workingwithrails.com/person/9021-rick-denatale](http://www.workingwithrails.com/person/9021-rick-denatale)  
LinkedIn: [http://www.linkedin.com/in/rickdenatale](http://www.linkedin.com/in/rickdenatale)
