Skip to content

Commit

Permalink
capture zone offset value in formats to possible usage
Browse files Browse the repository at this point in the history
  • Loading branch information
adzap committed Mar 31, 2009
1 parent d89266d commit 1e3c802
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 12 deletions.
27 changes: 15 additions & 12 deletions lib/validates_timeliness/formats.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,13 @@ class Formats
{ 's' => [ /s{1}/, '(\d{1,2})', :sec ] },
{ 'u' => [ /u{1,}/, '(\d{1,6})', :usec ] },
{ 'ampm' => [ /ampm/, '((?:[aApP])\.?[mM]\.?)', :meridian ] },
{ 'zo' => [ /zo/, '(?:[+-]\d{2}:?\d{2})'] },
{ 'zo' => [ /zo/, '([+-]\d{2}:?\d{2})', :offset ] },
{ 'tz' => [ /tz/, '(?:[A-Z]{1,4})' ] },
{ '_' => [ /_/, '\s?' ] }
]

# Arguments whichs will be passed to the format proc if matched in the
# time string. The key must should the key from the format tokens. The array
# Arguments which will be passed to the format proc if matched in the
# time string. The key must be the key from the format tokens. The array
# consists of the arry position of the arg, the arg name, and the code to
# place in the time array slot. The position can be nil which means the arg
# won't be placed in the array.
Expand All @@ -146,6 +146,7 @@ class Formats
:min => [4, 'n', 'n'],
:sec => [5, 's', 's'],
:usec => [6, 'u', 'microseconds(u)'],
:offset => [7, 'z', 'offset_in_seconds(z)'],
:meridian => [nil, 'md', nil]
}

Expand Down Expand Up @@ -175,7 +176,8 @@ def parse(string, type, options={})
end
matches = full.match(string.strip)
end
processor.call(*matches[1..7]) if matches
last = options[:include_offset] ? 8 : 7
processor.call(*matches[1..last]) if matches
end

# Delete formats of specified type. Error raised if format not found.
Expand Down Expand Up @@ -207,8 +209,7 @@ def add_formats(type, *add_formats)
end
compile_format_expressions
end



# Removes formats where the 1 or 2 digit month comes first, to eliminate
# formats which are ambiguous with the European style of day then month.
# The mmm token is ignored as its not ambigous.
Expand Down Expand Up @@ -247,17 +248,12 @@ def format_expression_generator(string_format)
# argument in the position indicated by the first element of the proc arg
# array.
#
# Examples:
#
# 'yyyy-mm-dd hh:nn' => lambda {|y,m,d,h,n| md||=0; [unambiguous_year(y),month_index(m),d,full_hour(h,md),n,nil,nil].map {|i| i.to_i } }
# 'dd/mm/yyyy h:nn_ampm' => lambda {|d,m,y,h,n,md| md||=0; [unambiguous_year(y),month_index(m),d,full_hour(h,md),n,nil,nil].map {|i| i.to_i } }
#
def format_proc(order)
arg_map = format_proc_args
args = order.invert.sort.map {|p| arg_map[p[1]][1] }
arr = [nil] * 7
order.keys.each {|k| i = arg_map[k][0]; arr[i] = arg_map[k][2] unless i.nil? }
proc_string = "lambda {|#{args.join(',')}| md||=nil; [#{arr.map {|i| i.nil? ? 'nil' : i }.join(',')}].map {|i| i.to_i } }"
proc_string = "lambda {|#{args.join(',')}| md||=nil; [#{arr.map {|i| i.nil? ? 'nil' : i }.join(',')}].map {|i| i.is_a?(Float) ? i : i.to_i } }"
eval proc_string
end

Expand Down Expand Up @@ -314,6 +310,13 @@ def abbr_month_names
def microseconds(usec)
(".#{usec}".to_f * 1_000_000).to_i
end

def offset_in_seconds(offset)
sign = offset =~ /^-/ ? -1 : 1
parts = offset.scan(/\d\d/).map {|p| p.to_f }
parts[1] = parts[1].to_f / 60
(parts[0] + parts[1]) * sign * 3600
end
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions spec/formats_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
it "should generate proc which outputs time array with microseconds" do
generate_proc('hh:nn:ss.u').call('01', '02', '03', '99').should == [0,0,0,1,2,3,990000]
end

it "should generate proc which outputs datetime array with zone offset" do
generate_proc('yyyy-mm-dd hh:nn:ss.u zo').call('2001', '02', '03', '04', '05', '06', '99', '+10:00').should == [2001,2,3,4,5,6,990000,36000]
end
end

describe "validation regexps" do
Expand Down Expand Up @@ -132,6 +136,11 @@
time_array = formats.parse('2000-02-01 12:13', :time, :strict => false)
time_array.should == [0,0,0,12,13,0,0]
end

it "should return zone offset when :include_offset options is true" do
time_array = formats.parse('2000-02-01T12:13:14-10:30', :datetime, :include_offset => true)
time_array.should == [2000,2,1,12,13,14,0,-37800]
end
end

describe "removing formats" do
Expand Down

0 comments on commit 1e3c802

Please sign in to comment.