How can I customize Rails' date parsing from params? - ruby-on-rails

I want to format dates in jQuery using the UI datepicker like this:
Sunday - 11/28/2010
How/where can I plug in a custom parser for Rails to make it so this works:
def create
puts params[:event] #=> {"my_date"=>"Sunday - 11/28/2010"}
event = Event.new(params[:event])
puts event.my_date #=> nil
end
This works:
def create
puts params[:event] #=> {"my_date"=>"11/28/2010"}
event = Event.new(params[:event])
puts event.my_date #=> Mon, 22 Nov 2010
end
What's the Rails way to do this?

You could use Chronic, a natural language date/time parser
Time.now #=> Sun Aug 27 23:18:25 PDT 2006
Chronic.parse('tomorrow')
#=> Mon Aug 28 12:00:00 PDT 2006
Chronic.parse('monday', :context => :past)
#=> Mon Aug 21 12:00:00 PDT 2006
Chronic.parse('this tuesday 5:00')
#=> Tue Aug 29 17:00:00 PDT 2006
Chronic.parse('may 27th', :guess => false)
#=> Sun May 27 00:00:00 PDT 2007..Mon May 28 00:00:00 PDT 2007
http://chronic.rubyforge.org/

params[:event][:my_date] = Date.parse(params[:event][:my_date])
event = Event.new(params[:event])

Exactly what you want:
http://www.mobalean.com/blog/2010/11/19/seamless-rails-integration-with-jquery-tools-dateinput

Related

strftime(%Z) returns wrong result

