fugit parses the time expressions a scheduler needs
time tools (cron, parsing, durations, ...) for Ruby, rufus-scheduler, and flor
At a glance
- What is it?
- fugit is a Ruby library that turns a string into a time object, whether that string is a cron expression, a natural phrase like every day at noon, a duration such as 12y12M, or a point in time. It is a core dependency of rufus-scheduler and the foundation of the time scheduling in the flor workflow engine.
- Who is it for?
- Adopt fugit when you accept a schedule from a user, a configuration file or a database and need it in a form you can compute occurrences from, especially if the input may be either a cron expression or a phrase. Do not adopt it to parse a fixed cron string you wrote yourself, where the standard library and a fixed schedule are enough.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 39 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What it parses, and for whom
fugit is described as time tools for flor and the floraison group, and it is built from two other projects of the same author. It uses et-orbi to represent time instances and raabro as a basis for its parsers, so the parsing side comes from a general purpose string parsing library and the time representation comes from a dedicated one.
The parsing targets are three kinds of thing. A cron expression, which is the classic five field form. A natural language expression, which the README calls a natural expression and which the example shows as `every day at noon`. And a duration or a point in time, with the examples `12y12M` and `2017-12-12`.
The relationship to the rest of the ecosystem is stated in the README's related projects section, and it explains the design. There are two sister projects. rufus-scheduler is a cron, at, in, every and interval in-process scheduler, and it is described as the father project to fugit. flor is a Ruby workflow engine, and fugit provides the foundation for its time scheduling capabilities.
So fugit exists because both of those need to turn human input into schedulable time objects, and neither of them wants to own that parser. fugit is also a core dependency of rufus-scheduler from version 3.5 onwards, which is a useful fact for anyone weighing it, because it means the library is already in the dependency tree of one of the most used Ruby schedulers.
The project is Ruby, MIT licensed, with no published GitHub releases and the last push on 2026-09-14.
One parse method, and the nil contract
The simplest way to use fugit is `Fugit.parse(s)`, and the shape of it is that one entry point returns whichever type fits the string:
require 'fugit'
Fugit.parse('0 0 1 jan *').class # ==> ::Fugit::Cron
Fugit.parse('12y12M').class # ==> ::Fugit::Duration
Fugit.parse('2017-12-12').class # ==> ::EtOrbi::EoTime
Fugit.parse('2017-12-12 UTC').class # ==> ::EtOrbi::EoTime
Fugit.parse('every day at noon').class # ==> ::Fugit::CronThe contract on failure is explicit. If fugit cannot extract a cron, duration or point in time out of the string, it will return nil.
So `Fugit.parse` is the tolerant entry point and there is a strict one. `Fugit.do_parse(s)` is equivalent, but instead of returning nil it raises an error if the given string contains no time information, and the README shows the resulting `ArgumentError` with the message `found no time information in "nada"`.
That pair is the pattern to take away, because it runs through the whole API. Each of the `parse_` methods has a `do_parse_` partner, and the difference is the same one: return nil or fail.
The typed methods are the ones to use when you know what you expect:
require 'fugit'
Fugit.parse_cron('0 0 1 jan *').class # ==> ::Fugit::Cron
Fugit.parse_duration('12y12M').class # ==> ::Fugit::Duration
Fugit.parse_at('2017-12-12').class # ==> ::EtOrbi::EoTime
Fugit.parse_at('2017-12-12 UTC').class # ==> ::EtOrbi::EoTime
Fugit.parse_nat('every day at noon').class # ==> ::Fugit::Cron`parse_cron`, `parse_duration`, `parse_at` and `parse_nat` each insist on one type, so a phrase is not silently accepted where a cron was expected.
Cronish: take a cron out of a larger string
The `parse_cronish` methods solve a different problem, and they are the ones most often overlooked.
Sometimes you know a cron expression or an every natural expression will come in and you want to discard the rest:
require 'fugit'
Fugit.parse_cronish('0 0 1 jan *').class # ==> ::Fugit::Cron
Fugit.parse_cronish('every saturday at noon').class # ==> ::Fugit::Cron
Fugit.parse_cronish('12y12M') # ==> nilSo `parse_cronish` returns a `Fugit::Cron` instance or else nil, and `do_parse_cronish` returns a `Fugit::Cron` instance or else fails with an `ArgumentError`.
The difference from `parse` is what it tolerates. `parse` wants the whole string to be a time expression, and `parse_cronish` is happy to find a cron inside a longer piece of text, which is what you want when the input is something like a chat message or a configuration line with a comment on it.
Note the last line of the example: a duration is not cronish, so `parse_cronish('12y12M')` returns nil. The method is specific to cron-like content, cron and natural expressions both.
This pair was introduced in fugit 1.8.0, which is worth knowing if you are pinning a version, since on an older release the method simply does not exist.
Computing occurrences with Fugit::Cron
The Cron class is where the parsing turns into scheduling. It parses cron strings and then `#next_time` and `#previous_time` compute the next or the previous occurrence respectively.
require 'fugit'
c = Fugit::Cron.parse('0 0 * * sun')
# or
c = Fugit::Cron.new('0 0 * * sun')
p Time.now # => 2017-01-03 09:53:27 +0900
p c.next_time.to_s # => 2017-01-08 00:00:00 +0900
p c.previous_time.to_s # => 2017-01-01 00:00:00 +0900
p c.next_time(Time.parse('2024-06-01')).to_s
# => "2024-06-02 00:00:00 +0900"
p c.previous_time(Time.parse('2024-06-01')).to_s
# => "2024-05-26 00:00:00 +0900"Both `next_time` and `previous_time` accept a start time, so you can ask for the occurrence after a given moment rather than after now. Both of them return times with a zone offset attached, which comes from the et-orbi representation.
There is also a `#brute_frequency` method which returns an array of shortest delta, longest delta and occurrence count, where delta is the time between two occurrences. That is the answer to the question a scheduler needs before it commits to a job, since a schedule whose shortest interval is one minute and whose longest is a year is a different commitment from one that fires every hour.
The later additions go further. `#next` and `#prev` return Enumerable instances, available since fugit 1.10.0, so you can ask for the next three occurrences of a cron and get an array of strings, and `#within` accepts a time range and returns an array of Eo::EoTime instances that correspond to the occurrences of the cron within that range, also available since fugit 1.10.0.
The cron syntax the class accepts is the extended kind, since the example in the README uses `0 12 * * mon#2`, the second Monday of the month form, which the parser supports.
The Ruby scheduling ecosystem around it
The README lists similar projects, and the list is a good map of the problem space, because each one covers a slice of it.
chronic is a pure Ruby natural language date parser, parse-cron parses cron expressions and calculates the next occurrence after a given date, ice_cube is a Ruby date recurrence library, ISO8601 is a Ruby parser for ISO8601 dateTimes and durations, chrono is a chain of logics about chronology, CronCalc calculates cron job occurrences, Recurrence is a simple library to handle recurring events, and CronConfigParser parses the cron configuration for readability.
So the difference between fugit and those is scope and lineage. fugit is the one written for the scheduler world, with the natural expression syntax that a user can type, and it is the one that rufus-scheduler and flor both build on.
The projects using fugit list is more telling. arask uses fugit to parse cron strings. sidekiq-cron has used fugit to parse cron strings since version 1.0.0, having used rufus-scheduler previously. que-scheduler is a job scheduler for que, and serial_scheduler is a Ruby task scheduler without threading. delayed_cron_job is an extension to Delayed::Job that lets you set cron expressions. GoodJob is a multithreaded Postgres based Active Job backend, Solid Queue is the database based queuing backend for Active Job, and qron is, in the README's words, a stupid cron thread that wakes up from time to time to do what is in its crontab.
That list spans both of the big Rails job backends, which tells you the parsing is stable enough to sit under a lot of scheduling code. And it tells you the library is used as a component, not as an application, so there is no scheduler here, only the time understanding that a scheduler needs.
The repository, the tests and the gem tasks
The repository layout is compact: `lib/` for the code, `test/` and `tst/` for the tests, `doc/` for the documentation, plus `CHANGELOG.md`, `CREDITS.md`, `invalid_crons.md`, `fugit.gemspec`, a `Makefile`, a `Gemfile`, an `.rspec` file and a `.vimshorts` file.
The `invalid_crons.md` file is a small but telling artefact. It is a document of cron expressions that are invalid, which is the kind of reference a parser project accumulates when users keep hitting the same edge cases, and it is useful precisely because the parser is strict about what it accepts.
The Makefile shows how the gem is developed, and it is written for a maintainer rather than for a user. The name and version are computed by evaluating the gemspec:
NAME != \
ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.name"
VERSION != \
ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.version"The `!=` assignment operator in make evaluates a shell command once and caches the result, so the version is read from the gemspec rather than duplicated in the Makefile, which is the right way to keep a single source of truth.
The targets follow. `count_lines` counts non-comment lines in `lib` and in the spec files, with `cl` as an alias, which is how the author keeps an eye on the size of the library. `scan` runs the Ruby scanner over the sources, `cw` runs `ruby -cw` over every file for warnings, and `gemspec_validate` checks the gemspec and prints the name and version. `build` depends on that validation, builds the gem and moves the package into a `pkg/` directory, and `push` builds and then pushes with an OTP. `console` opens an IRB session with the library loaded, and `test` runs the suite through `bundle exec proba`, with `spec` and `t` as aliases.
The test runner name is worth noticing, since it is not rspec even though there is an `.rspec` file in the repository.
Editorial conclusion
Adopt fugit when you accept a schedule from a user, a configuration file or a database and need it in a form you can compute occurrences from, especially if the input may be either a cron expression or a phrase. Do not adopt it to parse a fixed cron string you wrote yourself, where the standard library and a fixed schedule are enough. Verify first which parse method you want, since `Fugit.parse` returns nil for unrecognised input while `Fugit.do_parse` raises, that the version you take has the methods you need, since `parse_cronish` arrived in 1.8.0 and the enumerable `#next` and `#prev` and `#within` methods in 1.10.0, and that you are comfortable with the library's date handling, which produces `EtOrbi::EoTime` instances rather than plain `Time` objects.
Frequently asked questions
What is the fugit Ruby library?
It is a set of time tools for flor and the floraison group that parses cron expressions, natural language expressions such as every day at noon, durations and points in time into time objects. It uses et-orbi for the time representation and raabro as the basis for its parsers, and it is a core dependency of rufus-scheduler from version 3.5.
What is the difference between Fugit.parse and Fugit.do_parse?
Fugit.parse returns nil when the string contains no time information, while Fugit.do_parse raises an ArgumentError instead, with the message that no time information was found. Each of the typed parse methods, such as parse_cron and parse_at, has a do_parse_ partner with the same difference.
How do I find a cron expression inside a longer string?
Use Fugit.parse_cronish, which returns a Fugit::Cron instance or nil, and Fugit.do_parse_cronish, which returns the instance or fails with an ArgumentError. It accepts both cron expressions and natural expressions, and it was introduced in fugit 1.8.0.
How do I compute the next or previous occurrence of a cron?
Fugit::Cron provides #next_time and #previous_time, both of which accept an optional start time, plus #brute_frequency for the shortest and longest intervals and the occurrence count, and #next, #prev and #within for enumerations, the last three available since fugit 1.10.0.
Which projects use fugit?
The README lists arask, sidekiq-cron, que-scheduler, serial_scheduler, delayed_cron_job, GoodJob, Solid Queue and qron, alongside its two sister projects, rufus-scheduler, the in-process scheduler it was extracted for, and flor, the workflow engine that uses it for its cron procedure.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/floraison-fugit)Was this useful?