How do I parse a translated date in Ruby on Rails? - ruby-on-rails

I have configured an application in Ruby on Rails with translations to Spanish.
Now I need to parse a translated date, for example:
Jueves, 22 de Noviembre del 2012
I'm trying to do it this way:
Date.strptime('Jueves, 22 de Noviembre, 2012', '%A, %e de %B, %Y')
But it throws an invalid date error.
How can I do it?

Date::parse should understand Spanish. However, that de seems to throw the parser off. If you could get it into this format, this will work
Date.parse "Jueves, 22 Noviembre, 2012"
=> Thu, 22 Nov 2012

I had a very similar problem and I wrote a gem specifically for the purpose of parsing any non-English textual dates (that use Gregorian calendar), it's called Quando.
The gem readme is very informative and has code examples, but in short, this is how it works:
require 'quando'
Quando.configure do |c|
# First, tell the library how to identify Spanish months in your dates:
c.jan = /enero/i
c.feb = /febrero/i
c.mar = /marzo/i
c.apr = /abril/i
c.may = /mayo/i
c.jun = /junio/i
c.jul = /julio/i
c.aug = /agosto/i
c.sep = /septiembre/i
c.oct = /octubre/i
c.nov = /noviembre/i
c.dec = /diciembre/i
# Then, define pattern matchers for different date variations that you need to parse.
# c.day is a predefined regexp that matches numbers from 1 to 31;
# c.month_txt is a regexp that combines all month names that you previously defined;
# c.year is a predefined regexp that matches 4-digit numbers;
# c.dlm matches date parts separators, like . , - / etc. See readme for more information.
c.formats = [
/#{c.day} \s #{c.month_txt} ,\s #{c.year} $/xi, # matches "22 Mayo, 2012" or similar
/#{c.year} - #{c.month_txt} - #{c.day}/xi, # matches "2012-Mayo-22" or similar
# Add more matchers as needed. The higher in the order take preference.
]
end
# Then parse the date:
Quando.parse('Jueves, 22 Noviembre, 2012') # => #<Date: 2012-11-22 …>
You can redefine the matchers for date parts and formats partially or entirely, both globally or just for a single parser instance (to preserve your global settings), and use all the power of regular expressions.
There are more examples in the readme and in the source code. Hope you'll find the library useful.

So, the answer is: it's not possible, at least right now.
The only way to have it working, is by using javascript on the client side, and convert the format to another one before sending the field to the server. Then Rails will not have any problem parsing it.

Related

write Regex to find match

I never wrote any complex regular expression before, and what I need seems to be (at least) a bit complicated.
I need a Regex to find matches for the following:
"On Fri, Jan 16, 2015 at 4:39 PM"
Where On will always be there;
then 3 characters for week day;
, is always there;
space is always there;
then 3 characters for month name;
space is always there;
day of month (one or two numbers);
, is always there;
space is always there;
4 numbers for year;
space at space always there;
time (have to match 4:39 as well as 10:39);
space and 2 caps letters for AM or PM.
Here's a very simple and readable one:
/On \w{3}, \w{3} \d{1,2}, \d{4} at \d{1,2}:\d{2} [AP]M/
See it on rubular
Try this:
On\s+(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), (?:Jan|Feb|Mar|Apr|May|June|July|Aug|Sept|Oct|Nov|Dec) \d{1,2}, \d{4} at \d{1,2}:\d{2} (?:AM|PM)
/On \w{3}, \w{3} \d{1,2}, \d{4} at \d{1,2}:\d{1,2} [A-Z]{2}/
# \w{3} for 3 charecters
# \d{1,2} for a or 2 digits
# \d{4} for 4 digits
# [A-Z]{2} for 2 capital leters
You could try the below regex and it won't check for the month name or day name or date.
^On\s[A-Z][a-z]{2},\s[A-Z][a-z]{2}\s\d{1,2},\s\d{4}\sat\s(?:10|4):39\s[AP]M$
DEMO
You can use Rubular to construct and test Ruby Regular Expressions.
I have put together an Example: http://rubular.com/r/45RIiwheqs
Since it looks you try to parse dates, you should use Date.strptime.
/On [A-Za-z]{3}, [A-Za-z]{3} \d{1,2}, \d{4} at \d{1,2}:\d{1,2}/g
The way you are describing the problem makes me thing that the format will always be preserved.
I would then in your case use the Time.parse function, passing the format string
format = "On %a, %b"On Fri, Jan 16, 2015 at 4:39 PM", format)
which is more readable than a regexp (in my opinion) and has the added value that it returns a Time object, which is easier to use than a regexp match, in case you need to perform other time-based calculations.
Another good thing is that if the string contains an invalid date (like "On Mon, Jan 59, 2015 at 37:99 GX" ) the parse function will raise an exception, so that validation is done for free for you.

