Ruby string to Date object - ruby-on-rails

I have a Mongoid field that is of type Date. I'm having all sorts of trouble searching for documents against this specific field. I receive dates as a string in this format: 10/20/2013. I thought something like Date.parse("10/20/2013") or "10/20/2013".to_date would be good enough to let me do something like MyModel.find_by(datefield: date_result) but this is giving me a ton of ArgumentError out of range type issues.
What's the easiest way to turn "10/20/2013" into a simple Date object that I can use to query against databases?

You get this:
Date.parse("10/20/2013")
ArgumentError: invalid date
The problem is 10/20. Ruby is an international language, and the values 10 and 20 are somewhat ambiguous. In the U.S. the "standard" date format is "MMDDYYYY", or %m%d%Y in date parsing terms. The majority of the world uses a different standard though, "DDMMYYYY" or %d%m%Y. Ruby uses the second format, with day first.
Looking at the difference, it's easy to see why Date.parse would be confused and complain. 10 is a sensible day, but 20 is nonsense as far as a month, so Ruby rejects it.
You can fix this by forcing the pattern used for parsing:
Date.strptime('10/20/2013', '%m/%d/%Y')
# => #<Date: 2013-10-20 ((2456586j,0s,0n),+0s,2299161j)>

You can use strptime:
Date.strptime('10/20/2013', '%m/%d/%Y')
=> <Date: 2013-10-20 ((2456586j,0s,0n),+0s,2299161j)>
Read this a list of possible formats

Date.parse("10/20/2013")
=> ArgumentError: invalid date
to
Date.parse("20/10/2013")
=> Sun, 20 Oct 2013

Related

Ruby date time parse to get 'th'

I've got date as string '2020-02-10 8,00' which I want to convert into Monday, 10th of February. I'm aware of this old topic however I cannot find (or use) any related information.
All I have is just parsed string to date - Date.parse '2020-02-10 8,00'
You are halfway there! Date.parse '2020-02-10 8,00' produces a ruby Date object, as you have noted. You now have to apply strftime. However strftime doesn't have any ordinalization so that piece has to be done manually.
date = Date.parse('2020-02-10 8,00')
date.strftime("%A, #{date.day.ordinalize} of %B") #=> Monday, 10th of February
the ordinalize method is provided by ActiveSupport.
If this format will be used multiple times in your app, you may wish to add an app-wide format:
# in config/initializers/time_formats.rb
Date::DATE_FORMATS(:ordinalized_day) = lambda{|date| date.strftime("%A, #{date.day.ordinalize} of %B")}
# anywhere in the app
Date.today.to_formatted_s(:ordinalized_day)

How to get the date by day of the week ruby

