Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix zone offset parsing #40

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions lib/barometer/data/zone.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,27 @@ def utc_to_local(utc_time)
end

class ZoneOffset
NUMERIC_OFFSET = /(?:^| )([-+]?[01]?\d)(\d\d)?$/

def self.detect?(zone)
zone.respond_to?(:match) && zone.match(NUMERIC_OFFSET) { |m| zone = m[1].to_i }
zone.respond_to?(:abs) && zone.abs <= 14
end

def initialize(zone, time_class=::Time)
@zone = zone
@offset = case zone
when Integer
zone * 60 * 60
when NUMERIC_OFFSET
h = $1.to_i * 60 * 60
m = $2.to_i * 60
h < 0 ? h - m : h + m
end
@time_class = time_class
end

def code
end

def offset
zone.to_f * 60 * 60
end
attr_reader :code, :offset

def now
time_class.now.utc + offset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def initialize(payload)
end

def parse
current.observed_at = observed_at, '%B %e, %l:%M %p %Z'
current.observed_at = observed_at
current.stale_at = stale_at
current.humidity = humidity
current.condition = condition
Expand Down
39 changes: 37 additions & 2 deletions spec/data/zone_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,42 @@ def stub_time(utc_now)
expect( ZoneOffset.detect?('PST') ).to be false
end

it 'returns true when given an offset' do
it 'returns true when given a numeric offset' do
expect( ZoneOffset.detect?(10) ).to be true
end

it 'returns true when given a one-digit hour offset' do
expect( ZoneOffset.detect?('1') ).to be true
expect( ZoneOffset.detect?('+1') ).to be true
expect( ZoneOffset.detect?('-1') ).to be true
end

it 'returns true when given a two-digit hour offset' do
expect( ZoneOffset.detect?('09') ).to be true
expect( ZoneOffset.detect?('+09') ).to be true
expect( ZoneOffset.detect?('-09') ).to be true
end

it 'returns true when given a four-digit offset' do
expect( ZoneOffset.detect?('0100') ).to be true
expect( ZoneOffset.detect?('+0100') ).to be true
expect( ZoneOffset.detect?('-1200') ).to be true
end

it 'returns true when preceded by a space' do
expect( ZoneOffset.detect?('August 9, 6:56 AM -10') ).to be true
end

it 'returns false when only given a year' do
expect( ZoneOffset.detect?('August 9, 6:56 AM 2017') ).to be false
end

it 'returns false when part of a date' do
expect( ZoneOffset.detect?('2017-10-10') ).to be false
end

it 'returns false when given an offset out of range' do
expect( ZoneOffset.detect?(15) ).to be false
expect( ZoneOffset.detect?('15') ).to be false
end

it 'returns false when given nothing' do
Expand All @@ -178,6 +208,11 @@ def stub_time(utc_now)
it 'converts the input from hours to seconds' do
expect( ZoneOffset.new(5).offset ).to eq(5 * 60 * 60)
end

it 'converts 4-digit input from HHMM to seconds' do
expect( ZoneOffset.new('+0130').offset ).to eq(90 * 60)
expect( ZoneOffset.new('-0130').offset ).to eq(-90 * 60)
end
end

describe '#now' do
Expand Down
17 changes: 16 additions & 1 deletion spec/utils/time_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,21 @@ module Barometer
assert_times_are_equal(time, start_of_local_day)
end

it "parses a String (with no format), assumes UTC" do
it "parses a String with year (with no format), assumes UTC" do
t = "March 15, 10:36 AM 2013"

time = Utils::Time.parse(t)
assert_times_are_equal(time, ::Time.utc(2013, 3, 15, 10, 36, 0))
end

it "parses a String without year (with no format), assumes UTC" do
t = "August 17, 1:16 AM"

time = Utils::Time.parse(t)
current_year = Time.now.year
assert_times_are_equal(time, ::Time.utc(current_year, 8, 17, 1, 16, 0))
end

it "parses a String (with optional format), assumes UTC" do
format = "%B %e, %l:%M %p %Y"
t = "March 15, 10:36 AM 2013"
Expand All @@ -58,6 +66,13 @@ module Barometer
assert_times_are_equal(time, ::Time.utc(2013, 3, 15, 18, 36, 0))
end

it "parses a timezoned String (with no format)" do
t = "March 15, 10:36 AM -0800 2013"

time = Utils::Time.parse(t)
assert_times_are_equal(time, ::Time.utc(2013, 3, 15, 18, 36, 0))
end

it "accepts an array of values, creating a UTC time" do
time = Utils::Time.parse(2013, 3, 15, 18, 36, 0)
assert_times_are_equal(time, ::Time.utc(2013, 3, 15, 18, 36, 0))
Expand Down