Change Format Date From "Fri, 18 Jul 2014" to 7/18/14 Rails

I am parsing an xls file and it has changed all my dates to this format "Fri, 18 Jul 2014" and i need it back to this format "7/18/2014" or to "2014-07-18 17:00:00"
I have tried to use Chronic.parse() with no luck
You would first need to use Date.parse to turn your string into a Date object and then use Date#strftime.
Date.parse("Fri, 18 Jul 2014").strftime("%m/%d/%Y")
A good website for playing around with the different formatting options is:
http://www.foragoodstrftime.com/
You also have the localize() method of I18n (a Rails' guide of Internationalization):
I18n.localize(Date.current)
Uses the format defined for the current language in:
date:
formats:
default: "%Y-%m-%d"
short: "%b %d"
long: "%B %d, %Y"
# other formats' usage:
I18n.localize(Date.current, format: :long)
.localize has the same shorthand as .translate:
# in your views, you can simply do
Post's was created on <%= l(post.created_at, format: :long) %>
This method is very usefull since it relies on the end-user's language and can be easily changed. There is tons of helpers helping you dealing with Language AND dates (datetimes):
http://apidock.com/rails/ActionView/Helpers/DateHelper/distance_of_time_in_words
http://apidock.com/rails/v4.0.2/ActionView/Helpers/DateHelper/time_ago_in_words
All using I18n translation system in order to follow each language's specification/translation.

How to display DateTimes with am/pm without using custom formatting in Rails

Currently I display my DateTimes in Rails with:
my_time.to_formatted_s(:long_ordinal)
That produces a date like:
March 17th, 2014 14:44
Perfect except for the 14:44 time. I want it to say 2:44pm (how the 'pm' is formatted doesn't matter to me). This needs to be easier for a common person to read. I know I can use:
my_time.strftime('%l:%M %p')
However, I'd really like to use a predefined symbol for a more human readable format, because I'd like this to be more human readable in any language. If someone is browsing from a different language where DateTimes naturally look a little different, I'm hoping Rails can, or at least be set to, automatically display the DateTime nicely. Maybe I'm expecting too much of Rails there? Seems strange to me though that there isn't a simple flag or setting for a more human readable DateTime format.
in that case you can add your own humanized format
# config/initializers/time_formats.rb
Time::DATE_FORMATS[:custom_long_ordinal] = "%B %e, %Y %l:%M %p"
and use it with
my_time.to_formatted_s(:custom_long_ordinal)
Refer to the api doc reference for ActiveSupport DateTime formatting: http://apidock.com/rails/ActiveSupport/CoreExtensions/DateTime/Conversions/to_formatted_s
If you just want 10:15 pm
You could use:
t=Time.now
am=true
if t.hour >= 12
t=t-12*60*60
am=false
end
s=t.to_s[13..17]
if am==true
return s+ "am"
else
return s+ "pm"
end
Or edit/expand the Time-Class with SOMETHING LIKE (I would not advice you use this code, it's just a draft)
class Time
def self.humanize
t=self
am=true
if t.hour >= 12
t=t-12*60*60
am=false
end
s=t.to_s[13..17]
if am==true
return s+ "am"
else
return s+ "pm"
end
end
end
It sounds like you'll be better reading up on Rails' i18n
We format our times using the config/locales/xx.yml file:
#config/locals/en.yml
en:
time:
formats:
small: "%-dM %-dD %-dW"
This allows us to call:
<%=l object, format: :small %>
You can then use strftimer to get some really nice formatting

Rails: Date.today - 1.day

Using the rails console, I just got bit by this:
Assume today is December 11.
Date.today-1.day # December 10 (no spaces)
Date.today - 1.day # December 10 (a space on both sides of the minus sign)
Date.today -1.day # December 11 whaaaat?
Date.today -5.days # Still december 11!
Can someone explain what's going on here? I am a little worried about how easy this could be missed in code. Any other suggestions on how to code this?
The difference you are seeing is caused by the way how ruby parses your code. In your case, you have stumbled about a syntactic nuance which greatly changes how the code is evaluated.
Your first two examples are actually expressions involving an operation on an object. Thus
Date.today-1.day
Date.today - 1.day
are both equivalent to
Date.today.send(:-, 1.day)
# a "fancy" way to write
Date.today - 1.day
Your second two examples
Date.today -1.day
Date.today -5.days
are actually direct method calls on the Date.today method and are thus equivalent to
Date.today( (-1).day )
This is because the minus is interpreted as a prefix to the 1 (and thus is parsed as the number -1). This interpretation is possible and doesn't throw any errors because of two properties of ruby:
Parenthesis are optional when calling methods as long as the result is unambiguous
Date.today accepts an optional argument denoting calendar used
The actual results you receive depend a bit on your environment as Rails seems to override some Date methods here. In plain Ruby, you would get different dates back but it would still work.
When you don't add a space after the minus sign, ruby takes it as a parameter for the function today. This function can receive one parameter. See here
Your problem is a little syntax problem.
This works fine for me
Date.today
# => Sun, 18 May 2014
Date.today() - 1.day
# => Sat, 17 May 2014
An prettier option is
Date.yesterday
# => Sat, 17 May 2014
Good luck!

Ruby on Rails I18n - Localization of Dates Works In localhost but Not In Production

I am using Ruby on Rails 3.2.13 Ruby 1.9.3.
I have the following code in my en.yml file:
date:
formats:
default: "%Y-%m-%d"
short: "%b %d"
long: "%A, %B %d, %Y"
mmyy: "%B %Y"
I have the following code in my fr.yml file:
date:
formats:
default: "%Y-%m-%d"
short: "%b %d"
long: "%A, %d %B %Y"
mmyy: "%B %Y"
My date field media_created is stored in a string in YYYY-MM-DD format
Here is the code in my view to display the short date format in my view:
<%= l media_item.media_created.to_date, format: :mmyy %>
Here is an example of how my short format works in localhost (date 2013-07-01):
July 2013 (en)
juillet 2013 (fr)
Here is an example of how my long format works in production (date 2013-07-01):
July 2013 (en)
July 2013 (fr)
Here is the code in my view to display the long date format in my view:
<%= l media_item.media_created.to_date, format: :long %>
Here is an example of how my long format works in localhost (date 2013-06-23 which was on Sunday):
Sunday, June 23, 2013 (en)
dimanche, 23 juin 2013 (fr)
Here is an example of how my long format works in production (date 2013-06-23):
Sunday, June 23, 2013 (en)
Sunday, June 23, 2013 (fr)
I read the http://guides.rubyonrails.org/i18n.html and several examples on Stack Overflow which used the l helper as described in section 3.3. However in section 5 it talks about using the t helper for custom translations. I am using t for all my other I18n internationalization and it is working fine. The only problem is when I use the l helper for dates.
I have looked for examples of how to use the t helper as described in the link Rails Guide link. The link does not give an example of how to code a statement with a field name. All of the examples I have found in Stack Overflow are using the l helper or the strftime method. I want to be able to 'translate' the date formats like I do the rest of the application in production like it works in localhost. I have checked all the files that I have changed to do this on my production server to make sure that all the files were moved over there. From what I did read it seems like the l helper may not work that well for custom translations. Maybe using the t helper will take care of this problem which was suggested by the Rails Guide. I will keep looking to see if I can find examples using the t helper like I included here for the l helper or try and guess some solutions.
Any help would be appreciated.
UPDATE: 7/29/2013 12:47 pm CDT - The only other difference that I can see between the two servers is that the development server is running ruby 1.9.3p327 and the production server is running ruby 1.9.3p362. However I cannot believe that could be causing my problem but it is a difference that I feel I should note.
I could not find any other questions or comments relating to this. I decided to copy the fr.yml hashes for the rails-i18n gem. I did not have to do this on my development server to get the date formatting to translate into French. As I stated it was working fine without them. When I deployed the new yaml file in production all my clauses are in French. I guess there is a needle in a haystack type of bug somewhere in the i18n process. At least the Rails translations for dates are working now.

Resources