I'm creating rails app, and I need to put calendar into it. I have a json data which sending to app once in a week. JSON object has something like this:
route: "Monday"
or
route: "Saturday"
I need to put this day of the week as usual date(date calculated every week, since the day when the JSON was sent), for example JSON objects sent today, and to all of them I should give a date, routes: "Saturday" should give me 24-June-2017. Hope u understand my question :)
To get the current day in Rails, you can use:
Date.today
To get the previous Saturday (since today is Monday 3rd July, that's Saturday 1st July), you can use:
Date.today.beginning_of_week(:saturday)
Or, if what you actually wanted was the previous week's Saturday (Saturday 24th June), then you can use:
Date.today.weeks_ago(1).beginning_of_week(:saturday)
Or, if you prefer:
1.week.ago.beginning_of_week(:saturday)
...However, note that the above will return an ActiveSupport::TimeWithZone object rather than a Date object - so will behave slightly differently.
Have a read through the rails documentation - in particular, the ActiveSupport extensions to ruby's Date class to see what methods are available.
If, for some reason, you needed to do this in pure ruby (i.e. without the above mentioned ActiveSupport extensions that come bundled with rails), then you could instead utilise the Date.parse method:
require 'date'
Date.parse("Saturday") - 7
# => Sat, 01 Jul 2017
In order to convert your Date (or similar) object to the string format you desire ("24-June-2017"), you can use ruby's strftime method:
(Date.parse("Saturday") - 7).strftime('%d-%B-%Y')
In rails, it is a common convention to place such custom date formats in a locale or initializer to avoid repetition. You can then reference this format by name:
# config/initializers/date_formats.rb
# (Call this whatever you want!)
Date::DATE_FORMATS[:calendar] = '%d-%B-%Y'
# Anywhere else in the rails app
Date.today.beginning_of_week(:saturday).to_s(:calendar)
# => "01-July-2017"
In addition to #TomLord answer:
One can check which day of the week it is, by using dedicated method monday? to saturday?
e.g:
Date.today
# => Mon, 03 Jul 2017
Date.today.monday?
# => True
Date.today.saturday?
# => False
When working with any built in packages in Ruby it is always a good idea to check out the documentation for available functions and examples. For time, Ruby comes with a convenient Time object which simplifies much of the interactions we do with Time.
For example, one can get the current time using:
t = Time.now, one can then do (t + 1.days).monday? or (t + 2.days).day == 1.
Days already have corresponding int values.
http://ruby-doc.org/core-2.4.1/Time.html
This documentation applies to the newest head, but you can find the version for your ruby with ruby -v and find the appropriate version because it does change over versions.
For your issue, you could have the URL use the string Monday and using a switch case or hash to derive the integer difference from today, using this one could get the exact calendar date. Once it is parsed to Time, you could also do Time.monday?..Time.sunday?, which you may or may not find useful when trying to solve your problem. There are many ways to approach it, but difference from Today is a good solution and with how Time is able to add days like Time.now + 7.days, it feels natural using Ruby to do it in this way.

Retrieve Hash values with key in a specific date format

I'm using Rails. I've stored a count by month in a postgres db as a hash using hstore.
The stored hash is formatted as follows:
{"2017-03-01 00:00:00 UTC"=>"10", "2017-04-01 00:00:00 UTC"=>"3"}
I'm struggling to find a great way to retrieve specific month counts from this hash due to the date format used for the key.
QUESTION
What is the best way to format a string to match the current hash key date format?
For example for March in the Hash the key is "2017-03-01 00:00:00 UTC"
However, a new DateTime for March 1 2017 is formatted as "2017-03-01T00:00:00+00:00"
Or is it best to change the format of how I am storing the hash in the first place?
If you need a timestamp in a specific format, the standard tool to use is DateTime#strftime (all the time-ish classes will have a strftime method and they all behave the same). In your case:
some_datetime.utc.strftime('%Y-%m-%d %H:%M:%S %Z')
And hooking that up to ActiveRecord:
Model.where('your_hstore -> :key', :key => some_datetime.utc.strftime('%Y-%m-%d %H:%M:%S %Z'))
Or:
Model.where('your_hstore -> ?', some_datetime.utc.strftime('%Y-%m-%d %H:%M:%S %Z'))
%Z should be the "Time zone abbreviation name" and for me it produces strings like 'UTC', 'PDT', ... If your strftime (which almost certainly is just a wrapper around the system's libc version of strftime) doesn't produce the strings that you want then you have some options:
Drop the timezone completely if it will always be UTC. Then the keys would look like 2017-03-01 00:00:00 and you'd use '%Y-%m-%d %H:%M:%S' as your strftime format string.
If they keys are actually just dates as they appear to be, then use dates and drop the time-of-day. Then your keys would look like 2017-03-01, you'd use Date instances in Ruby rather than DateTimes, and you'd say some_date.strftime('%Y-%m-%d') or some_date.iso8601 in Ruby to get your hstore keys.
If you are using non-UTC timezones, then convert everything to UTC and go with 1 or 2.
If you don't want any of the above, switch to numeric timezone offsets (2017-05-10 18:05:57 +0000, 2017-05-10 18:06:48 +00:00, ...) and use %z, %:z, or %::z in the strftime format string (see the docs for difference between these three).
These of course require reworking any data you already have in the database but it is best to get the out of the way sooner rather than later.

Ruby: get TimeZone component of string

I'm working with Date strings in Ruby and want to determine if a string was passed with a timezone or not (beyond simply parsing the text). If no timezone is supplied, I want to convert it to a certain timezone dependent on other factors.
Example:
DateTime.parse("2014-01-01T23:59:00")
=> #<DateTime: 2014-01-01T23:59:00+00:00 ((2456659j,86340s,0n),+0s,2299161j)>
DateTime.parse("2014-01-01T23:59:00Z")
=> #<DateTime: 2014-01-01T23:59:00+00:00 ((2456659j,86340s,0n),+0s,2299161j)>
DateTime.parse("2014-01-01T23:59:00PST")
=> #<DateTime: 2014-01-01T23:59:00-08:00 ((2456660j,28740s,0n),-28800s,2299161j)>
The problem is that parsing "2014-01-01T23:59:00" and "2014-01-01T23:59:00Z" (with Zulu) yields the same result, when one is specifying "Zulu" and the other isn't. I'm sure the default behavior is to assume UTC if no zone is supplied.
To check that the date string doesn't end with a time zone, you can check that the minutes and seconds are the end of the string, using this regex: \d{2}:\d{2}$
Here are some examples using debuggex to illustrate:
\d{2}:\d{2}$
Debuggex Demo

Date conversion in rails

I am importing data from CSV inside Rails 3.2 and saving it to mongodb collection and everything works fine except the date field. The imported date format is DD/MM/YYY. Please how can I convert the imported date to YYYY-MM-DD?
Thanks
You could use date parsing like this:
Date.strptime('01/02/2003', '%d/%m/%Y').to_s #=> "2003-02-01"
Date.strptime creates a Date object from a string in the given format
Date#to_s returns it in the ISO 8601 format (i.e. YYYY-MM-DD)
But it depends on how big your CSV is - this would create a bunch of intermediate Date objects which would be a bit slower than a (slightly ugly) string indexing approach:
def reformat_date(date)
"#{date[6..9]}-#{date[3..4]}-#{date[0..1]}"
end
reformat_date('01/02/2003') #=> "2003-02-01"
Update
I was curious so I ran some quick benchmarks - the date parsing method was about 2.7 times slower than the string method (5.289s vs 1.981s for a million conversions, Ruby 1.9.3/Windows). YMMV.
You may need
require 'date'
Then use the following statement to parse the date:
d = Date.strptime('09/10/2012', '%d/%m/%Y')
Using the following examples will return the right format:
d.year #=> 2012
d.mon #=> 10
d.day #=> 9
d.strftime('%Y/%m/%d') #=> "2012/10/09"
Then save it to the database. I'm not familiar with mongodb, though, but I'm sure you know what to do.
For more information on date parsing you should visit http://www.ruby-doc.org/stdlib-1.9.3/libdoc/date/rdoc/DateTime.html.

Resources