Extract recognized date string passed to parse method in Chronic - ruby-on-rails

I'd like to mimic the functionality of the Mac calendar quick event or Fantastical's quick entry. Using the Chronic gem, I can pass a string like:
"Today at 3pm"
=> 2014-01-24 15:00:00 -0600
Chronic parsing doesn't work if you pass in something like:
"Eat at Joes Today at 3pm"
=> nil
What I've done so far is use a simple regex to split a string at a word normally used to return a date with Chronic. The initial regex is simple:
scan(/(.+)(tomorrow{1}.+|in\s.+|next\s.+|today\s.+)/)
This returns an array with the "title", if you will, and the string I want to sent to Chronic to parse for me.
Two questions:
Is this really the best way to do this? I'd have to provide some mega regex to split whatever string I think my users will submit here.
Would hacking at Chronic be better? It's already parsing the dates for me, but my initial thought is no because if you pass Eat at Joes Today at 3pm to Chronic.parse, it'll return nil. It seems it doesn't recognize the part of the string for formatting the date in it's present form.

I wouldn't edit Chronic. Chronic's only function is to parse natural language date time, not other input. You might be interested in the Nickel gem here:
https://github.com/iainbeeston/nickel
This separates time from other language.
n = Nickel.parse("use the force on july 1st at 9am", Time.now)
n.message #=> "use the force"
n.occurrences.first.start_date #=> "20110701"

Related

Split ruby string and then swap two elements in that array

I have a rails and react app and i noticed i have been logging the date into my backend as day/month/year instead of month/day/year. what is the best way to go into my rails backend and fix theses dates. For example I want to turn "7/3/2018" into "3/7/2018" (yes they are strings).
I'm assuming i would start off with something like this:
date = "7/3/2018"
date.split("/")
but then how will i swap the values? Or is there a better way to do this other than to use split?
You can get each value in the array from the splitted string, and then interpolate them in a new string in the order you need:
date = '7/3/2018'
month, day, year = date.split('/')
p "#{day}/#{month}/#{year}" # "3/7/2018"
Other way could be using Date#parse and strftime to handle the format output:
require 'date'
date = '7/3/2018'
p Date.parse(date).strftime('%m/%d/%Y') # "03/07/2018"

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.

Ruby string to Date object

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

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.

Ruby Time.parse gives me out of range error

I am using Time.parse to create a Time object from a string.
For some reason
Time.parse("05-14-2009 19:00")
causes an argument our of range error, whereas
Time.parse("05-07-2009 19:00")
does not
Any ideas?
If you know the format of the string use:
Time.strptime(date, format, now=self.now) {|year| ...}
http://www.ruby-doc.org/core-1.9/classes/Time.html#M000266
It will solve your problem and will probably be faster than Time.parse.
EDIT:
Looks like they took strptime from Time class, but it called Date.strptime anyway. If you are on Rails you can do:
Date.strptime("05-14-2009 19:00","%m-%d-%Y %H:%M").to_time
if you use pure ruby then you need:
require 'date'
d=Date._strptime("05-14-2009 19:00","%m-%d-%Y %H:%M")
Time.utc(d[:year], d[:mon], d[:mday], d[:hour], d[:min],
d[:sec], d[:sec_fraction], d[:zone])
See also: Date and Time formating issues in Ruby on Rails.
It's because of the heuristics of Time#parse.
And it's due to anglo-american formats.
With dashes '-' it expects mm-dd-yyyy, with slashes '/' it expects dd/mm/yyyy.
This behaviour changes intentionally in 1.9. to accomplish eur, iso and jp date standards.
My guess would be that its expecting the second part of the string (the 14) to be the month.
This link may help you parse it.
You probably do not need it to solve this problem but I still recommend checking out the natural language date/time parser Chronic, it has saved me a lot of work a couple of times.
It is probably expecting Day-Month-Year format, so your first value is trying to specify the 5th day of the 14th month.

Resources