EzDevInfo.com

chronic

Chronic is a pure Ruby natural language date parser.

does chronic have any options of date format it parses? (ruby)

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)

Can using Chronic impair your sense of time?

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)

Advertisements

rails -- parse military time into AM/PM, using chronic?

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)

How to set timezone in ActiveSupport's TimeZone class

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)

Get the last Sunday of the Month

I'm using Chronic to get the last Sunday of the month of any given year. It will gladly give me the n‌th 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)

Problems installing rdoc, irb, bluecloth, chronic on fedora 12

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)

Rails chronic gem not validating as expected

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)

How to use Chronic to parse dates in a datetime text_field

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)

How do set ruby Gem Chronic's default timezone to Specific Timezone without rails

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)

Is there a 24-hour time setting for Chronic?

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)

Rails: Custom validations using ActiveModel

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

enter image description here

then it redirects to ..

localhost:3000/main/search?utf8=%E2%9C%93&q=invalid+date+test

enter image description here

No validation, no date, nothing..


Source: (StackOverflow)

Rubygems Chronic cannot parse "2010-09-12 3:12pm" but can parse "2010-09-12 3pm" or "last monday 3:12pm"?

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)

Extract recognized date string passed to parse method in Chronic

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:

  1. 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.
  2. 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)

Using Ruby Chronic To Calculate Offset Of Date

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:

  1. Can I use chronic to parse offsets of existing date objects? (eg. 14 days before this date instead of just +14 days).

  2. Can I use chronic to parse offsets of existing dates at all?

  3. 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)

chronic gem getting a undefined method `time_class='

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)