Comparing time or ditching date in ruby on rails - ruby-on-rails

I have some time defined from my database, and this is how it looks:
ruby-1.9.2-p290 :017 > djel.smjena.pocetak1.to_time
=> 2000-01-01 08:00:00 +0100
and that is ok, it assigned me 2000-1-1
also, I got something that happened in some datetime
ruby-1.9.2-p290 :019 > dog.pocetak
=> Thu, 25 Aug 2011 08:18:00 UTC +00:00
So I was hoping, that .to_time would ditch my date, but that does not
happen
ruby-1.9.2-p290 :020 > dog.pocetak.to_time
=> Thu, 25 Aug 2011 08:18:00 UTC +00:00
so, now, comparing if something happened before 8:00 is useless.
So, how can I compare that? is there a way to set dog.pocetak to
2000-01-01 without touch clock?
thank you
p.s. also, I thought of creating new time variable, only to get from old variable hours and minutes, but this methods dont work?
ruby-1.9.2-p290 :059 > dog.pocetak.hour
=> 8
but
ruby-1.9.2-p290 :060 > dog.pocetak.minute
NoMethodError: undefined method `minute' for 2011-08-25 08:18:00 UTC:Time
from /home/dorijan/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.0.10/lib/active_support/time_with_zone.rb:322:in `method_missing'
from (irb):60
from /home/dorijan/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands/console.rb:44:in `start'
from /home/dorijan/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands/console.rb:8:in `start'
from /home/dorijan/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
ruby-1.9.2-p290 :061 > dog.pocetak.minutes
NoMethodError: undefined method `minutes' for 2011-08-25 08:18:00 UTC:Time
from /home/dorijan/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.0.10/lib/active_support/time_with_zone.rb:322:in `method_missing'
from (irb):61
from /home/dorijan/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands/console.rb:44:in `start'
from /home/dorijan/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands/console.rb:8:in `start'
from /home/dorijan/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
really frustrating :)

With ActiveSupport and Time.change you can reset the year, month and day if you like:
> t = Time.now
=> Sun Aug 21 00:46:29 +0000 2011
> t.change(:month => 1, :day => 1, :year => 2000)
=> Sat Jan 01 00:46:29 +0000 2000
This way you could compare the "times" between each other, if they all were reset to the same date. Not sure if this is a good solution though, depends on what you really are looking for.
EDIT:
As per mu's suggestion you could also take a look at the time data type.

To get the minutes from a Time object, you want min not minutes. You can't have a Time instance that's just a "time of day" (i.e. no year, month, ...) but you can use strftime to get a string version that will compare properly:
tod = Time.now.strftime('%H:%M:%S')
# "17:07:23"
if(t1.strftime('%H:%M:%S') == t2.strftime('%H:%M:%S'))
# Same time of day (to one second resolution)
end
Or you could compare the individual hour, min, and sec components:
if(t1.hour == t2.hour && t1.min == t2.min && t1.sec == t2.sec)
# Same time of day (to one second resolution)
end
Which approach you take depends, as usual, on your specific situation and what else is going in in that vicinity.

Related

Can't set timezone using abbreviation

