What's wrong with Rails's Date - ruby-on-rails

I ran into this non-sense problem this morning in Rails 3.2 console. I'm under MacOS 10.10, my timezone is +7.
Loading development environment (Rails 3.2.12)
irb(main):001:0> Date.today
=> Sun, 16 Nov 2014
irb(main):002:0> Date.yesterday
=> Fri, 14 Nov 2014
irb(main):003:0>
Everything is fine with original Ruby Date:
irb(main):006:0> Date.today
=> #<Date: 2014-11-16 ((2456978j,0s,0n),+0s,2299161j)>
irb(main):007:0> Date.today.prev_day
=> #<Date: 2014-11-15 ((2456977j,0s,0n),+0s,2299161j)>
irb(main):008:0>

From the bug report here: https://rails.lighthouseapp.com/projects/8994/tickets/6410#ticket-6410-8
This is a subtle one - Date.yesterday uses Date.current which will use the time zone whereas Date.today doesn't. If you set your time zone to one where it's tomorrow already (e.g. Europe/Berlin as I type this) then you can get Date.today == Date.yesterday:
Time.zone = "Europe/London"
=> "Europe/London"
Date.today == Date.yesterday
=> false
Time.zone = "Europe/Berlin"
=> "Europe/Berlin"
Date.today == Date.yesterday
=> true

Related

Ruby and Rails "Date.today" format

In IRB, if I run following commands:
require 'date'
Date.today
I get the following output:
=> #<Date: 2015-09-26 ((2457292j,0s,0n),+0s,2299161j)>
But in Rails console, if I run Date.today, I get this:
=> Sat, 26 Sep 2015
I looked at Rails' Date class but can't find how Rails' Date.today displays the output differently than Ruby's output.
Can anybody tell, in Rails how Date.today or Date.tomorrow formats the date to display nicely?
The answer to your question is ActiveSupport's core extension to Date class. It overrides the default implementations of inspect and to_s:
# Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
def readable_inspect
strftime('%a, %d %b %Y')
end
alias_method :default_inspect, :inspect
alias_method :inspect, :readable_inspect
Command line example:
ruby-2.2.0 › irb
>> require 'date'
=> true
>> Date.today
=> #<Date: 2015-09-27 ((2457293j,0s,0n),+0s,2299161j)>
>> require 'active_support/core_ext/date'
=> true
>> Date.today
=> Sun, 27 Sep 2015
Rails' strftime or to_s methods should do what you need.
For example, using to_s:
2.2.1 :004 > Date.today.to_s(:long)
=> "September 26, 2015"
2.2.1 :005 > Date.today.to_s(:short)
=> "26 Sep"
If you run this:
require 'date'
p Date.today.strftime("%a, %e %b %Y")
You'll get this: "Sat, 26 Sep 2015"

Check if DateTime value is today, tomorrow or later

I have an object attribute of the DateTime class.
How would I understand if the saved date is today, tomorrow or else later?
Here are some useful ways to achieve it:
datetime = DateTime.now => Sun, 26 Oct 2014 21:00:00
datetime.today? # => true
datetime.to_date.past? # => false (only based on date)
datetime.to_date.future? # => false (only based on date)
datetime.to_date == Date.tomorrow # => false
datetime.to_date == Date.yesterday # => false
Something like...
datetime = Time.now.to_datetime
=> Sun, 26 Oct 2014 16:24:55 -0600
datetime >= Date.today
=> true
datetime < Date.tomorrow
=> true
datetime += 1.day
=> Mon, 27 Oct 2014 16:25:12 -0600
datetime >= Date.today
=> true
datetime >= Date.tomorrow
=> true
datetime < (Date.tomorrow + 1.day)
=> false
?
yesterday? & tomorrow? (Rails 6.1+)
Rails 6.1 adds new #yesterday? and #tomorrow? methods to Date and Time classes.
As a result, now, your problem can be solved as:
datetime = DateTime.current
# => Mon, 16 Nov 2020 20:50:16 +0000
datetime.today?
# => true
datetime.yesterday?
# => false
datetime.tomorrow?
# => false
It is also worth to mention that #yesterday? and #tomorrow? are aliased to #prev_day? and #next_day?.
Here is a link to the corresponding PR.

How to get the time zone abbreviation from Time.now?

