Skip to content
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@ next_time = cron_parser.next(Time.now)

# Last occurrence
most_recent_time = cron_parser.last(Time.now)

# With Timezone

cron_parser = CronParser.new('30 * * * * +08:00')

```

20 changes: 14 additions & 6 deletions lib/cron_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ class CronParser
# internal "mutable" time representation
class InternalTime
attr_accessor :year, :month, :day, :hour, :min
attr_accessor :time_source
attr_accessor :time_source, :offset

def initialize(time,time_source = Time)
def initialize(time, time_source = Time)
@year = time.year
@month = time.month
@day = time.day
Expand All @@ -20,7 +20,11 @@ def initialize(time,time_source = Time)
end

def to_time
time_source.local(@year, @month, @day, @hour, @min, 0)
if @offset
time_source.new(@year, @month, @day, @hour, @min, 0, @offset)
else
time_source.local(@year, @month, @day, @hour, @min, 0)
end
end

def inspect
Expand Down Expand Up @@ -50,10 +54,11 @@ def inspect
"fri" => "5",
"sat" => "6"
}

def initialize(source,time_source = Time)
attr_accessor :offset
def initialize(source,time_source = Time, offset = nil)
@source = interpret_vixieisms(source)
@time_source = time_source
@offset = offset
validate_source
end

Expand All @@ -80,6 +85,7 @@ def interpret_vixieisms(spec)
# returns the next occurence after the given date
def next(now = @time_source.now, num = 1)
t = InternalTime.new(now, @time_source)
t.offset = time_specs[:offset]

unless time_specs[:month][0].include?(t.month)
nudge_month(t)
Expand Down Expand Up @@ -109,6 +115,7 @@ def next(now = @time_source.now, num = 1)
# returns the last occurence before the given date
def last(now = @time_source.now, num=1)
t = InternalTime.new(now,@time_source)
t.offset = time_specs[:offset]

unless time_specs[:month][0].include?(t.month)
nudge_month(t, :last)
Expand Down Expand Up @@ -253,7 +260,8 @@ def time_specs
:hour => parse_element(tokens[1], 0..23), #hour
:dom => parse_element(tokens[2], 1..31), #DOM
:month => parse_element(tokens[3], 1..12), #mon
:dow => parse_element(tokens[4], 0..6) #DOW
:dow => parse_element(tokens[4], 0..6), #DOW
:offset => (tokens.length == 6) ? tokens[5] : nil, #timezone offset
}
end
end
Expand Down
24 changes: 24 additions & 0 deletions spec/cron_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ def parse_date(str)
Time.local(dt.year, dt.month, dt.day, dt.hour, dt.min, 0)
end

def parse_date_with_tz(str)
dt = DateTime.strptime(str, "%Y-%m-%d %H:%M %z")
Time.new(dt.year, dt.month, dt.day, dt.hour, dt.min, 0, dt.zone)
end

describe "CronParser#parse_element" do
[
["*", 0..59, (0..59).to_a],
Expand Down Expand Up @@ -169,6 +174,25 @@ def parse_date(str)
end
end

describe "With timezone" do
describe "#time_spec" do
it "returns the correct breakdown" do
parser = CronParser.new('0 17 * * * -08:00')
expect(parser.send(:time_specs)[:offset]).to eq("-08:00")
end
end

it "Should return in the specified timezone with the correct computed day" do
now = parse_date_with_tz('2017-12-14 17:15 -08:00')
expected_last = parse_date_with_tz('2017-12-14 17:00 -08:00')
expected_next = parse_date_with_tz('2017-12-15 17:00 -08:00')

parser = CronParser.new('0 17 * * * -08:00')
parser.next(now).should == expected_next
parser.last(now).should == expected_last
end
end

describe "CronParser#new" do
it 'should not raise error when given a valid cronline' do
expect { CronParser.new('30 * * * *') }.not_to raise_error
Expand Down