I can't set timezone on Rails using its abbreviation, for example:
>> Time.zone = 'BRT'
ArgumentError: Invalid Timezone: BRT
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-3.2.21/lib/active_support/core_ext/time/zones.rb:61:in `rescue in find_zone!'
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-3.2.21/lib/active_support/core_ext/time/zones.rb:53:in `find_zone!'
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-3.2.21/lib/active_support/core_ext/time/zones.rb:37:in `zone='
from (irb):14
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-3.2.21/lib/rails/commands/console.rb:47:in `start'
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-3.2.21/lib/rails/commands/console.rb:8:in `start'
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-3.2.21/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
This is necessary as some systems (android and some browsers) report timezone using the abbreviation.
The list of abbreviations can be found at http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations
jstimezone was reporting timezone using abbreviations. It is also quite buggy and unmaintained (https://bitbucket.org/pellepim/jstimezonedetect/issues?status=new&status=open). It is simpler to just use standard javascript:
var offset = - new Date().getTimezoneOffset()/60
Then call on document ready:
$.cookie("browser.tzoffset", offset, { expires: 30, path: '/' })
Then in rails use around_filter in ApplicationController:
def set_time_zone
return yield unless (utc_offset = cookies['browser.tzoffset']).present?
utc_offset = utc_offset.to_i
gmt_offset = if utc_offset == 0 then nil elsif utc_offset > 0 then -utc_offset else "+#{-utc_offset}" end
Time.use_zone("Etc/GMT#{gmt_offset}"){ yield }
rescue ArgumentError
yield
end
This localizes all dates for users, independently where he/she is. In Brazil we have multiple timezones, for example.
PS: ActiveSupport::TimeZone[utc_offset.to_i] can't be used as it uses DST, see https://github.com/rails/rails/issues/20504
PS: You can also use moment: moment.parseZone(Date.now()).utcOffset()/60 or moment().format('zz')
You don't have to use around_filter.
Put this in before_action
Time.zone = "Etc/GMT#{gmt_offset}"
(Time.zone is thread local. It's safe to change.)

Calculate total time in minutes between two timings in two diff. time zones (UTC and IST) - Rails 3.2.13

I have two datetimes formats to calculate the difference.
2013-08-29 22:48:00 UTC
2013-08-30 00:18:40 +0530
How can I get the first subtracted from the second one? What is actually the difference between them other than in time?
Below are the things I run in my console:
Loading development environment (Rails 3.2.13)
2.0.0-p247 :001 > #a = Time.parse('2013-08-29 22:48:00 UTC')
=> 2013-08-29 22:48:00 UTC
2.0.0-p247 :002 > #b = Time.parse('2013-08-29 22:48:00 +0530')
=> 2013-08-29 22:48:00 +0530
2.0.0-p247 :003 > #a > #b
=> true
2.0.0-p247 :004 > #a == #b
=> false
2.0.0-p247 :005 > #a < #b
=> false
2.0.0-p247 :006 >
Both are not the same, so the answer from cmwright is found to be incorrect. Please have a look and it would be great if you could tell me how can we convert UTC format to +5.30 format in Rails 3.2?
seconds_difference = Time.parse('2013-08-29 22:48:00 UTC') - Time.parse('2013-08-30 00:18:40 +0530')
Will give you the seconds difference, then you can get you need from there by doing
seconds_difference / 1.day or seconds_difference / 1.hour
What is actually the difference between them other than in time?
Well, one date is at UTC (+00:00) and the other is at UTC+05:30.
2013-08-29 22:48:00 UTC => 2013-08-30 04:18:00 +0530
- 2013-08-29 18:48:40 UTC <= - 2013-08-30 00:18:40 +0530
------------------------- ---------------------------
3:59:20 3:59:20
Whichever direction you convert, they are 3 hours, 59 minutes, and 20 seconds apart.
CMWright's answer shows how you can subtract them in code. The integers you get from the Time.parse function are both based on UTC.

Rails Time class has a TimeZone Bug. Can this be confirmed?

Here goes :
Time.zone.now => "Eastern Time (US & Canada)"
Time.zone.now => Wed, 15 Aug 2012 06:05:37 EDT -04:00
Time.zone.now + 39.years => Tue, 15 Aug 2051 06:06:03 EST -05:00
And so you have it, the end of our fabled Eastern Daylight Time has been prophesied by Ruby on Rails to end in the year 2051.
Also works for any other TimeZone changing area.
Time.zone
=> "Pacific Time (US & Canada)"
1.9.2p180 :003 > Time.zone.now
=> Wed, 15 Aug 2012 03:08:57 PDT -07:00
1.9.2p180 :004 > Time.zone.now + 39.years
=> Tue, 15 Aug 2051 03:08:57 PST -08:00
This exists in Rails 3.0 and in Rails 3.2.6
Yes, it looks like a bug. It's not Rails, however, it's the Ruby Time class. It has problems with times after 2038.
For example, with Ruby 1.8.7:
> Time.local(2037,8,16,9,30,15)
=> Sun Aug 16 09:30:15 -0400 2037
>
> Time.local(2038,8,16,9,30,15)
=> Mon Aug 16 09:30:15 -0500 2038
JRuby 1.6.7.2 - for instance - does not have this problem:
> Time.local(2038,8,16,9,30,15)
=> Mon Aug 16 09:30:15 -0400 2038
Note that, on MRI Ruby on 64-bit systems, the ActiveSupport time extension which supports the addition of durations ultimately calls Time.local or Time.utc via this method in active_support/core_ext/time/calculations.rb:
# Returns a new Time if requested year can be accommodated by Ruby's Time class
# (i.e., if year is within either 1970..2038 or 1902..2038, depending on system architecture);
# otherwise returns a DateTime
def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
rescue
offset = utc_or_local.to_sym == :local ? ::DateTime.local_offset : 0
::DateTime.civil(year, month, day, hour, min, sec, offset)
end
I guess the issue is that for years >= 2038, they were expecting an overflow exception and for DateTime to be used instead. On 64-bit systems, this doesn't happen.
UPDATE: This analysis is incorrect for Ruby 1.9.2+. Time.local works as expected, but the original problem still occurs.

Rails time formatting test failing because it's one hour off?

I have the following method in one of my Rails classes:
def human_departure_time
"#{departure_time.strftime("%A, %d %B %Y")} at #{departure_time.strftime("%I:%M %p")}"
end
As you can see, it just takes a datetime attribute of the model and formats it so that it is more human friendly.
Anyway, I have the following test for this method:
describe "human_departure_time" do
it "should output the time in readable format" do
# first I use the Timecop gem to freeze the time
Timecop.freeze(DateTime.now) do
bus_time = DateTime.now + 1.days
# factory a bus with a specific departure time
bus = Factory :bus, departure_time: bus_time
expected = "#{bus_time.strftime("%A, %d %B %Y")} at #{bus_time.strftime("%I:%M %p")}"
# check that the output is as expected
bus.human_departure_time.should == expected
end
end
end
Pretty simple but the test fails by one hour with the following output:
Failures:
1) Bus human_departure_time should output the time in readable format
Failure/Error: bus.human_departure_time.should == expected
expected: "Wednesday, 17 August 2011 at 03:13 AM"
got: "Wednesday, 17 August 2011 at 02:13 AM" (using ==)
# ./spec/models/bus_spec.rb:34:in `block (4 levels) in <top (required)>'
# ./spec/models/bus_spec.rb:30:in `block (3 levels) in <top (required)>'
Here is my bus factory just incase that is important. I'm overwriting the departure time with the frozen time plus one hour in my test.
factory :bus do
origin_name "Drogheda"
event_name "EP"
departure_time { DateTime.now + 14.days }
end
I assume this is something to do with daylight savings time or something? How can I fix this issue?
ActiveRecord could be automatically converting time attributes in your model to local time.
You can try and use the %Z parameter of strftime to see the time zone of the outputted timestamp to see where a possible conversion is sneaking into your time.
Some Googled hints that might be relevant:
default_timezone:
http://apidock.com/rails/ActiveRecord/Base/default_timezone/class
ActiveRecord::Base.time_zone_aware_attributes
config.active_record.time_zone_aware_attributes:
http://tamersalama.com/2011/01/10/rails-disable-timezone-conversions/
https://mirrors.kilnhg.com/Repo/Mirrors/From-Git/Rails/History/70cb470c1ab8
http://www.ruby-forum.com/topic/2096919
http://www.ruby-forum.com/topic/890711