Time.now.strftime('%Z') returns 'Mountain Daylight Time' for me. I'd like to get MDT.
What's the correct way to get the time zone abbreviation?
Just in case anyone suspected I was misleading them:
irb(main):001:0> Time.now.strftime('%Z')
=> "Mountain Daylight Time"
irb(main):002:0> Time.now.zone
=> "Mountain Daylight Time"
irb(main):003:0> Time.now.in_time_zone('Mountain Time (US & Canada)').zone
=> "MDT"
Ran a few things, I'd say try using Time.now.zone
#This is working for me, but not for you. I'm not sure why (although others might!)
$ > Time.now.strftime('%Z')
=> "CEST"
#This gives UTC time which is useful, but not what you're after
$ > Time.zone
=> #<ActiveSupport::TimeZone:0x00000103049918 #name="UTC", #utc_offset=nil, #tzinfo=#<TZInfo::TimezoneProxy: Etc/UTC>, #current_period=nil>
$ > Time.zone.now
=> Sat, 05 Oct 2013 09:11:01 UTC +00:00
$ > Time.zone.now.zone
=> "UTC"
#This will (perhaps) return what you want.
#It's possible that you'll still just get "Mountain Daylight Time"
$ > Time.now
=> 2013-10-05 11:12:09 +0200
$ > Time.now.zone
=> "CEST"

Rails timezone activerecord

My application.rb:
config.time_zone = 'Moscow'
config.time_zone = "(GMT+04:00) Moscow"
config.active_record.default_timezone = 'Moscow'
config.active_record.default_timezone = :local
When i run this commands, i get:
1.9.3-p362 :001 > Time.now
=> 2013-02-14 14:18:42 +0400
1.9.3-p362 :002 > Time.zone.now
=> Thu, 14 Feb 2013 10:18:52 UTC +00:00
So in db i see 10:18:52 UTC +00:00.
But what and how to configure, to see such time, as in Time.Now? (when i insert new row to db i must see time, as given by Time.now, what to configure?)
Server's time is Moscow....
also db is mysql
You can use local time like this:
> current_time = Time.now.utc
=> 2013-02-14 15:15:58 UTC
> current_time .localtime
=> 2013-02-14 10:15:58 -05 hours
You can use also:
Time.now.utc.in_time_zone("Moscow")
But for the answer to your question, the solution could be to set it like this:
config.time_zone = 'Moscow' (don't set this - delete this line)
config.active_record.default_timezone = :local
And also you can use your local time something like this:
Time.local_time
I hope some of this approaches might help you
In your application.rb include these lines:
config.time_zone = 'Moscow'
config.active_record.default_timezone = 'Moscow'
Now that you have set the time zone:
Time.now
=> 2013-02-14 11:14:46 +0000
Time.current
=> Thu, 14 Feb 2013 15:14:48 MSK +04:00
user = User.create(name: 'test')
=> #<User id: 6, name: "test", created_at: "2013-02-14 11:15:00", updated_at: "2013-02-14 11:15:00">
user.created_at
=> Thu, 14 Feb 2013 15:15:00 MSK +04:00
As you can see, despite the fact that rails stores the time as UCT +0000 (very clever btw), the rails interface is providing the required offset. If you call any object, such as user.created_at it will offset the database time to return the zone time.
It is very useful, because it allows the configuration of different time zones for different users. The time will be stored without offset, but each user will get its equivalent time zone.
Time.now return +00:00, doesn't matter your time zone.
Time.current is the same as Time.zone.now.

how to change server time to client time on rails?

So my end goal is to have Heroku server's Time.now to be same as the time that you do new Date.now() from JavaScript. What I have done so far is catching the timezone offset from JavaScript, and set Time.zone on Rails with the appropriate client timezone, so now, Time.zone is the right time zone. But however, Time.now is still reflecting the real timezone instead of the one feeding into Time.zone. I guess that's not what I suppose to do at the first place.
So once again, all I want is, the server time to reflect the client time, so any operations such as Time.now or DateTime.now or Date.today will be shown with the client time.
You should apply the UTC offset when displaying the times.
All server-side time calculation or storage should be done in UTC.
Check this
1.8.7 :001 > Time.zone
=> #<ActiveSupport::TimeZone:0xb740d1b8 #tzinfo=#<TZInfo::TimezoneProxy: Etc/UTC>, #utc_offset=nil, #name="UTC", #current_period=nil>
1.8.7 :002 > Time.now
=> Fri Apr 20 13:13:53 +0530 2012
1.8.7 :003 > Time.zone.now
=> Fri, 20 Apr 2012 07:43:59 UTC +00:00
1.8.7 :004 > Time.zone = "Helsinki"
=> "Helsinki"
1.8.7 :005 > Time.zone
=> #<ActiveSupport::TimeZone:0xb70ab830 #tzinfo=#<TZInfo::TimezoneProxy: Europe/Helsinki>, #utc_offset=nil, #name="Helsinki", #current_period=nil>
1.8.7 :006 > Time.now
=> Fri Apr 20 13:14:48 +0530 2012
1.8.7 :007 > Time.zone.now
=> Fri, 20 Apr 2012 10:45:10 EEST +03:00
1.8.7 :008 > Time.zone.now.to_time.strftime("%c").to_datetime
=> Fri, 20 Apr 2012 10:47:01 +0000
1.8.7 :009 >
So Time.zone.now.to_time.strftime("%c").to_datetime will give you current time in user's timezone as UTC
Time.now always gives time in your server's timezone. Time.zone.now gives time in specified timezone.
Thanks,
Amit Patel

Resources