I have this date
date = Mon, 15 Aug 2016 13:00:00 UTC +00:00
which is ActiveSupport::TimeWithZone class
Then, I need to get the time in time zone "Fiji"
start_in_time_zone = date.in_time_zone("Fiji")
This returns Tue, 16 Aug 2016 01:00:00 +12 +12:00
Then, I need to present the date with the name of the time zone, so
time_zone_abbr = start_in_time_zone.strftime("%Z")
It should return "FJT"
but returns "+12"
Any idea why?
I am using ruby 2.3.7 and rails 4.2.7
UPDATE
If I do
start_in_time_zone = date.in_time_zone("Madrid")
it returns
"CEST"
UPDATE 2
I have tried to see where the problem is by setting different time.
date=Time.utc(2018, 07, 25, 20, 30, 45)
date.class #=> Time
date.in_time_zone("Madrid") #=> Wed, 25 Jul 2018 22:30:45 CEST +02:00
date.in_time_zone("Fiji") #=> Thu, 26 Jul 2018 08:30:45 +12 +12:00
date.in_time_zone("EST") #=> Wed, 25 Jul 2018 15:30:45 EST -05:00
Sadly, it seems there is no 'FJT' abbreviation assigned to 'Fiji' in timezone data used by Rails. Also, support for those abbreviations seems patchy regarding Pacific timezones.
irb(main):002:0> DateTime.now.in_time_zone('Samoa').strftime('%Z')
=> "+13"
irb(main):003:0> DateTime.now.in_time_zone('Midway Island').strftime('%Z')
=> "SST"
irb(main):004:0> DateTime.now.in_time_zone('Samoa').strftime('%Z')
=> "+13"
irb(main):005:0> DateTime.now.in_time_zone('Tokelau Is.').strftime('%Z')
=> "+13"
irb(main):006:0> DateTime.now.in_time_zone('Wellington').strftime('%Z')
=> "NZST"
UTC offset is displayed as fallback. If it's any help, remember that full name and additional information can be retrieved with .time_zone.tzinfo on ActiveSupport::TimeWithZone objects. 'FJ' code is recognized by TZInfo::Country.
irb(main):056:0> TZInfo::Country.get('FJ')
=> #<TZInfo::Country: FJ>
irb(main):057:0> TZInfo::Country.get('FJ').zone_info
=> [#<TZInfo::CountryTimezone: Pacific/Fiji>]

Rails - Is there an easy way to check if British Summer Time and GMT are different?

I've been reading Rails BST timezone implementation however the method listed doesn't seem to work any more:
Time.zone = 'London'
Time.now = 2017-04-10 15:47:45 +0100
Time.zone = 'Cairo'
Time.now = 2017-04-10 15:47:45 +0100
This is clearly wrong. Is there an easy way for me to check? My end result is trying to see if the London timezone has +0100 in it or not, could I simply do Time.now.include?('+0100')
Thanks in advance
the method listed doesn't seem to work any more
You're using the wrong method:
Time.now is a Ruby method returning a "plain" Time instance.
Time.zone.now is a Rails method returning a ActiveSupport::TimeWithZone instance.
There's also a shortcut Time.current:
Time.zone = 'London'
Time.zone.now
#=> Mon, 10 Apr 2017 15:54:35 BST +01:00
Time.current
#=> Mon, 10 Apr 2017 15:54:35 BST +01:00
With another time zone:
Time.zone = 'Cairo'
Time.zone.now
#=> Mon, 10 Apr 2017 16:54:35 EET +02:00
My end result is trying to see if the London timezone has +0100 in it or not
In that case "+0100" indicates daylight saving time. The proper method is dst?:
t1 = Time.zone.parse('2017-03-26') #=> Sun, 26 Mar 2017 00:00:00 GMT +00:00
t2 = Time.zone.parse('2017-03-27') #=> Mon, 27 Mar 2017 00:00:00 BST +01:00
t1.dst? #=> false
t2.dst? #=> true

1.year.from_now is also one day ahead

Today's date is 2016-09-19. I add one year to it, and I expect the result to be 2017-09-19. Instead, I get 2017-09-20. One year plus one day ahead. Is this behavior as intended?
$ rails c
2.3.1 :001 > Time.now.to_date.iso8601
=> "2016-09-19"
2.3.1 :002 > 1.year.from_now.to_date.iso8601
=> "2017-09-20"
If you want get ecactly date with time zones, you can use Time.current
1.year.from_now
#=> Wed, 20 Sep 2017 05:38:50 UTC +00:00
Time.current
#=> Tue, 20 Sep 2016 05:39:08 UTC +00:00
since or its alias from_now calculate the offset based on Time.current which is equivalent to Time.zone.now – both return a ActiveSupport::TimeWithZone instance:
Time.current #=> Mon, 19 Sep 2016 19:56:34 SST -11:00
Time.zone.now #=> Mon, 19 Sep 2016 19:56:35 SST -11:00
Time.now on the other hand returns an ordinary Time instance in your system's timezone, which can differ from the Rails timezone:
Time.now #=> 2016-09-20 08:56:36 +0200
To avoid confusion, you should always use Time.current / Time.zone.now when working within Rails. You can however pass another "base time" to since:
1.year.since(Time.now) #=> 2017-09-20 08:56:37 +0200
Or, because you are working with dates:
1.year.since(Date.today) #=> Wed, 20 Sep 2017
There is also Date.current which is equivalent to Time.zone.today:
1.year.since(Date.current) #=> Wed, 19 Sep 2017
Turns out it's a timezone thing. I'm UTC -7 hours.
Time.now returns the time in my timezone.
1.year.from_now returns the time in UTC+0, 7 hours ahead of where I am.
It's 10pm here, so it's the next day at UTC+0.

How to get start day and end day of a particular month and year in ruby?

Iam having the month value like (1 to 12) and year value like 2011 to 2012 by passing these parameters i want to get the starting day and ending day of the paticular month and year. how can i do this in ruby?
In addition to jfornoff's excellent answer, Rails' Active Support gem comes with a rich set of date and time methods:
require 'active_support/core_ext/date' #to cherry pick just date helpers
d = Date.new(2011, 4) #=> Fri, 01 Apr 2011
d.beginning_of_month #=> Fri, 01 Apr 2011
d.end_of_month #=> Sat, 30 Apr 2011
d.all_month #=> Fri, 01 Apr 2011..Sat, 30 Apr 2011
Date.civil sounds like what you need
start_date = Date.civil(2011, 1, 1) #=> Sat, 01 Jan 2011
end_date = Date.civil(2011, 12, -1) #=> Sat, 31 Dec 2011
Docs: here
require 'date'
start_date = Date.new(2016, 2)
#=> #<Date: 2016-02-01 ((2457420j,0s,0n),+0s,2299161j)>
end_date = (start_date >> 1) - 1
#=> #<Date: 2016-02-29 ((2457448j,0s,0n),+0s,2299161j)>

"Fuzzy" date with optional day/month

I would like to store date for some data in Rails app. User can select a date, sometimes it would be specific (like "1 Jan 2010") but sometimes he knows only month & year ("Jan 2010") or even just the year (2010). Is there a standard method to store (and provide input) for that in Rails? I know I could just create 3 separate columns in model, but perhaps there is a nice gem for it.
I created a gem to do exactly this:
http://rubygems.org/gems/date_time_precision
For example:
require 'date_time_precision/format/string'
Date.new(2010, 1).to_s(:long)
# => "January 2010"
Have you ever heard of the Chronic gem?
These are some usage examples from the Github documentation.
require 'chronic'
Time.now #=> Sun Aug 27 23:18:25 PDT 2006
Chronic.parse('tomorrow')
#=> Mon Aug 28 12:00:00 PDT 2006
Chronic.parse('monday', :context => :past)
#=> Mon Aug 21 12:00:00 PDT 2006
Chronic.parse('this tuesday 5:00')
#=> Tue Aug 29 17:00:00 PDT 2006
Chronic.parse('this tuesday 5:00', :ambiguous_time_range => :none)
#=> Tue Aug 29 05:00:00 PDT 2006
Chronic.parse('may 27th', :now => Time.local(2000, 1, 1))
#=> Sat May 27 12:00:00 PDT 2000
Chronic.parse('may 27th', :guess => false)
#=> Sun May 27 00:00:00 PDT 2007..Mon May 28 00:00:00 PDT 2007
Chronic.parse('6/4/2012', :endian_precedence => :little)
#=> Fri Apr 06 00:00:00 PDT 2012
Chronic.parse('INVALID DATE')
#=> nil

Resources