How to use to_date in rails? - ruby

Ruby 2.0
controller action
#date = "2013-12-21"
#new_date = #date.to_date
p #new_date
o/p: Sat, 21 Dec 2013
at view
<%= #new_date %>
o/p: 2013-12-21
i want on view "Sat, 21 Dec 2013"

Rails is so intelligent that it automatically calls all objects in a view that are not already a string via the method .to_s, which always converts the content of the object to a string.
Lets first dig me into the root cause, why such unexpected output :
kirti#kirti-Aspire-5733Z:~/workspace/testproject$ rvm use 1.9.3
Using /home/kirti/.rvm/gems/ruby-1.9.3-p484
kirti#kirti-Aspire-5733Z:~/workspace/testproject$ rails c
Loading development environment (Rails 3.2.16)
1.9.3p484 :001 > d = "2013-12-21".to_date
=> Sat, 21 Dec 2013
1.9.3p484 :002 > d.to_s
=> "2013-12-21"
1.9.3p484 :003 > d
=> Sat, 21 Dec 2013
1.9.3p484 :004 > d.class
=> Date
1.9.3p484 :005 > d.strftime('%a, %e %b %Y')
=> "Sat, 21 Dec 2013"
1.9.3p484 :006 >
"2013-12-21".to_date giving you a Date instance, not a String instance.d.class proved that. d is a Date instance, on which in view again to_s method is called as I told in the begining, so Sat, 21 Dec 2013 is again set back into the "2013-12-21". So your solution will be :
#date = "2013-12-21".to_date.strftime('%a, %e %b %Y')
"2013-12-21".to_date.strftime('%a, %e %b %Y') will give you the desired result as an String instance.So on string instance(receiver) if you apply to_s,you will get the same receiver back. Now you can use this #date variable in your view.

in Ruby 2.0 in a controller's action:
#date = "2013-12-21"
#new_date = #date.to_date
# => Sat, 21 Dec 2013
And use the #new_date on your view.

#new_date.strftime('%a, %e %b %Y')
Use it directly on the view.

From what I understand, you are getting
2013-12-21
but want
Sat, 21 Dec 2013
The reason it is outputted in the console nicely is because the console will auto format it for you. This can be verified by printing #new_date.to_s in the console, it'll be the unformatted version. To print it out on a screen in the way you want, you have to format it yourself.
You should use strftime like this:
#new_date = #new_date.strftime('%a, %e %b %Y')
or
#date.to_date.strftime('%a, %e %b %Y')
This will output Sat, 21 Dec 2013 correctly.

The best way to format a date object in Rails is by using the available I18n formatters.
<%= l # new_date, format: :long %>
As described in the guide, you can also create additional formats. For example, if none of the defaults matches your desired format, simply define
# config/locales/en.yml
en:
time:
formats:
custom: "%a, %e %b %Y"
then use
<%= l # new_date, format: :custom %>

Related

How to avoid from storing date objects in array in Ruby?

