Cron expression parser for calculating next and previous occurrences
gem install philiprehberger-cron_parserCron expression parser for calculating next and previous occurrences
Add to your Gemfile:
gem "philiprehberger-cron_parser"
Or install directly:
gem install philiprehberger-cron_parser
require "philiprehberger/cron_parser"
cron = Philiprehberger::CronParser.new('0 9 * * 1-5')
cron.next(from: Time.now) # => next weekday at 9:00 AM
cron.prev(from: Time.now) # => previous weekday at 9:00 AM
cron = Philiprehberger::CronParser.new('*/15 * * * *')
cron.next_n(5, from: Time.now) # => next 5 quarter-hour times
cron = Philiprehberger::CronParser.new('0 9 * * *')
cron.matches?(Time.new(2026, 3, 22, 9, 0, 0)) # => true
cron.matches?(Time.new(2026, 3, 22, 10, 0, 0)) # => false
cron = Philiprehberger::CronParser.new('*/15 * * * *')
from = Time.new(2026, 4, 30, 9, 0, 0)
to = Time.new(2026, 4, 30, 10, 0, 0)
cron.count_in(from: from, to: to) # => 5
cron = Philiprehberger::CronParser.new('*/15 * * * *')
from = Time.new(2026, 4, 30, 9, 0, 0)
to = Time.new(2026, 4, 30, 10, 0, 0)
cron.each_in(from: from, to: to) { |t| puts t }
# Without a block, returns an Enumerator
cron.each_in(from: from, to: to).first(2)
# => [2026-04-30 09:00:00, 2026-04-30 09:15:00]
cron = Philiprehberger::CronParser.new('30 9 * * 1-5')
cron.human_readable # => "at minute 30, at hour 9, on weekday 1,2,3,4,5"
Use named months (JAN-DEC) and weekdays (SUN-SAT) in cron expressions. Names are case-insensitive and work in ranges and lists.
Philiprehberger::CronParser.new('0 0 1 JAN *') # first of January
Philiprehberger::CronParser.new('0 0 1 JAN-MAR *') # first of Jan-Mar
Philiprehberger::CronParser.new('0 0 * * MON') # every Monday
Philiprehberger::CronParser.new('0 0 * * MON-FRI') # weekdays
Philiprehberger::CronParser.new('0 0 * * MON,WED,FRI') # specific days
Philiprehberger::CronParser.new('0 0 * * 1,WED,5') # mixed numeric and named
Standard crontab aliases are supported (case-insensitive):
Philiprehberger::CronParser.new('@hourly') # => 0 * * * *
Philiprehberger::CronParser.new('@daily') # => 0 0 * * *
Philiprehberger::CronParser.new('@midnight') # alias for @daily
Philiprehberger::CronParser.new('@weekly') # => 0 0 * * 0
Philiprehberger::CronParser.new('@monthly') # => 0 0 1 * *
Philiprehberger::CronParser.new('@yearly') # => 0 0 1 1 *
Philiprehberger::CronParser.new('@annually') # alias for @yearly
Philiprehberger::CronParser.valid?('*/5 * * * *') # => true
Philiprehberger::CronParser.valid?('60 * * * *') # => false
result = Philiprehberger::CronParser.validate('60 25 * * *')
result[:valid] # => false
result[:errors] # => ["minute field: Value 60 out of range (0-59)", "hour field: Value 25 out of range (0-23)"]
Standard 5-field cron expressions (minute hour day month weekday):
Philiprehberger::CronParser.new('* * * * *') # every minute
Philiprehberger::CronParser.new('*/5 * * * *') # every 5 minutes
Philiprehberger::CronParser.new('0 9-17 * * *') # hourly 9am-5pm
Philiprehberger::CronParser.new('0 9,12,17 * * *') # specific hours
Philiprehberger::CronParser.new('0 0 1 * *') # first of month
Philiprehberger::CronParser.new('0 0 1 JAN-MAR *') # named months
Philiprehberger::CronParser.new('0 9 * * MON-FRI') # named weekdays
| Method | Description |
|---|---|
CronParser.new(expr) | Parse a 5-field cron expression |
CronParser.valid?(expr) | Check if expression is valid (returns boolean) |
CronParser.validate(expr) | Validate with structured field-level errors |
Expression#next(from:) | Calculate the next matching time |
Expression#prev(from:) | Calculate the previous matching time |
Expression#next_n(n, from:) | Calculate the next N matching times |
Expression#count_in(from:, to:) | Count occurrences within an inclusive [from, to] window |
Expression#each_in(from:, to:, &block) | Yield each matching occurrence in [from, to]; returns an Enumerator without a block |
Expression#matches?(time) | Check if a time matches the expression |
Expression#human_readable | Human-readable description of the expression |
Expression#description | Alias for human_readable |
bundle install
bundle exec rspec
bundle exec rubocop
If you find this project useful: