{"id":13477464,"url":"https://github.com/floraison/fugit","last_synced_at":"2025-04-29T18:57:11.299Z","repository":{"id":38050643,"uuid":"77764339","full_name":"floraison/fugit","owner":"floraison","description":"time tools (cron, parsing, durations, ...) for Ruby, rufus-scheduler, and flor","archived":false,"fork":false,"pushed_at":"2025-04-15T05:34:10.000Z","size":581,"stargazers_count":439,"open_issues_count":4,"forks_count":38,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-27T04:34:26.347Z","etag":null,"topics":["at","cron","every","in","ruby","time"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/floraison.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-01-01T03:21:02.000Z","updated_at":"2025-04-24T10:11:31.000Z","dependencies_parsed_at":"2023-12-19T04:14:41.084Z","dependency_job_id":"49693e4f-5627-4a03-811a-ac036b0b561e","html_url":"https://github.com/floraison/fugit","commit_stats":{"total_commits":649,"total_committers":17,"mean_commits":38.1764705882353,"dds":0.03852080123266566,"last_synced_commit":"141d3399afe64da710b3fa22e251e1c702e2fc51"},"previous_names":[],"tags_count":55,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/floraison%2Ffugit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/floraison%2Ffugit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/floraison%2Ffugit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/floraison%2Ffugit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/floraison","download_url":"https://codeload.github.com/floraison/fugit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251254262,"owners_count":21559791,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["at","cron","every","in","ruby","time"],"created_at":"2024-07-31T16:01:43.167Z","updated_at":"2025-04-29T18:57:11.250Z","avatar_url":"https://github.com/floraison.png","language":"Ruby","readme":"\n# fugit\n\n[![tests](https://github.com/floraison/fugit/workflows/test/badge.svg)](https://github.com/floraison/fugit/actions)\n[![Gem Version](https://badge.fury.io/rb/fugit.svg)](http://badge.fury.io/rb/fugit)\n\nTime tools for [flor](https://github.com/floraison/flor) and the floraison group.\n\nIt uses [et-orbi](https://github.com/floraison/et-orbi) to represent time instances and [raabro](https://github.com/floraison/raabro) as a basis for its parsers.\n\nFugit is a core dependency of [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) \u003e= 3.5.\n\n\n## Related projects\n\n### Sister projects\n\nThe intersection of those two projects is where fugit is born:\n\n* [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) — a cron/at/in/every/interval in-process scheduler, in fact, it's the father project to this fugit project\n* [flor](https://github.com/floraison/flor) — a Ruby workflow engine, fugit provides the foundation for its time scheduling capabilities\n\n### Similar, sometimes overlapping projects\n\n* [chronic](https://github.com/mojombo/chronic) — a pure Ruby natural language date parser\n* [parse-cron](https://github.com/siebertm/parse-cron) — parses cron expressions and calculates the next occurrence after a given date\n* [ice_cube](https://github.com/seejohnrun/ice_cube) — Ruby date recurrence library\n* [ISO8601](https://github.com/arnau/ISO8601) — Ruby parser to work with ISO8601 dateTimes and durations\n* [chrono](https://github.com/r7kamura/chrono) — a chain of logics about chronology\n* [CronCalc](https://github.com/mizinsky/cron_calc) — calculates cron job occurrences\n* [Recurrence](https://github.com/fnando/recurrence) — a simple library to handle recurring events\n* [CronConfigParser](https://github.com/madogiwa0124/cron_config_parser) — parse the cron configuration for readability\n* ...\n\n### Projects using fugit\n\n* [arask](https://github.com/Ebbe/arask) — \"Automatic RAils taSKs\" uses fugit to parse cron strings\n* [sidekiq-cron](https://github.com/ondrejbartas/sidekiq-cron) — uses fugit to parse cron strings since version 1.0.0, it was using rufus-scheduler previously\n* [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) — as seen above\n* [flor](https://github.com/floraison/flor) — used in the [cron](https://github.com/floraison/flor/blob/master/doc/procedures/cron.md) procedure\n* [que-scheduler](https://github.com/hlascelles/que-scheduler) — a reliable job scheduler for [que](https://github.com/chanks/que)\n* [serial_scheduler](https://github.com/grosser/serial_scheduler) — ruby task scheduler without threading\n* [delayed_cron_job](https://github.com/codez/delayed_cron_job) — an extension to Delayed::Job that allows you to set cron expressions for your jobs\n* [GoodJob](https://github.com/bensheldon/good_job) — a multithreaded, Postgres-based, Active Job backend for Ruby on Rails\n* [Solid Queue](https://github.com/rails/solid_queue) — a DB-based queuing backend for Active Job, designed with simplicity and performance in mind\n* [qron](https://github.com/floraison/qron) — stupid cron thread that wakes up from time to time to do what's in its crontab\n* ...\n\n## `Fugit.parse(s)`\n\nThe simplest way to use fugit is via `Fugit.parse(s)`.\n\n```ruby\nrequire 'fugit'\n\nFugit.parse('0 0 1 jan *').class         # ==\u003e ::Fugit::Cron\nFugit.parse('12y12M').class              # ==\u003e ::Fugit::Duration\n\nFugit.parse('2017-12-12').class          # ==\u003e ::EtOrbi::EoTime\nFugit.parse('2017-12-12 UTC').class      # ==\u003e ::EtOrbi::EoTime\n\nFugit.parse('every day at noon').class   # ==\u003e ::Fugit::Cron\n```\n\nIf fugit cannot extract a cron, duration or point in time out of the string, it will return nil.\n```ruby\nFugit.parse('nada')\n  # ==\u003e nil\n```\n\n## `Fugit.do_parse(s)`\n\n`Fugit.do_parse(s)` is equivalent to `Fugit.parse(s)`, but instead of returning nil, it raises an error if the given string contains no time information.\n```ruby\nFugit.do_parse('nada')\n  # ==\u003e /home/jmettraux/w/fugit/lib/fugit/parse.rb:32\n  #     :in `do_parse': found no time information in \"nada\" (ArgumentError)\n```\n\n## parse_cron, parse_in, parse_at, parse_duration, and parse_nat\n\n```ruby\nrequire 'fugit'\n\nFugit.parse_cron('0 0 1 jan *').class       # ==\u003e ::Fugit::Cron\nFugit.parse_duration('12y12M').class        # ==\u003e ::Fugit::Duration\n\nFugit.parse_at('2017-12-12').class          # ==\u003e ::EtOrbi::EoTime\nFugit.parse_at('2017-12-12 UTC').class      # ==\u003e ::EtOrbi::EoTime\n\nFugit.parse_nat('every day at noon').class  # ==\u003e ::Fugit::Cron\n```\n\n## do_parse_cron, do_parse_in, do_parse_at, do_parse_duration, and do_parse_nat\n\nAs `Fugit.parse(s)` returns nil when it doesn't grok its input, and `Fugit.do_parse(s)` fails when it doesn't grok, each of the `parse_` methods has its partner `do_parse_` method.\n\n## parse_cronish and do_parse_cronish\n\nSometimes you know a cron expression or an \"every\" natural expression will come in and you want to discard the rest.\n\n```ruby\nrequire 'fugit'\n\nFugit.parse_cronish('0 0 1 jan *').class             # ==\u003e ::Fugit::Cron\nFugit.parse_cronish('every saturday at noon').class  # ==\u003e ::Fugit::Cron\n\nFugit.parse_cronish('12y12M')        # ==\u003e nil\n```\n\n`.parse_cronish(s)` will return a `Fugit::Cron` instance or else nil.\n\n`.do_parse_cronish(s)` will return a `Fugit::Cron` instance or else fail with an `ArgumentError`.\n\nIntroduced in fugit 1.8.0.\n\n\n## `Fugit::Cron`\n\nA class `Fugit::Cron` to parse cron strings and then `#next_time` and `#previous_time` to compute the next or the previous occurrence respectively.\n\nThere is also a `#brute_frequency` method which returns an array `[ shortest delta, longest delta, occurrence count ]` where delta is the time between two occurrences.\n\n```ruby\nrequire 'fugit'\n\nc = Fugit::Cron.parse('0 0 * *  sun')\n  # or\nc = Fugit::Cron.new('0 0 * *  sun')\n\np Time.now  # =\u003e 2017-01-03 09:53:27 +0900\n\np c.next_time.to_s      # =\u003e 2017-01-08 00:00:00 +0900\np c.previous_time.to_s  # =\u003e 2017-01-01 00:00:00 +0900\n\np c.next_time(Time.parse('2024-06-01')).to_s\n  # =\u003e \"2024-06-02 00:00:00 +0900\"\np c.previous_time(Time.parse('2024-06-01')).to_s\n  # =\u003e \"2024-05-26 00:00:00 +0900\"\n    #\n    # `Fugit::Cron#next_time` and `#previous_time` accept a \"start time\"\n\nc = Fugit.parse_cron('0 12 * * mon#2')\n\n  # `#next` and `#prev` return Enumerable instances\n  #\n  # These two methods are available since fugit 1.10.0.\n  #\nc.next(Time.parse('2024-02-16 12:00:00'))\n  .take(3)\n  .map(\u0026:to_s)\n    # =\u003e [ '2024-03-11 12:00:00',\n    #      '2024-04-08 12:00:00',\n    #      '2024-05-13 12:00:00' ]\nc.prev(Time.parse('2024-02-16 12:00:00'))\n  .take(3)\n  .map(\u0026:to_s)\n    # =\u003e [ '2024-02-12 12:00:00',\n    #      '2024-01-08 12:00:00',\n    #      '2023-12-11 12:00:00' ]\n\n  # `#within` accepts a time range and returns an array of Eo::EoTime\n  # instances that correspond to the occurrences of the cron within\n  # the time range\n  #\n  # This method is available since fugit 1.10.0.\n  #\nc.within(Time.parse('2024-02-16 12:00')..Time.parse('2024-08-01 12:00'))\n  .map(\u0026:to_s)\n    # =\u003e [ '2024-03-11 12:00:00',\n    #      '2024-04-08 12:00:00',\n    #      '2024-05-13 12:00:00',\n    #      '2024-06-10 12:00:00',\n    #      '2024-07-08 12:00:00' ]\n\np c.brute_frequency  # =\u003e [ 604800, 604800, 53 ]\n                     #    [ delta min, delta max, occurrence count ]\np c.rough_frequency  # =\u003e 7 * 24 * 3600 (7d rough frequency)\n\np c.match?(Time.parse('2017-08-06'))  # =\u003e true\np c.match?(Time.parse('2017-08-07'))  # =\u003e false\np c.match?('2017-08-06')              # =\u003e true\np c.match?('2017-08-06 12:00')        # =\u003e false\n```\n\nExample of cron strings understood by fugit:\n```ruby\n'5 0 * * *'         # 5 minutes after midnight, every day\n'15 14 1 * *'       # at 1415 on the 1st of every month\n'0 22 * * 1-5'      # at 2200 on weekdays\n'0 22 * * mon-fri'  # idem\n'23 0-23/2 * * *'   # 23 minutes after 00:00, 02:00, 04:00, ...\n\n'@yearly'    # turns into '0 0 1 1 *'\n'@monthly'   # turns into '0 0 1 * *'\n'@weekly'    # turns into '0 0 * * 0'\n'@daily'     # turns into '0 0 * * *'\n'@midnight'  # turns into '0 0 * * *'\n'@hourly'    # turns into '0 * * * *'\n\n'0 0 L * *'     # last day of month at 00:00\n'0 0 last * *'  # idem\n'0 0 -7-L * *'  # from the seventh to last to the last day of month at 00:00\n\n# and more...\n```\n\nPlease note that `'15/30 * * * *'` is interpreted as `'15-59/30 * * * *'` since fugit 1.4.6.\n\n### time zones\n\nFugit accepts a IANA timezone identifier right after a cron string:\n```ruby\n'5 0 * * *  Europe/Rome'      # 5 minutes after midnight, every day, Rome tz\n'0 22 * * 1-5  Asia/Tbilisi'  # at 2200 on weekdays in Georgia\n\n'@yearly Asia/Kuala_Lumpur'  # turns into '0 0 1 1 * Asia/Kuala_Lumpur'\n'@monthly Asia/Jakarta'      # turns into '0 0 1 * * Asia/Jakarta'\n  #\n  # those two \"ats\" and friends since fugit 1.11.2...\n```\n\nWhen no time zone is specified, fugit uses Ruby's provided timezone.\n\n### the first Monday of the month\n\nFugit tries to follow the `man 5 crontab` documentation.\n\nThere is a surprising thing about this canon, all the columns are joined by ANDs, except for monthday and weekday which are joined together by OR if they are both set (they are not `*`).\n\nMany people (me included) [are surprised](https://superuser.com/questions/428807/run-a-cron-job-on-the-first-monday-of-every-month) when they try to specify \"at 05:00 on the first Monday of the month\" as `0 5 1-7 * 1` or `0 5 1-7 * mon` and the results are off.\n\nThe man page says:\n\n\u003e Note: The day of a command's execution can be specified by\n\u003e two fields -- day of month, and day of week. If both fields\n\u003e are restricted (ie, are not *), the command will be run when\n\u003e either field matches the current time.\n\u003e For example, ``30 4 1,15 * 5'' would cause a command to be run\n\u003e at 4:30 am on the 1st and 15th of each month, plus every Friday.\n\nFugit follows this specification.\n\nSince fugit 1.7.0, by adding `\u0026` right after a day specifier, the `day-of-month OR day-of-week` becomes `day-of-month AND day-of-week`.\n\n```ruby\n# standard cron\n\np Fugit.parse_cron('0 0 */2 * 1-5').next_time('2022-08-09').to_s\n  # ==\u003e \"2022-08-10 00:00:00 +0900\"\n\n# with an \u0026\n\np Fugit.parse_cron('0 0 */2 * 1-5\u0026').next_time('2022-08-09').to_s # or\np Fugit.parse_cron('0 0 */2\u0026 * 1-5').next_time('2022-08-09').to_s\np Fugit.parse_cron('0 0 */2\u0026 * 1-5\u0026').next_time('2022-08-09').to_s\n  # ==\u003e \"2022-08-11 00:00:00 +0900\"\n\n\n# standard cron\n\np Fugit.parse_cron('59 6 1-7 * 2').next_time('2020-03-15').to_s\n  # ==\u003e \"2020-03-17 06:59:00 +0900\"\n\n# with an \u0026\n\np Fugit.parse_cron('59 6 1-7 * 2\u0026').next_time('2020-03-15').to_s\np Fugit.parse_cron('59 6 1-7\u0026 * 2').next_time('2020-03-15').to_s\np Fugit.parse_cron('59 6 1-7\u0026 * 2\u0026').next_time('2020-03-15').to_s\n  # ==\u003e \"2020-04-07 06:59:00 +0900\"\n```\n\n### the hash extension\n\nFugit understands `0 5 * * 1#1` or `0 5 * * mon#1` as \"each first Monday of the month, at 05:00\".\n\nThe hash extension can only be used in the day-of-week field.\n\n```ruby\n'0 5 * * 1#1'    #\n'0 5 * * mon#1'  # the first Monday of the month at 05:00\n\n'0 6 * * 5#4,5#5'      #\n'0 6 * * fri#4,fri#5'  # the 4th and 5th Fridays of the month at 06:00\n\n'0 7 * * 5#-1'    #\n'0 7 * * fri#-1'  # the last Friday of the month at 07:00\n\n'0 7 * * 5#L'       #\n'0 7 * * fri#L'     #\n'0 7 * * 5#last'    #\n'0 7 * * fri#last'  # the last Friday of the month at 07:00\n\n'0 23 * * mon#2,tue'  # the 2nd Monday of the month and every Tuesday, at 23:00\n```\n\n### the modulo extension\n\nFugit, since 1.1.10, also understands cron strings like \"`9 0 * * sun%2`\" which can be read as \"every other Sunday at 9am\".\n\nThe modulo extension can only be used in the day-of-week field.\n\nFor odd Sundays, one can write `9 0 * * sun%2+1`.\n\nIt can be combined, as in `9 0 * * sun%2,tue%3+2`\n\nBut what does it reference to? It starts at 1 on 2019-01-01 (in the EtOrbi instance timezone, not the UTC \"timezone\").\n\n```ruby\nrequire 'et-orbi' # \u003e= 1.1.8\n\n# the reference\np EtOrbi.parse('2019-01-01').wday       # =\u003e 2\np EtOrbi.parse('2019-01-01').rweek      # =\u003e 1\np EtOrbi.parse('2019-01-01').rweek % 2  # =\u003e 1\n\n# today (as of this coding...)\np EtOrbi.parse('2019-04-11').wday       # =\u003e 4\np EtOrbi.parse('2019-04-11').rweek      # =\u003e 15\np EtOrbi.parse('2019-04-11').rweek % 2  # =\u003e 1\n\nc = Fugit.parse('* * * * tue%2')\nc.match?('2019-01-01')  # =\u003e false, since rweek % 2 == 1\nc.match?('2019-01-08')  # =\u003e true, since rweek % 2 == 0\n\nc = Fugit.parse('* * * * tue%2+1')\nc.match?('2019-01-01')  # =\u003e true, since (rweek + 1) % 2 == 0\nc.match?('2019-01-08')  # =\u003e false, since (rweek + 1) % 2 == 1\n\n# ...\n```\n\n`sun%2` matches if Sunday and `current_date.rweek % 2 == 0`\n`tue%3+2` matches if Tuesday and `current_date.rweek + 2 % 3 == 0`\n`tue%x+y` matches if Tuesday and `current_date.rweek + y % x == 0`\n\n\n### the second extension\n\nFugit accepts cron strings with five elements, `minute hour day-of-month month day-of-week`, the standard cron format or six elements `second minute hour day-of-month month day-of-week`.\n\n```ruby\nc = Fugit.parse('* * * * *') # every minute\nc = Fugit.parse('5 * * * *') # every hour at minute 5\nc = Fugit.parse('* * * * * *') # every second\nc = Fugit.parse('5 * * * * *') # every minute at second 5\n```\n\n\n## `Fugit::Nat`\n\nFugit understand some kind of \"natural\" language:\n\nFor example, those \"every\" get turned into `Fugit::Cron` instances:\n```ruby\nFugit::Nat.parse('every day at five')                         # ==\u003e '0 5 * * *'\nFugit::Nat.parse('every weekday at five')                     # ==\u003e '0 5 * * 1,2,3,4,5'\nFugit::Nat.parse('every day at 5 pm')                         # ==\u003e '0 17 * * *'\nFugit::Nat.parse('every tuesday at 5 pm')                     # ==\u003e '0 17 * * 2'\nFugit::Nat.parse('every wed at 5 pm')                         # ==\u003e '0 17 * * 3'\nFugit::Nat.parse('every day at 16:30')                        # ==\u003e '30 16 * * *'\nFugit::Nat.parse('every day at 16:00 and 18:00')              # ==\u003e '0 16,18 * * *'\nFugit::Nat.parse('every day at noon')                         # ==\u003e '0 12 * * *'\nFugit::Nat.parse('every day at midnight')                     # ==\u003e '0 0 * * *'\nFugit::Nat.parse('every tuesday and monday at 5pm')           # ==\u003e '0 17 * * 1,2'\nFugit::Nat.parse('every wed or Monday at 5pm and 11')         # ==\u003e '0 11,17 * * 1,3'\nFugit::Nat.parse('every day at 5 pm on America/Los_Angeles')  # ==\u003e '0 17 * * * America/Los_Angeles'\nFugit::Nat.parse('every day at 6 pm in Asia/Tokyo')           # ==\u003e '0 18 * * * Asia/Tokyo'\nFugit::Nat.parse('every 3 hours')                             # ==\u003e '0 */3 * * *'\nFugit::Nat.parse('every 4 months')                            # ==\u003e '0 0 1 */4 *'\nFugit::Nat.parse('every 5 minutes')                           # ==\u003e '*/5 * * * *'\nFugit::Nat.parse('every 15s')                                 # ==\u003e '*/15 * * * * *'\n```\n\nDirectly with `Fugit.parse(s)` is OK too:\n```ruby\nFugit.parse('every day at five')  # ==\u003e Fugit::Cron instance '0 5 * * *'\n```\n\n### Ambiguous nats\n\nNot all strings result in a clean, single, cron expression. The `multi: false|true|:fail` argument to `Fugit::Nat.parse` could help.\n\n```ruby\nFugit::Nat.parse('every day at 16:00 and 18:00')\n  .to_cron_s\n    # ==\u003e '0 16,18 * * *' (a single Fugit::Cron instances)\nFugit::Nat.parse('every day at 16:00 and 18:00', multi: true)\n  .collect(\u0026:to_cron_s)\n    # ==\u003e [ '0 16,18 * * *' ] (array of Fugit::Cron instances, here only one)\n\nFugit::Nat.parse('every day at 16:15 and 18:30')\n  .to_cron_s\n    # ==\u003e '15 16 * * *' (a single of Fugit::Cron instances)\nFugit::Nat.parse('every day at 16:15 and 18:30', multi: true)\n  .collect(\u0026:to_cron_s)\n    # ==\u003e [ '15 16 * * *', '30 18 * * *' ] (two Fugit::Cron instances)\n\nFugit::Nat.parse('every day at 16:15 and 18:30', multi: :fail)\n  # ==\u003e ArgumentError: multiple crons in \"every day at 16:15 and 18:30\"\n  #     (15 16 * * * | 30 18 * * *)\nFugit::Nat.parse('every day at 16:15 nada 18:30', multi: true)\n  # ==\u003e nil\n```\n\n`multi: true` indicates to `Fugit::Nat` that an array of `Fugit::Cron` instances is expected as a result.\n\n`multi: :fail` tells `Fugit::Nat.parse` to fail if the result is more than 1 `Fugit::Cron` instances.\n\n`multi: false` is the default behaviour, return a single `Fugit::Cron` instance or nil when it cannot parse.\n\nPlease note that \"nat\" input is limited to 256 characters (fugit 1.11.1).\n\n### Nat Midnight\n\n`\"Every day at midnight\"` is supported, but `\"Every monday at midnight\"` will be interpreted (as of Fugit \u003c= 1.4.x) as `\"Every monday at 00:00\"`. Sorry about that.\n\n\n### 12 AM and PM\n\nHow does fugit react with `\"12 am\"`, `\"12 pm\"`, `\"12 midnight\"`, etc?\n\n```ruby\nrequire 'fugit'\n\np Fugit.parse('every day at 12am').original  # ==\u003e \"0 0 * * *\"\np Fugit.parse('every day at 12pm').original  # ==\u003e \"0 12 * * *\"\n\np Fugit.parse('every day at 12:00am').original   # ==\u003e \"0 0 * * *\"\np Fugit.parse('every day at 12:00pm').original   # ==\u003e \"0 12 * * *\"\np Fugit.parse('every day at 12:00 am').original  # ==\u003e \"0 0 * * *\"\np Fugit.parse('every day at 12:00 pm').original  # ==\u003e \"0 12 * * *\"\np Fugit.parse('every day at 12:15am').original   # ==\u003e \"15 0 * * *\"\np Fugit.parse('every day at 12:15pm').original   # ==\u003e \"15 12 * * *\"\np Fugit.parse('every day at 12:15 am').original  # ==\u003e \"15 0 * * *\"\np Fugit.parse('every day at 12:15 pm').original  # ==\u003e \"15 12 * * *\"\n\np Fugit.parse('every day at 12 noon').original         # ==\u003e \"0 12 * * *\"\np Fugit.parse('every day at 12 midnight').original     # ==\u003e \"0 24 * * *\"\np Fugit.parse('every day at 12:00 noon').original      # ==\u003e \"0 12 * * *\"\np Fugit.parse('every day at 12:00 midnight').original  # ==\u003e \"0 24 * * *\"\np Fugit.parse('every day at 12:15 noon').original      # ==\u003e \"15 12 * * *\"\np Fugit.parse('every day at 12:15 midnight').original  # ==\u003e \"15 24 * * *\"\n\n  # as of fugit 1.7.2\n```\n\n\n## `Fugit::Duration`\n\nA class `Fugit::Duration` to parse duration strings (vanilla [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) ones and [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) ones).\n\nProvides duration arithmetic tools.\n\n```ruby\nrequire 'fugit'\n\nd = Fugit::Duration.parse('1y2M1d4h')\n\np d.to_plain_s  # =\u003e \"1Y2M1D4h\"\np d.to_iso_s    # =\u003e \"P1Y2M1DT4H\" ISO 8601 duration\np d.to_long_s   # =\u003e \"1 year, 2 months, 1 day, and 4 hours\"\n\nd += Fugit::Duration.parse('1y1h')\n\np d.to_long_s  # =\u003e \"2 years, 2 months, 1 day, and 5 hours\"\n\nd += 3600\n\np d.to_plain_s  # =\u003e \"2Y2M1D5h3600s\"\n\np Fugit::Duration.parse('1y2M1d4h').to_sec # =\u003e 36820800\n```\n\nThere is a `#deflate` method\n\n```ruby\nFugit::Duration.parse(1000).to_plain_s # =\u003e \"1000s\"\nFugit::Duration.parse(3600).to_plain_s # =\u003e \"3600s\"\nFugit::Duration.parse(1000).deflate.to_plain_s # =\u003e \"16m40s\"\nFugit::Duration.parse(3600).deflate.to_plain_s # =\u003e \"1h\"\n\n# or event shorter\nFugit.parse(1000).deflate.to_plain_s # =\u003e \"16m40s\"\nFugit.parse(3600).deflate.to_plain_s # =\u003e \"1h\"\n```\n\nThere is also an `#inflate` method\n\n```ruby\nFugit::Duration.parse('1h30m12').inflate.to_plain_s # =\u003e \"5412s\"\nFugit.parse('1h30m12').inflate.to_plain_s # =\u003e \"5412s\"\n\nFugit.parse('1h30m12').to_sec # =\u003e 5412\nFugit.parse('1h30m12').to_sec.to_s + 's' # =\u003e \"5412s\"\n```\n\nThe `to_*_s` methods are also available as class methods:\n```ruby\np Fugit::Duration.to_plain_s('1y2M1d4h')\n  # =\u003e \"1Y2M1D4h\"\np Fugit::Duration.to_iso_s('1y2M1d4h')\n  # =\u003e \"P1Y2M1DT4H\" ISO 8601 duration\np Fugit::Duration.to_long_s('1y2M1d4h')\n  # =\u003e \"1 year, 2 months, 1 day, and 4 hours\"\n```\n\n\n## `Fugit::At`\n\nPoints in time are parsed and given back as EtOrbi::EoTime instances.\n\n```ruby\nFugit::At.parse('2017-12-12').to_s\n  # ==\u003e \"2017-12-12 00:00:00 +0900\" (at least here in Hiroshima)\n\nFugit::At.parse('2017-12-12 12:00:00 America/New_York').to_s\n  # ==\u003e \"2017-12-12 12:00:00 -0500\"\n```\n\nDirectly with `Fugit.parse_at(s)` is OK too:\n```ruby\nFugit.parse_at('2017-12-12 12:00:00 America/New_York').to_s\n  # ==\u003e \"2017-12-12 12:00:00 -0500\"\n```\n\nDirectly with `Fugit.parse(s)` is OK too:\n```ruby\nFugit.parse('2017-12-12 12:00:00 America/New_York').to_s\n  # ==\u003e \"2017-12-12 12:00:00 -0500\"\n```\n\n\n## KNOWN ISSUES\n\nThe gem [nice_hash](https://github.com/MarioRuiz/nice_hash) gets in the way of `fugit`, as seen in [issue 108](https://github.com/floraison/fugit/issues/108). It prevents `fugit` from correctly parsing cron strings.\n\n\n## LICENSE\n\nMIT, see [LICENSE.txt](LICENSE.txt)\n\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffloraison%2Ffugit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffloraison%2Ffugit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffloraison%2Ffugit/lists"}