Rails translate current date in another format - ruby-on-rails

In Rails I'm trying to localize the date:
2.1.1 :005 > Date.today
=> Mon, 14 Apr 2014
2.1.1 :006 > I18n.localize(Date.today)
=> "14/04/2014"
2.1.1 :007 >
The second output is not the correct translation of the first!
Can you help me ?

You can define a new format:
en:
date: # there is also a section for datetime and time
formats:
day_month_abbr: "%a, %d %b %Y"
and use it like this:
I18n.localize(Date.today, format: :day_month_abbr)
# => "Mon, 14 Apr 2014"
Or you can overwrite the default format:
en:
date:
formats:
default: "%a, %d %b %Y"
And then you don't need to give any argument:
I18n.l(Date.today) #=> "Mon, 14 Apr 2014"
List of all the wildcards usable for DateTime/Time/Date here: http://apidock.com/ruby/DateTime/strftime

The second upload is in fact the correct translation.
If you want to customize the output formatting, check out the documentation here:
http://edgeguides.rubyonrails.org/i18n.html#adding-date-time-formats

Related

Date validation in Ruby

How to check if the date is valid date in ruby. Many of the methods are check only the range. But, I need to check the date with day of
week to check whether the date is valid or not. For Ex:
20 Jul 2016 Wed --> Valid
20 Jul 2016 Mon --> Not-Valid
How to do this in ruby ?
I'm not pretend on the best solution ever, but this should work.
def valid_date?(date)
Date.parse(date).strftime("%d %b %Y %a") == date
end
[55] pry(main)> valid_date?("20 Jul 2016 Wed")
=> true
[56] pry(main)> valid_date?("20 Jul 2016 Mon")
=> false
[57] pry(main)>
If you have many formats you may pass format as a second argument
def valid_date?(date, fmt)
Date.parse(date).strftime(fmt) == date
end
=> :valid_date?
[59] pry(main)> valid_date?("20 Jul 2016 Wed", "%d %b %Y %a")
=> true
Hope this will help.
UPDATE
As I mentioned in comment that method name overlaps with existing method valid_date?
So, you may just rename the custom method
def date_valid?(date, fmt)
Date.parse(date).strftime(fmt) == date
end
[2] pry(main)> date_valid?("20 Jul 2016 Wed", "%d %b %Y %a")
=> true
Just out of curiosity:
dates = ['20 Jul 2016 Wed', '20 Jul 2016 Mon']
dates.map do |date|
Date.parse(date).public_send(
Date.instance_methods.detect do |m|
m.to_s =~ /\A#{date[-3..-1].downcase}.*day\?\z/
end)
end
#⇒ [ true, false ]
require 'date'
dates = ['20 Jul 2016 Wed', '20 Jul 2016 Mon']
dates.select do |s|
d = Date.strptime(s[0,11], "%d %b %Y") rescue nil
d.nil? ? false : (Date::ABBR_DAYNAMES[d.wday] == s[-3,3])
end
#=> ["20 Jul 2016 Wed"]
This reads, "select strings 'dd mmm yyyy' that represent valid dates and whose day-of-week matches the day-of-week given by the last three characters of the string".

Convert Active Support timezone original format into a string

I'm trying to convert Active Support timezone original format into a string. I want to store it in an array of characters then parse each needed data individually.
Time.zone = current_user.timezone
date_and_time = Time.zone.now
Now
date_and_time = Thu, 21 Apr 2016 20:58:04 PDT -07:00
Ruby method ( to_s ) does not convert it. I found other ways to convert it to but all of them will change the format to numbers only, I want the day to stay the same because I will store it in a variable then use it in a different method.
You can use .to_formatted_s(DATE_FORMAT) for this.
time = Time.now # => Thu Jan 18 06:10:17 CST 2007
time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
time.to_formatted_s(:long) # => "January 18, 2007 06:10"
time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
time.to_formatted_s(:iso8601) # => "2007-01-18T06:10:17-06:00"
A list of all DATE_FORMATS and more information can be found here:
http://api.rubyonrails.org/classes/Time.html#method-i-to_formatted_s
You can try this
date_and_time.strftime("%a %d %b %Y")
Also You can check this guide, to get format you want
You should get what you want using this :
date_and_time.strftime("%a %d %b %Y %H:%M:%S UTC %:z")
Please see strftime Docs for more info
Explanation
Reason for hardcoding UTC is so that according to the docs
%z - Time zone as hour and minute offset from UTC
So i believe it should be UTC all the time.

