chronic
Chronic is a pure Ruby natural language date parser.
I need to tell chronic that the format of date is day-month-year is that possible? The data I pass to chronic could also be words today/yesterday/2 days ago.
Currently chronic gives me 2 Dec 2010
instead of 12 Feb 2010
from 12-02-2010
The only solution I can think of is to swap day and month before passing the string to chronic.
require 'chronic'
puts "12-02-2010 = #{Chronic.parse('12-02-2010')}" #should be 12 Feb 2010
puts "yesteday = #{Chronic.parse('yesterday')}" #working ok
puts "Today = #{Chronic.parse('today')}" #working ok
Source: (StackOverflow)
Haha..
I'm using Chronic to parse the time users add in the Calendar. Where the code works and implements the right time, the end result is that, IF a user adds a time, then it has no date, and because it has no date, it will not show in results. Any ideas?
def set_dates
unless self.natural_date.blank? || Chronic.parse(self.natural_date).blank?
# check if we are dealing with a date or a date + time
if time_provided?(self.natural_date)
self.date = nil
self.time = Chronic.parse(self.natural_date)
else
self.date = Chronic.parse(self.natural_date).to_date
self.time = nil
end
end
unless self.natural_end_date.blank? || Chronic.parse(self.natural_end_date).blank?
# check if we are dealing with a date or a date + time
if time_provided?(self.natural_end_date)
self.end_date = nil
self.end_time = Chronic.parse(self.natural_end_date)
else
self.end_date = Chronic.parse(self.natural_end_date).to_date
self.end_time = nil
end
end
end
Edit:
Here is the time_provided? method:
def time_provided?(natural_date_string)
date_span = Chronic.parse(natural_date_string, :guess => false)
(date_span.last - date_span.first).to_i == 1
end
Source: (StackOverflow)
I've been using Chronic, the natural language parser and its awesome. The problem I'm running into now is I cant parse the military time its give me back in to some form of AM/PM time that would be normal for a user to see.
<%= Chronic.parse("next monday") %>
yields => Mon Jul 05 12:00:00 -0500 2010
Is there a way to go backwards so I can parse "Mon Jul 05 12:00:00 -0500 2010" into "Monday July 5th 5:00 AM" or even better yet just "5:00 AM"?
Wierd one I know, but I thought someone must have dealt with this before.
Source: (StackOverflow)
I am trying to parse text into a date using chronic in ruby. However, I keep running into an error while trying to parse the string.
Error: NoMethodError - undefined method 'zone=' for Time:Class:
Here is the code:
require 'rubygems'
require 'sinatra'
require 'chronic'
require 'date'
require 'time'
require 'active_support'
require 'cgi'
require 'json'
module TimeAPI
ZoneOffset = {
'A' => +1,
'ADT' => -3,
'AKDT' => -8,
'AKST' => -9,
'AST' => -4,
'B' => +2,
'BST' => +1,
'C' => +3,
'CDT' => -5,
'CEDT' => +2,
'CEST' => +2,
'CET' => +1,
'CST' => -6,
'D' => +4,
'E' => +5,
'EDT' => -4,
'EEDT' => +3,
'EEST' => +3,
'EET' => +2,
'EST' => -5,
'F' => +6,
'G' => +7,
'GMT' => 0,
'H' => +8,
'HADT' => -9,
'HAST' => -10,
'I' => +9,
'IST' => +1,
'K' => +10,
'L' => +11,
'M' => +12,
'MDT' => -6,
'MSD' => +4,
'MSK' => +3,
'MST' => -7,
'N' => -1,
'O' => -2,
'P' => -3,
'PDT' => -7,
'PST' => -8,
'Q' => -4,
'R' => -5,
'S' => -6,
'T' => -7,
'U' => -8,
'UTC' => 0,
'V' => -9,
'W' => -10,
'WEDT' => +1,
'WEST' => +1,
'WET' => 0,
'X' => -11,
'Y' => -12,
'Z' => 0
}
class App < Sinatra::Base
set :sessions, false
set :run, false
set :environment, ENV['RACK_ENV']
def callback
(request.params['callback'] || '').gsub(/[^a-zA-Z0-9_]/, '')
end
def prefers_json?
(request.accept.first || '').downcase == 'application/json'
end
def json?
prefers_json? \
|| /\.json$/.match((params[:zone] || '').downcase) \
|| /\.json$/.match((params[:time] || '').downcase)
end
def jsonp?
json? && callback.present?
end
def format
format = (request.params.select { |k,v| v.blank? }.first || [nil]).first \
|| request.params['format'] \
|| (jsonp? ? '%B %d, %Y %H:%M:%S GMT%z' : '')
CGI.unescape(format).gsub('\\', '%')
end
get '/' do
erb :index
end
get '/favicon.ico' do
''
end
get '/:zone/?' do
parse(params[:zone])
end
get '/:zone/:time/?' do
parse(params[:zone], params[:time])
end
def parse(zone='UTC', time='now')
zone = zone.gsub(/\.json$/, '').upcase
puts zone
offset = ZoneOffset[zone] || Integer(zone)
puts offset
time = time \
.gsub(/\.json$/, '') \
.gsub(/^at /, '') \
.gsub(/(\d)h/, '\1 hours') \
.gsub(/(\d)min/, '\1 minutes') \
.gsub(/(\d)m/, '\1 minutes') \
.gsub(/(\d)sec/, '\1 seconds') \
.gsub(/(\d)s/, '\1 seconds')
puts time
if prefers_json?
response.headers['Content-Type'] = 'application/json'
end
Time.zone = offset
Chronic.time_class = Time.zone
time = Chronic.parse(time).to_datetime.to_s(format)
time = json? ? { 'dateString' => time }.to_json : time
time = jsonp? ? callback + '(' + time + ');' : time
end
end
end
class Time
def to_datetime
# Convert seconds + microseconds into a fractional number of seconds
seconds = sec + Rational(usec, 10**6)
# Convert a UTC offset measured in minutes to one measured in a
# fraction of a day.
offset = Rational(utc_offset, 60 * 60 * 24)
DateTime.new(year, month, day, hour, min, seconds, offset)
end
end
class DateTime
def to_datetime
self
end
def to_s(format='')
unless format.empty?
strftime(format)
else
strftime
end
end
end
When I try to set the timezone using:
Time.zone = offset
Chronic.time_class = Time.zone
it throws me that error. I am printing the offset and it is appropriate according to the docs. I even replaced the calculated offset with 'Eastern Time (US & Canada)'
(straight from ActiveSupport Docs)
Error: NoMethodError - undefined method 'now' for "UTC":String:
With 'now' being the time that needs to be parsed and "UTC" being the timezone.
Any and all help is truly appreciated.
Code source: timeapi
Source: (StackOverflow)
I'm using Chronic to get the last Sunday of the month of any given year. It will gladly give me the nth Sunday, but not the last.
This works, but is not what I need:
Chronic.parse('4th sunday in march', :now => Time.local(2015,1,1))
This is what I need, but doesn't work:
Chronic.parse('last sunday in march', :now => Time.local(2015,1,1))
Is there any way around this apparent limitation?
UPDATE: I'm upvoting the two answers below because they're both good, but I've already implemented this in "pure Ruby" (in 2 lines of code, besides the require 'date'
line), but I'm trying to demonstrate to management that Ruby is the right language to use to replace a Java codebase that is going away (and which had dozens of lines of code to compute this), and I told one manager that I probably could do it in one line of Ruby, and it would be readable and easy to maintain.
Source: (StackOverflow)
What do these errors mean?
[root@localhost config]# gem install bluecloth
Building native extensions. This could take a while...
ERROR: Error installing bluecloth:
ERROR: Failed to build gem native extension.
/usr/bin/ruby extconf.rb
can't find header files for ruby.
Gem files will remain installed in /usr/lib64/ruby/gems/1.8/gems/bluecloth-2.0.7 for
inspection.
Results logged to /usr/lib64/ruby/gems/1.8/gems/bluecloth-2.0.7/ext/gem_make.out
[root@localhost config]#
And this
[root@localhost config]# gem install chronic
Successfully installed json_pure-1.4.3
Successfully installed rubyforge-2.0.4
Successfully installed hoe-2.6.0
Successfully installed chronic-0.2.3
4 gems installed
/usr/lib64/ruby/gems/1.8/gems/rdoc-2.5.8/lib/rdoc/ruby_lex.rb:67: warning:
parenthesize argument(s) for future version
ERROR: While executing gem ... (Gem::DocumentError)
ERROR: RDoc documentation generator not installed: no such file to load -- irb/slex
[root@localhost config]#
I have installed rdocs using "yum install ruby-rdocs". But I don't understand what this error means
Source: (StackOverflow)
I'm trying to enter the date '03/20/1985' into a text field called "birthday" and have it inserted into a database field with the column type "date".
When i enter 10/20/1985
, i get the error "Birthday is invalid", but when i enter 20/10/1985
, it works just fine.
From all the documentation i have been reading, chronic should parse '10/20/1985' as mm/dd/yyyy, but it seems that it's parsing it as dd/mm/yyyy.
How can i make this parse the date as mm/dd/yyyy?
/models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]
# Virtual attribute for authenticating by either username or email
# This is in addition to a real persisted field like 'username'
attr_accessor :login
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :login, :first_name, :last_name, :home_phone, :cell_phone, :work_phone, :birthday, :home_address, :work_address, :position, :company
validate :birthday_is_date
validate :position, :presence => true
require 'chronic'
# validate the birthday format
def birthday_is_date
errors.add(:birthday, "is invalid") unless Chronic.parse(birthday)
end
# validates email or username when logging in
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions).first
end
end
end
Source: (StackOverflow)
I'm trying to get a text field that my users can enter in something that is parsable by the Chronic gem. Here is my model file:
require 'chronic'
class Event < ActiveRecord::Base
belongs_to :user
validates_presence_of :e_time
before_validation :parse_date
def parse_date
self.e_time = Chronic.parse(self.e_time_before_type_cast) if self.e_time_before_type_cast
end
end
I think that it is being called because if I misspell something in parse_date, it complains that it doesn't exist. I've also tried before_save :parse_date, but that doesn't work either.
How could I get this to work?
Thanks
Source: (StackOverflow)
Question
By default, the Chronic gem uses the system timezone as the default timezone.
They mention here (https://github.com/mojombo/chronic#time-zones), that I can use ActiveSupports Time.zone to change this. But i'm not using Rails, i'm using Sinatra and including active support just to utilize the timezone class seems unnecessary.
How else can I do this?
What i'm trying to do.
I'm using Chronic for system reporting / dashboards and stats.
The servers are storing timestamps in the created_at fields in the DB at utc time.
But of course we run our reports as PDT.
I want to set the default timezone to America/Los_Angeles.
So that:
d = Chronic.parse("1 days ago at midnight")
date = d.localtime #Should give me a date like "2013-05-27 00:00:00"
utc_date = date.utc #Should give me a date like "2013-05-27 07:00:00"
How can I accomplish this?
Source: (StackOverflow)
I stumbled upon an interesting (and for quit some time puzzling) behavior using the Chronic gem.
Parsing the string 1/21/13 2:20
:
Chronic.parse('1/21/13 2:20')
=> 2013-01-21 14:20:00 -0800
However, if a 0
is place in front of the 2
:
Chronic.parse('1/21/13 02:20')
=> 2013-01-21 02:20:00 -0800
Now, I can put AM or PM at the end of the string, which essentially overrides this behavior (so it doesn't matter whether the leading 0
is present), but that is obviously an extra step of parsing, and negates much of the advantage of using Chronic. Is there another option to deal with this leading zero problem appropriately? It caught me off guard that this wasn't already figured out.
I should note that the strings I need to parse could be either of the two presented cases above.
Source: (StackOverflow)
I am currently trying to make custom validations work with an input of dates, but, unfortunately, it doesn't seem to work.
There are two pages inside the application, Index page and Search page. Inside the index page there is a text field that takes in a date. I am using Chronic gem which parses text into dates. If the date is invalid, Chronic returns nil. If it is valid, it redirects to search page and shows the date.
The code I wrote so far doesn't seem to work properly, but what I want to achieve is..
1) to validate that Chronic doesn't return nil
2) to validate that date is greater than today's date
Please note that I am not using a database with this, I just want to be able to validate inputted date without ActiveRecord. If someone could help me with this, your help will be greatly appreciated.
views/main/index.html.erb
<%= form_tag({controller: "main", action: "search"}, method: "get") do %>
<%= label_tag(:q, "Enter Date:") %>
<%= text_field_tag(:q) %>
<%= submit_tag "Explore", name: nil %>
<% end %>
views/main/search.html.erb
<%= @show_date %>
main_controller.rb
def search
passed_info = Main.new
if passed_info.valid_date?
@show_date = passed_info
else
flash[:error] = "Please enter correct date!"
render :index => 'new'
end
end
models/main.rb
class Main
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :q
validates_presence_of :q
def initialize(params={})
params.each do |attr, value|
self.public_send("#{attr}=", value)
end if params
end
def persisted?
false
end
def valid_date?
require 'chronic'
if Chronic.parse(q).nil? || Chronic.parse(q) < Time.today
errors.add(:q, "is missing or invalid")
end
end
end
EDIT:
this is what goes wrong...
localhost:3000
then it redirects to ..
localhost:3000/main/search?utf8=%E2%9C%93&q=invalid+date+test
No validation, no date, nothing..
Source: (StackOverflow)
It seems strange that "2010--9-12 3:12pm" is a weak spot of Chronic Rubygem? Is there a way to make it work? (or another gem that can do it?) I also hope to find a parser that can handle 2010-09-12 3:12pm UTC
or other timezones such as PDT
, PST
, or UTC+8
or -0700
irb(main):001:0> RUBY_VERSION
=> "1.8.7"
irb(main):002:0> require 'rubygems'
=> true
irb(main):003:0> require 'chronic'
=> true
irb(main):004:0> Chronic.parse('9/12/2010')
=> Sun Sep 12 12:00:00 -0700 2010
irb(main):005:0> Chronic.parse('9/12/2010 3pm')
=> Sun Sep 12 15:00:00 -0700 2010
irb(main):006:0> Chronic.parse('9/12/2010 3:12pm') # <-- cannot work
=> nil
irb(main):007:0> Chronic.parse('last monday 3:12pm')
=> Mon Sep 06 15:12:00 -0700 2010
irb(main):008:0> Chronic.parse('2010-09-12')
=> Sun Sep 12 12:00:00 -0700 2010
irb(main):009:0> Chronic.parse('2010-09-12 3:12pm') # <-- cannot work
=> nil
Source: (StackOverflow)
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.
Source: (StackOverflow)
I use chronic to return parsed date objects like so:
last_pay_date = Date.parse(Chronic.parse('2011-11-04').strftime("%Y-%m-%d"))
two_weeks_ago = Date.parse(Chronic.parse("two weeks ago").strftime("%Y-%m-%d"))
puts last_pay_date # 2011-11-04
puts last_pay_date.class # Date
puts two_weeks_ago # 2011-10-24
puts two_weeks_ago.class # Date
But what I really want to do is date a date object like last_day_date and have the date two weeks before returned, like so:
two_weeks_ago = Date.parse(Chronic.parse("two weeks before #{last_pay_date}").strftime("%Y-%m-%d"))
This returns nil, as other attempts, both with variables and hard coded:
last_pay_date = Date.parse(Chronic.parse('2011-11-04').strftime("%Y-%m-%d"))
two_weeks_ago = Chronic.parse("two weeks before #{last_pay_date}")
puts two_weeks_ago.class #NilClass
puts two_weeks_ago.nil? #true
two_weeks_ago = Chronic.parse("2 weeks before 2011-11-04 05:00:00")
puts two_weeks_ago.class #NilClass
puts two_weeks_ago.nil? #true
Questions:
Can I use chronic to parse offsets of existing date objects? (eg. 14 days before this date instead of just +14 days).
Can I use chronic to parse offsets of existing dates at all?
How is this best accomplished, even if the solution is outside of chronic?
Edit: I am running Ruby 1.9.2 without rails. These are strait up ruby scripts, though I'll happily include any gems needed to do the job.
Source: (StackOverflow)
I have started getting this error on my chronic gem:
undefined method `time_class=' for Chronic:Module
The code is as follows:
time_zone = "America/Los_Angeles"
Time.zone = time_zone
Chronic.time_class = Time.zone
This has definitely worked prior and I'm unclear what is causing the problem.
Source: (StackOverflow)