lib/timeliness/parser.rb in timeliness-0.2.0 vs lib/timeliness/parser.rb in timeliness-0.3.0

- old
+ new

@@ -5,55 +5,64 @@ class << self def parse(value, *args) return value unless value.is_a?(String) - options = args.last.is_a?(Hash) ? args.pop : {} - type = args.first + type, options = type_and_options_from_args(args) time_array = _parse(value, type, options) return nil if time_array.nil? - override_values_by_type(time_array, type, options) unless type == :datetime - make_time(time_array[0..6], options[:zone]) + default_values_by_type(time_array, type, options) unless type == :datetime + + make_time(time_array[0..7], options[:zone]) rescue NoMethodError => ex raise ex unless ex.message =~ /zone/ raise MissingTimezoneSupport, "ActiveSupport must be loaded to use timezones other than :utc and :local." end - def make_time(time_array, zone=nil) + def make_time(time_array, zone_option=nil) return nil unless fast_date_valid_with_fallback(*time_array[0..2]) - zone ||= Timeliness.default_timezone - case zone - when :utc, :local - time_with_datetime_fallback(zone, *time_array.compact) - when :current - Time.zone.local(*time_array) - else - Time.use_zone(zone) { Time.zone.local(*time_array) } - end + zone_or_offset = time_array.delete_at(7) + zone, offset = zone_and_offset(zone_or_offset) if zone_or_offset + + value = create_time_in_zone(time_array, zone || zone_option) + value = time_in_zone(value, zone_option) if zone + + offset ? value + (value.utc_offset - offset) : value rescue ArgumentError, TypeError nil end def _parse(string, type=nil, options={}) if options[:strict] && type - set = Formats.send("#{type}_format_set") + set = Definitions.send("#{type}_format_set") set.match(string, options[:format]) else values = nil - Formats.format_set(type, string).find {|set| values = set.match(string, options[:format]) } + Definitions.format_sets(type, string).find {|set| values = set.match(string, options[:format]) } values end rescue nil end private - def override_values_by_type(values, type, options) + def type_and_options_from_args(args) + options = args.last.is_a?(Hash) ? args.pop : {} + type_or_now = args.first + if type_or_now.is_a?(Symbol) + type = type_or_now + elsif !type_or_now.is_a?(Hash) + options[:now] = type_or_now + end + return type, options + end + + def default_values_by_type(values, type, options) case type when :date values[3..7] = nil when :time values[0..2] = current_date(options) @@ -83,9 +92,42 @@ when :current Time.current else Time.use_zone(zone) { Time.current } end + end + + def time_in_zone(time, zone=nil) + zone ||= Timeliness.default_timezone + case zone + when :utc, :local + time.send("get#{zone}") + when :current + time.in_time_zone + else + Time.use_zone(zone) { time.in_time_zone } + end + end + + def create_time_in_zone(time_array, zone=nil) + zone ||= Timeliness.default_timezone + case zone + when :utc, :local + time_with_datetime_fallback(zone, *time_array.compact) + when :current + Time.zone.local(*time_array) + else + Time.use_zone(zone) { Time.zone.local(*time_array) } + end + end + + def zone_and_offset(parsed_value) + if parsed_value.is_a?(String) + zone = Definitions.timezone_mapping[parsed_value] || parsed_value + else + offset = parsed_value + end + return zone, offset end # Taken from ActiveSupport and simplified def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0) return nil if hour > 23 || min > 59 || sec > 59