How do I format my created_at output correctly with I18n?

I am using this I18n file.
I am calling it in my view like this:
<td class="center"><%= l o.created_at %></td>
This is being outputted like this:
Mon, 22 May 2013 04:04:43 +0000
For starters, why is it displaying May 22, 2013 and not April 22?
When I do it in the console, I get this:
> o.created_at
=> Mon, 22 Apr 2013 04:04:43 UTC +00:00
I don't want it to display the time, or rather would prefer to just say something like:
Monday, April 22, 2013 # 4:04am
How do I do that?
You can add custom date/time formats to your translation file. To see what time-based substitutions are possible, consult a reference for strfime
formats:
default: ! '%Y-%m-%d'
long: ! '%B %d, %Y'
short: ! '%b %d'
custom: ! '%A, %M %B, %Y # %l:%M%P'
In your view, you'd make use as follows:
<%= l o.created_at, :format => :custom %>
You may need to get rid of blank entries in your en.yml file to correct your translation errors.

Extra space in cucumber step when using to_s(:long)

I have a step that fails with the following...
expected #has_content?("July 4, 2009") to return true, got false
The problem, I think, is the extra space between "July" and "4". I am using published_on.to_s(:long) in both the step definition and the view, so I'm not entirely sure where the extra space is coming from.
Any ideas?
It's what happens when you try:
Date.civil(2010, 7, 4).strftime("%e") # => " 4"
And Rails uses %e in their :long format. The funny thing is that %e isn't documented.
I would adjust my step definition to match Ruby behavior if you don't care about the extra space (extra spaces won't show in HTML anyway). If you do care about it, squish it:
Date.civil(2010, 7, 4).to_s(:long).squish # => "July 4, 2010"
Squish is avaiable in Rails 3. If you're using Rails 2, you can use gsub:
Date.civil(2010, 7, 4).to_s(:long).gsub(/\s+/, " ") # => "July 4, 2010"
I ran into the same problem with my cucumber test today!
The problem (as iain pointed out) is that Date::DATE_FORMATS[:long] is "%B %e, %Y". The %e, according to ri strftime, yields a blank-padded day number:
%d - Day of the month, zero-padded (01..31)
%-d no-padded (1..31)
%e - Day of the month, blank-padded ( 1..31)
So by default, this is what I see in Rails 3.1.3:
> d = '2012-02-01'.to_date
=> Wed, 01 Feb 2012
> d.to_s(:long)
=> "February 1, 2012"
Strangely, Rails uses a different day format for the :long format of times (%d, which yields "01") as for dates (%e, which yields " 1"):
> d = '2012-02-01'.to_time
=> 2012-02-01 00:00:00 UTC
> d.to_s(:long)
=> "February 01, 2012 00:00"
> Time::DATE_FORMATS[:long]
=> "%B %d, %Y %H:%M"
> Date::DATE_FORMATS[:long]
=> "%B %e, %Y"
The solution then is to use "%-d" for the day in your format string instead of %e:
> Date::DATE_FORMATS[:long] = "%B %-d, %Y"
=> "%B %-d, %Y"
> d = '2012-02-01'.to_date
Wed, 01 Feb 2012
> d.to_s(:long)
=> "February 1, 2012"
You can just add this line to a new initializer, config/initializers/date_formats.rb:
Date::DATE_FORMATS[:long] = "%B %-d, %Y"
Please comment on https://github.com/rails/rails/pull/1994 if you would like to see this default changed in Rails.
For what it's worth, I would rather use the "%-d" fix (or even "%-e"! which gives the same results) than ".squish", which is Rails-specific, and not as portable (why not use the Ruby-native ".squeeze", or even ".squeeze(' ')" at that then, if you don't want to mess around with the date formats?).
Also, as an update: #iain mentions that '%e' isn't documented. For what it's worth, it is now! (although interestingly, not "%-e" specifically, which, if you do try it, is valid, and works!)

In Ruby on Rails, how do I format a date with the "th" suffix, as in, "Sun Oct 5th"?

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

Resources