module Chronic

def construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)

Returns:
  • (Time) -
def construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
  if second >= 60
    minute += second / 60
    second = second % 60
  end
  if minute >= 60
    hour += minute / 60
    minute = minute % 60
  end
  if hour >= 24
    day += hour / 24
    hour = hour % 24
  end
  # determine if there is a day overflow. this is complicated by our crappy calendar
  # system (non-constant number of days per month)
  day <= 56 || raise("day must be no more than 56 (makes month resolution easier)")
  if day > 28
    # no month ever has fewer than 28 days, so only do this if necessary
    leap_year_month_days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    common_year_month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    days_this_month = Date.leap?(year) ? leap_year_month_days[month - 1] : common_year_month_days[month - 1]
    if day > days_this_month
      month += day / days_this_month
      day = day % days_this_month
    end
  end
  if month > 12
    if month % 12 == 0
      year += (month - 12) / 12
      month = 12
    else
      year += month / 12
      month = month % 12
    end
  end
  Chronic.time_class.local(year, month, day, hour, minute, second)
end

def definitions(options={})

Returns:
  • (Hash) - A Hash of Handler definitions

Other tags:
    See: parse -
def definitions(options={})
  options[:endian_precedence] ||= [:middle, :little]
  @definitions ||= {
    :time => [
      Handler.new([:repeater_time, :repeater_day_portion?], nil)
    ],
    :date => [
      Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :repeater_time, :separator_slash_or_dash?, :time_zone, :scalar_year], :handle_rdn_rmn_sd_t_tz_sy),
      Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :repeater_time, :time_zone], :handle_sy_sm_sd_t_tz),
      Handler.new([:repeater_month_name, :scalar_day, :scalar_year], :handle_rmn_sd_sy),
      Handler.new([:repeater_month_name, :ordinal_day, :scalar_year], :handle_rmn_od_sy),
      Handler.new([:repeater_month_name, :scalar_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_sd_sy),
      Handler.new([:repeater_month_name, :ordinal_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_od_sy),
      Handler.new([:repeater_month_name, :scalar_day, :separator_at?, 'time?'], :handle_rmn_sd),
      Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :scalar_day], :handle_rmn_sd_on),
      Handler.new([:repeater_month_name, :ordinal_day, :separator_at?, 'time?'], :handle_rmn_od),
      Handler.new([:ordinal_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_od_rmn_sy),
      Handler.new([:ordinal_day, :repeater_month_name, :separator_at?, 'time?'], :handle_od_rmn),
      Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :ordinal_day], :handle_rmn_od_on),
      Handler.new([:repeater_month_name, :scalar_year], :handle_rmn_sy),
      Handler.new([:scalar_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_sd_rmn_sy),
      Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :separator_at?, 'time?'], :handle_sy_sm_sd),
      Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_year], :handle_sm_sy)
    ],
    # tonight at 7pm
    :anchor => [
      Handler.new([:grabber?, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
      Handler.new([:grabber?, :repeater, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
      Handler.new([:repeater, :grabber, :repeater], :handle_r_g_r)
    ],
    # 3 weeks from now, in 2 months
    :arrow => [
      Handler.new([:scalar, :repeater, :pointer], :handle_s_r_p),
      Handler.new([:pointer, :scalar, :repeater], :handle_p_s_r),
      Handler.new([:scalar, :repeater, :pointer, 'anchor'], :handle_s_r_p_a)
    ],
    # 3rd week in march
    :narrow => [
      Handler.new([:ordinal, :repeater, :separator_in, :repeater], :handle_o_r_s_r),
      Handler.new([:ordinal, :repeater, :grabber, :repeater], :handle_o_r_g_r)
    ]
  }
  endians = [
    Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_day, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sm_sd_sy),
    Handler.new([:scalar_day, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sd_sm_sy)
  ]
  case endian = Array(options[:endian_precedence]).first
  when :little
    @definitions[:endian] = endians.reverse
  when :middle
    @definitions[:endian] = endians
  else
    raise ArgumentError, "Unknown endian option '#{endian}'"
  end
  @definitions
end

def guess(span)

Returns:
  • (Time) -

Parameters:
  • span (Span) --
def guess(span)
  if span.width > 1
    span.begin + (span.width / 2)
  else
    span.begin
  end
end

def numericize_numbers(text)

Returns:
  • (String) - A new string with words converted to numbers

Parameters:
  • text (String) -- The string to convert

Other tags:
    See: Numerizer.numerize -
def numericize_numbers(text)
  warn "Chronic.numericize_numbers will be deprecated in version 0.7.0. Please use Chronic::Numerizer.numerize instead"
  Numerizer.numerize(text)
end

def parse(text, opts={})

Returns:
  • (Time, Chronic::Span, nil) -

Options Hash: (**opts)
  • :ambiguous_year_future_bias (Integer) --
  • :endian_precedence (Array) --
  • :ambiguous_time_range (Integer) --
  • :guess (Boolean) --
  • :now (Object) --
  • :context (Symbol) --

Parameters:
  • text (String) -- The text to parse
def parse(text, opts={})
  options = DEFAULT_OPTIONS.merge opts
  # ensure the specified options are valid
  (opts.keys - DEFAULT_OPTIONS.keys).each do |key|
    raise ArgumentError, "#{key} is not a valid option key."
  end
  unless [:past, :future, :none].include?(options[:context])
    raise ArgumentError, "Invalid context, :past/:future only"
  end
  options[:text] = text
  Chronic.now = options[:now] || Chronic.time_class.now
  # tokenize words
  tokens = tokenize(text, options)
  if Chronic.debug
    puts "+#{'-' * 51}\n| #{tokens}\n+#{'-' * 51}"
  end
  span = tokens_to_span(tokens, options)
  if span
    options[:guess] ? guess(span) : span
  end
end

def pre_normalize(text)

Returns:
  • (String) - A new string ready for Chronic to parse

Parameters:
  • text (String) -- The string to normalize
def pre_normalize(text)
  text = text.to_s.downcase
  text.gsub!(/['"\.]/, '')
  text.gsub!(/,/, ' ')
  text.gsub!(/\bsecond (of|day|month|hour|minute|second)\b/, '2nd \1')
  text = Numerizer.numerize(text)
  text.gsub!(/ \-(\d{4})\b/, ' tzminus\1')
  text.gsub!(/([\/\-\,\@])/) { ' ' + $1 + ' ' }
  text.gsub!(/\b0(\d+:\d+\s*pm?\b)/, '\1')
  text.gsub!(/\btoday\b/, 'this day')
  text.gsub!(/\btomm?orr?ow\b/, 'next day')
  text.gsub!(/\byesterday\b/, 'last day')
  text.gsub!(/\bnoon\b/, '12:00')
  text.gsub!(/\bmidnight\b/, '24:00')
  text.gsub!(/\bnow\b/, 'this second')
  text.gsub!(/\b(?:ago|before(?: now)?)\b/, 'past')
  text.gsub!(/\bthis (?:last|past)\b/, 'last')
  text.gsub!(/\b(?:in|during) the (morning)\b/, '\1')
  text.gsub!(/\b(?:in the|during the|at) (afternoon|evening|night)\b/, '\1')
  text.gsub!(/\btonight\b/, 'this night')
  text.gsub!(/\b\d+:?\d*[ap]\b/,'\0m')
  text.gsub!(/(\d)([ap]m|oclock)\b/, '\1 \2')
  text.gsub!(/\b(hence|after|from)\b/, 'future')
  text
end

def tokenize(text, options)

def tokenize(text, options)
  text = pre_normalize(text)
  tokens = text.split(' ').map { |word| Token.new(word) }
  [Repeater, Grabber, Pointer, Scalar, Ordinal, Separator, TimeZone].each do |tok|
    tok.scan(tokens, options)
  end
  tokens.select { |token| token.tagged? }
end

def tokens_to_span(tokens, options)

def tokens_to_span(tokens, options)
  definitions = definitions(options)
  definitions.each do |type, handlers|
    handlers.each do |handler|
      next unless handler.match(tokens, definitions)
      good_tokens = case type
      when :date, :endian, :anchor
        tokens.reject { |o| o.get_tag Separator }
      when :arrow
        tokens.reject { |o| o.get_tag(SeparatorAt) || o.get_tag(SeparatorSlashOrDash) || o.get_tag(SeparatorComma) }
      else
        tokens
      end
      if handler.handler_method
        return handler.invoke(type, good_tokens, options)
      end
    end
  end
  puts "-none" if Chronic.debug
  return nil
end