Consider below code:
dates = ["20th OCT 1232", "6th JUN 2019", "23th AUG 2017", "9th JAN 2015"]
def reformateDate(dates)
ans = []
dates.length.times do |i|
ans << (DateTime.parse(dates[i], '%d %b %Y').to_date)
end
ans
end
This function return array in below format:
[#<Date: 1232-10-20 ((2171339j,0s,0n),+0s,2299161j)>, #<Date: 2019-06-06 ((2458641j,0s,0n),+0s,2299161j)>, #<Date: 2017-08-23 ((2457989j,0s,0n),+0s,2299161j)>, #<Date: 2015-01-09 ((2457032j,0s,0n),+0s,2299161j)>]
But i want it to return array in this format:
["1232-10-20","2019-06-06","2017-08-23","2015-01-09"]
So how can i do this?
dates.map { |e| Date.parse(e).strftime('%Y-%m-%d') }
#=> ["1232-10-20", "2019-06-06", "2017-08-23", "2015-01-09"]
Change the template '%Y-%m-%d' according to your needs, see this for reference: Date#strftime.
Picking up the wise suggestion from Cary Swoveland.
Instead of Date.parse(e) you can use Date.strptime(e, '%dth %b %Y'), which works more or less the reverse of strftime. See Date#strptime. It follows a template ('%dth %b %Y') to interpret the original string as a date. Adding th to the template after %d (day), it converts properly the current format to a date object:
Date.strptime("20th OCT 1232", '%dth %b %Y') #=> #<Date: 1232-10-20 ((2171339j,0s,0n),+0s,2299161j)>
But, what if the date is '1st OCT 2018' or '23rd OCT 2018'? The template does not match, because it expects to find th and not st or rd.
To be ordinal suffix agnostic, comes in hand the method String#sub:
"20th OCT 1232".sub(/(?<=\d)\p{Alpha}+/, '') #=> "20 OCT 1232"
So, mixing all together, the best solution to be safe should be:
dates.map { |e| Date.strptime(e.sub(/(?<=\d)\p{Alpha}+/, ''), '%d %b %Y').strftime('%Y-%m-%d') }
Well, you're actually storing Date objects when you write:
ans << (DateTime.parse(dates[i], '%d %b %Y').to_date)
There's a couple of problems with this: First, the parenthesis don't do anything, so you can remove them. Second, what you're doing is parsing a string into a DateTime object, and then converting it into a Date object. Not really sure why you would do that, but I believe it's a mistake. If you want to convert this to a string by temporally using DateTime objects, consider using strftime, which will take the DateTime object and turn it into a string with a specific format. It would look like this:
ans << DateTime.parse(dates[i], '%d %b %Y').strftime('%Y-%m-%d')
I would do something like this:
require 'date'
def reformat_date(dates)
dates.map { |date| Date.parse(date).to_s }
end
dates = ["20th OCT 1232", "6th JUN 2019", "23th AUG 2017", "9th JAN 2015"]
reformat_date(dates)
#=> ["1232-10-20", "2019-06-06", "2017-08-23", "2015-01-09"]

`DateTime.strptime` returns invalid date for weekday/time string

Why won't Ruby's strptime convert this to a DateTime object:
DateTime.strptime('Monday 10:20:20', '%A %H:%M:%S')
# => ArgumentError: invalid date
While these work?
DateTime.strptime('Wednesday', '%A')
# => #<DateTime: 2015-11-18T00:00:00+00:00 ((2457345j,0s,0n),+0s,2299161j)>
DateTime.strptime('10:20:20', '%H:%M:%S')
# => #<DateTime: 2015-11-18T10:20:20+00:00 ((2457345j,37220s,0n),+0s,2299161j)>
This looks like a bug - minitech's comment is spot on. For now, though, a workaround (because you probably want this to work now):
You can split it on the space, get the date from the weekday, then get the time component from the other string (using the _strptime method minitech mentioned). Then you can set the time on the first date to the time component from the second string:
def datetime_from_weekday_time_string(string)
components = string.split(" ")
date = DateTime.strptime(components[0], '%A')
time = Date._strptime(components[1], '%H:%M:%S') # returns a hash like {:hour=>10, :min=>20, :sec=>20}
return date.change(time)
end
2.2.2 :021 > datetime_from_weekday_time_string("Monday 10:20:20")
=> Mon, 16 Nov 2015 10:20:20 +0000
2.2.2 :022 > datetime_from_weekday_time_string("Saturday 11:45:21")
=> Sat, 21 Nov 2015 11:45:21 +0000
2.2.2 :023 > datetime_from_weekday_time_string("Thursday 23:59:59")
=> Thu, 19 Nov 2015 23:59:59 +0000

Adding "st,nd,rd,th" to a date in Ruby [duplicate]

I want to display dates in the format: short day of week, short month, day of month without leading zero but including "th", "st", "nd", or "rd" suffix.
For example, the day this question was asked would display "Thu Oct 2nd".
I'm using Ruby 1.8.7, and Time.strftime just doesn't seem to do this. I'd prefer a standard library if one exists.
Use the ordinalize method from 'active_support'.
>> time = Time.new
=> Fri Oct 03 01:24:48 +0100 2008
>> time.strftime("%a %b #{time.day.ordinalize}")
=> "Fri Oct 3rd"
Note, if you are using IRB with Ruby 2.0, you must first run:
require 'active_support/core_ext/integer/inflections'
You can use active_support's ordinalize helper method on numbers.
>> 3.ordinalize
=> "3rd"
>> 2.ordinalize
=> "2nd"
>> 1.ordinalize
=> "1st"
Taking Patrick McKenzie's answer just a bit further, you could create a new file in your config/initializers directory called date_format.rb (or whatever you want) and put this in it:
Time::DATE_FORMATS.merge!(
my_date: lambda { |time| time.strftime("%a, %b #{time.day.ordinalize}") }
)
Then in your view code you can format any date simply by assigning it your new date format:
My Date: <%= h some_date.to_s(:my_date) %>
It's simple, it works, and is easy to build on. Just add more format lines in the date_format.rb file for each of your different date formats. Here is a more fleshed out example.
Time::DATE_FORMATS.merge!(
datetime_military: '%Y-%m-%d %H:%M',
datetime: '%Y-%m-%d %I:%M%P',
time: '%I:%M%P',
time_military: '%H:%M%P',
datetime_short: '%m/%d %I:%M',
due_date: lambda { |time| time.strftime("%a, %b #{time.day.ordinalize}") }
)
>> require 'activesupport'
=> []
>> t = Time.now
=> Thu Oct 02 17:28:37 -0700 2008
>> formatted = "#{t.strftime("%a %b")} #{t.day.ordinalize}"
=> "Thu Oct 2nd"
Although Jonathan Tran did say he was looking for the abbreviated day of the week first followed by the abbreviated month, I think it might be useful for people who end up here to know that Rails has out-of-the-box support for the more commonly usable long month, ordinalized day integer, followed by the year, as in June 1st, 2018.
It can be easily achieved with:
Time.current.to_date.to_s(:long_ordinal)
=> "January 26th, 2019"
Or:
Date.current.to_s(:long_ordinal)
=> "January 26th, 2019"
You can stick to a time instance if you wish as well:
Time.current.to_s(:long_ordinal)
=> "January 26th, 2019 04:21"
You can find more formats and context on how to create a custom one in the Rails API docs.
Create your own %o format.
Initializer
config/initializers/srtftime.rb
module StrftimeOrdinal
def self.included( base )
base.class_eval do
alias_method :old_strftime, :strftime
def strftime( format )
old_strftime format.gsub( "%o", day.ordinalize )
end
end
end
end
[ Time, Date, DateTime ].each{ |c| c.send :include, StrftimeOrdinal }
Usage
Time.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
You can use this with Date and DateTime as well:
DateTime.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
Date.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
I like Bartosz's answer, but hey, since this is Rails we're talking about, let's take it one step up in devious. (Edit: Although I was going to just monkeypatch the following method, turns out there is a cleaner way.)
DateTime instances have a to_formatted_s method supplied by ActiveSupport, which takes a single symbol as a parameter and, if that symbol is recognized as a valid predefined format, returns a String with the appropriate formatting.
Those symbols are defined by Time::DATE_FORMATS, which is a hash of symbols to either strings for the standard formatting function... or procs. Bwahaha.
d = DateTime.now #Examples were executed on October 3rd 2008
Time::DATE_FORMATS[:weekday_month_ordinal] =
lambda { |time| time.strftime("%a %b #{time.day.ordinalize}") }
d.to_formatted_s :weekday_month_ordinal #Fri Oct 3rd
But hey, if you can't resist the opportunity to monkeypatch, you could always give that a cleaner interface:
class DateTime
Time::DATE_FORMATS[:weekday_month_ordinal] =
lambda { |time| time.strftime("%a %b #{time.day.ordinalize}") }
def to_my_special_s
to_formatted_s :weekday_month_ordinal
end
end
DateTime.now.to_my_special_s #Fri Oct 3rd

Add st, nd, rd, or th to date (ordinalize) [duplicate]

I want to display dates in the format: short day of week, short month, day of month without leading zero but including "th", "st", "nd", or "rd" suffix.
For example, the day this question was asked would display "Thu Oct 2nd".
I'm using Ruby 1.8.7, and Time.strftime just doesn't seem to do this. I'd prefer a standard library if one exists.
Use the ordinalize method from 'active_support'.
>> time = Time.new
=> Fri Oct 03 01:24:48 +0100 2008
>> time.strftime("%a %b #{time.day.ordinalize}")
=> "Fri Oct 3rd"
Note, if you are using IRB with Ruby 2.0, you must first run:
require 'active_support/core_ext/integer/inflections'
You can use active_support's ordinalize helper method on numbers.
>> 3.ordinalize
=> "3rd"
>> 2.ordinalize
=> "2nd"
>> 1.ordinalize
=> "1st"
Taking Patrick McKenzie's answer just a bit further, you could create a new file in your config/initializers directory called date_format.rb (or whatever you want) and put this in it:
Time::DATE_FORMATS.merge!(
my_date: lambda { |time| time.strftime("%a, %b #{time.day.ordinalize}") }
)
Then in your view code you can format any date simply by assigning it your new date format:
My Date: <%= h some_date.to_s(:my_date) %>
It's simple, it works, and is easy to build on. Just add more format lines in the date_format.rb file for each of your different date formats. Here is a more fleshed out example.
Time::DATE_FORMATS.merge!(
datetime_military: '%Y-%m-%d %H:%M',
datetime: '%Y-%m-%d %I:%M%P',
time: '%I:%M%P',
time_military: '%H:%M%P',
datetime_short: '%m/%d %I:%M',
due_date: lambda { |time| time.strftime("%a, %b #{time.day.ordinalize}") }
)
>> require 'activesupport'
=> []
>> t = Time.now
=> Thu Oct 02 17:28:37 -0700 2008
>> formatted = "#{t.strftime("%a %b")} #{t.day.ordinalize}"
=> "Thu Oct 2nd"
Although Jonathan Tran did say he was looking for the abbreviated day of the week first followed by the abbreviated month, I think it might be useful for people who end up here to know that Rails has out-of-the-box support for the more commonly usable long month, ordinalized day integer, followed by the year, as in June 1st, 2018.
It can be easily achieved with:
Time.current.to_date.to_s(:long_ordinal)
=> "January 26th, 2019"
Or:
Date.current.to_s(:long_ordinal)
=> "January 26th, 2019"
You can stick to a time instance if you wish as well:
Time.current.to_s(:long_ordinal)
=> "January 26th, 2019 04:21"
You can find more formats and context on how to create a custom one in the Rails API docs.
Create your own %o format.
Initializer
config/initializers/srtftime.rb
module StrftimeOrdinal
def self.included( base )
base.class_eval do
alias_method :old_strftime, :strftime
def strftime( format )
old_strftime format.gsub( "%o", day.ordinalize )
end
end
end
end
[ Time, Date, DateTime ].each{ |c| c.send :include, StrftimeOrdinal }
Usage
Time.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
You can use this with Date and DateTime as well:
DateTime.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
Date.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
I like Bartosz's answer, but hey, since this is Rails we're talking about, let's take it one step up in devious. (Edit: Although I was going to just monkeypatch the following method, turns out there is a cleaner way.)
DateTime instances have a to_formatted_s method supplied by ActiveSupport, which takes a single symbol as a parameter and, if that symbol is recognized as a valid predefined format, returns a String with the appropriate formatting.
Those symbols are defined by Time::DATE_FORMATS, which is a hash of symbols to either strings for the standard formatting function... or procs. Bwahaha.
d = DateTime.now #Examples were executed on October 3rd 2008
Time::DATE_FORMATS[:weekday_month_ordinal] =
lambda { |time| time.strftime("%a %b #{time.day.ordinalize}") }
d.to_formatted_s :weekday_month_ordinal #Fri Oct 3rd
But hey, if you can't resist the opportunity to monkeypatch, you could always give that a cleaner interface:
class DateTime
Time::DATE_FORMATS[:weekday_month_ordinal] =
lambda { |time| time.strftime("%a %b #{time.day.ordinalize}") }
def to_my_special_s
to_formatted_s :weekday_month_ordinal
end
end
DateTime.now.to_my_special_s #Fri Oct 3rd

Which one of these is correct?

Among the following formats which is correct not just syntax but as a practice as well ?
DateTime.strptime((date[:month]+date[:year]),'%B %Y')
or
DateTime.strptime((date[:month]+' '+date[:year]),'%B %Y')
or
DateTime.strptime((date[:month]+date[:year]),'%B%Y')
Ref strptime
They both are correct as long as you giving correct values
of 'date[:month]' & 'date[:year]'
1.9.3p327 :015 > DateTime.strptime("Mar 2010",'%B %Y')
=> Mon, 01 Mar 2010 00:00:00 +0000
1.9.3p327 :016 > DateTime.strptime("Mar2010",'%B %Y')
=> Mon, 01 Mar 2010 00:00:00 +0000
Syntactically, both DateTime.strptime((date[:month]+' '+date[:year]),'%B %Y') and DateTime.strptime((date[:month]+date[:year]),'%B%Y') are correct.
As a practice, the 2nd one is better as there is no point adding a ' ' and then parsing it out. Anyway, both will give the same output.

Resources