Ruby, Rails and difference between two dates

I will let the example speak for it self:
ruby-1.9.2-p0 > DateTime.now
=> Mon, 14 Feb 2011 20:02:49 +0100
ruby-1.9.2-p0 > User.first.created_at
=> Tue, 04 May 2010 07:03:24 CEST +02:00
ruby-1.9.2-p0 > DateTime.now-User.first.created_at
TypeError: expected numeric or date
from /Users/Jacob/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/date.rb:1356:in `-'
from /Users/Jacob/.rvm/gems/ruby-1.9.2-p0#loyaltric_template/gems/activesupport-3.0.3/lib/active_support/core_ext/date/calculations.rb:98:in `minus_with_duration'
from (irb):47
from /Users/Jacob/.rvm/gems/ruby-1.9.2-p0#loyaltric_template/gems/railties-3.0.3/lib/rails/commands/console.rb:44:in `start'
from /Users/Jacob/.rvm/gems/ruby-1.9.2-p0#loyaltric_template/gems/railties-3.0.3/lib/rails/commands/console.rb:8:in `start'
from /Users/Jacob/.rvm/gems/ruby-1.9.2-p0#loyaltric_template/gems/railties-3.0.3/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
ruby-1.9.2-p0 >
What?!?
.created_at returns an ActiveSupport::TimeWithZone object. Try
DateTime.now - User.first.created_at.to_datetime
You can instead use
Time.now - User.first.created_at
This will report the number of seconds between now and your first user creation time.

Resources