{"id":13507738,"url":"https://github.com/peek-travel/cocktail","last_synced_at":"2026-02-26T08:02:15.659Z","repository":{"id":24978818,"uuid":"99972537","full_name":"peek-travel/cocktail","owner":"peek-travel","description":"Elixir date recurrence library based on iCalendar events","archived":false,"fork":false,"pushed_at":"2024-05-15T18:11:37.000Z","size":532,"stargazers_count":223,"open_issues_count":15,"forks_count":30,"subscribers_count":24,"default_branch":"main","last_synced_at":"2025-03-28T14:09:42.935Z","etag":null,"topics":["datetime","elixir","icalendar","scheduling"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/cocktail","language":"Elixir","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/peek-travel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","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}},"created_at":"2017-08-10T23:25:20.000Z","updated_at":"2025-01-08T18:57:57.000Z","dependencies_parsed_at":"2024-05-01T16:19:47.961Z","dependency_job_id":"82d03e53-bd16-426a-be67-9d9bf9e14370","html_url":"https://github.com/peek-travel/cocktail","commit_stats":{"total_commits":298,"total_committers":18,"mean_commits":"16.555555555555557","dds":"0.44966442953020136","last_synced_commit":"988bd3d2c40b3ad4de8517c992b448acd33cdd70"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peek-travel%2Fcocktail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peek-travel%2Fcocktail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peek-travel%2Fcocktail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peek-travel%2Fcocktail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peek-travel","download_url":"https://codeload.github.com/peek-travel/cocktail/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246301963,"owners_count":20755512,"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":["datetime","elixir","icalendar","scheduling"],"created_at":"2024-08-01T02:00:38.416Z","updated_at":"2025-10-21T15:05:52.360Z","avatar_url":"https://github.com/peek-travel.png","language":"Elixir","funding_links":[],"categories":["Date and Time","Elixir"],"sub_categories":[],"readme":"# Cocktail\n\n[![CI\nStatus](https://github.com/peek-travel/cocktail/workflows/CI/badge.svg)](https://github.com/peek-travel/cocktail/actions)\n[![codecov](https://codecov.io/gh/peek-travel/cocktail/branch/main/graph/badge.svg)](https://codecov.io/gh/peek-travel/cocktail)\n[![Hex.pm Version](https://img.shields.io/hexpm/v/cocktail.svg?style=flat)](https://hex.pm/packages/cocktail)\n[![License](https://img.shields.io/hexpm/l/cocktail.svg)](LICENSE.md)\n\nCocktail is an Elixir date recurrence library based on [iCalendar events](https://tools.ietf.org/html/rfc5545#section-3.6.1). Its primary use case currently is to expand schedules with recurrence rules into streams of occurrences. For example: say you wanted to represent a repeating schedule of events that occurred every other week, on Mondays, Wednesdays and Fridays, at 10am and 4pm.\n\n```elixir\niex\u003e schedule = Cocktail.Schedule.new(~N[2017-01-02 10:00:00])\n...\u003e schedule = Cocktail.Schedule.add_recurrence_rule(schedule, :weekly, interval: 2, days: [:monday, :wednesday, :friday], hours: [10, 16])\n#Cocktail.Schedule\u003cEvery 2 weeks on Mondays, Wednesdays and Fridays on the 10th and 16th hours of the day\u003e\n```\n\nThen to get a list of the first 10 occurrences of this schedule, you would do:\n\n```elixir\n...\u003e stream = Cocktail.Schedule.occurrences(schedule)\n...\u003e Enum.take(stream, 10)\n[~N[2017-01-02 10:00:00], ~N[2017-01-02 16:00:00], ~N[2017-01-04 10:00:00],\n ~N[2017-01-04 16:00:00], ~N[2017-01-06 10:00:00], ~N[2017-01-06 16:00:00],\n ~N[2017-01-16 10:00:00], ~N[2017-01-16 16:00:00], ~N[2017-01-18 10:00:00],\n ~N[2017-01-18 16:00:00]]\n```\n\n## Installation\n\nCocktail is [available in Hex](https://hex.pm/packages/cocktail) and can be installed\nby adding `cocktail` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:cocktail, \"~\u003e 0.10\"}\n  ]\nend\n```\n\n## Documentation\n\nDetailed documentation with all available options can be found at \u003chttps://hexdocs.pm/cocktail\u003e.\n\n## Quick-start Guide\n\n### Schedules\n\nEverything starts with a [Cocktail.Schedule](https://hexdocs.pm/cocktail/Cocktail.Schedule.html); create one like this:\n\n```elixir\niex\u003e schedule = Cocktail.schedule(start_time, opts)\n#Cocktail.Schedule\u003c\u003e\n\n# or\n...\u003e schedule = Cocktail.Schedule.new(start_time, opts)\n#Cocktail.Schedule\u003c\u003e\n```\n\n-   `start_time` - Either a `DateTime` or a `NaiveDateTime` representing the beginning of your schedule.\n-   `opts`:\n    -   `duration` - (optional) How long each occurrence is, in seconds.\n\n### Recurrence Rules\n\nSchedules are pretty useless on their own. To have them do something useful, you add recurrence rules to them. Currently, Cocktail supports:\n\n-   Monthly\n-   Weekly\n-   Daily\n-   Hourly\n-   Minutely\n-   Secondly\n\nOn top of these basic recurrence frequencies, you can add various options. Let's see some examples:\n\n```elixir\niex\u003e every_other_day = Cocktail.Schedule.add_recurrence_rule(schedule, :daily, interval: 2)\n#Cocktail.Schedule\u003cEvery 2 days\u003e\n\n...\u003e weekly_on_mo_we_fr = Cocktail.Schedule.add_recurrence_rule(schedule, :weekly, days: [:monday, :wednesday, :friday])\n#Cocktail.Schedule\u003cWeekly on Mondays, Wednesdays and Fridays\u003e\n\n...\u003e daily_at_9am_and_5pm = Cocktail.Schedule.add_recurrence_rule(schedule, :daily, hours: [9, 17])\n#Cocktail.Schedule\u003cDaily on the 9th and 17th hours of the day\u003e\n```\n\nFor more details about frequencies and options, see [Cocktail.Schedule.add_recurrence_rule/3](https://hexdocs.pm/cocktail/Cocktail.Schedule.html#add_recurrence_rule/3)\n\n### Occurrences\n\nOnce you've got a schedule set up the way you want, you can generate a stream of occurrences that match the schedule like so:\n\n```elixir\niex\u003e occurrences = Cocktail.Schedule.occurrences(schedule)\n#Function\u003c60.51599720/2 in Stream.unfold/2\u003e\n...\u003e Enum.take(occurrences, 3)\n[~N[2017-01-01 00:00:00], ~N[2017-01-02 00:00:00], ~N[2017-01-03 00:00:00]]\n```\n\nThe type of each occurrence depends on what start time type you used, and wether or not you supplied a duration when creating the schedule.\n\n### Duration\n\nIf you add the `duration` option when creating a schedule, you'll get `Cocktail.Span` structs as occurrences, with `:from` and `:until` fields of the same type as your start time.\n\n```elixir\niex\u003e schedule = Cocktail.schedule(~N[2017-01-01 00:00:00], duration: 3600) |\u003e Cocktail.Schedule.add_recurrence_rule(:daily)\n#Cocktail.Schedule\u003cDaily\u003e\n...\u003e occurrences = Cocktail.Schedule.occurrences(schedule)\n#Function\u003c60.51599720/2 in Stream.unfold/2\u003e\n...\u003e Enum.take(occurrences, 3)\n[%Cocktail.Span{from: ~N[2017-01-01 00:00:00], until: ~N[2017-01-01 01:00:00]},\n %Cocktail.Span{from: ~N[2017-01-02 00:00:00], until: ~N[2017-01-02 01:00:00]},\n %Cocktail.Span{from: ~N[2017-01-03 00:00:00], until: ~N[2017-01-03 01:00:00]}]\n```\n\n### Recurrence Times and Exception Times\n\nYou can also add one-off recurrence times that don't fit into a normal recurrence pattern, and exception times if you want to exclude a time that would normally be included because of a recurrence rule:\n\n```elixir\niex\u003e schedule = Cocktail.schedule(~N[2017-01-01 08:00:00]) |\u003e Cocktail.Schedule.add_recurrence_rule(:daily)\n#Cocktail.Schedule\u003cDaily\u003e\n...\u003e schedule = [~N[2017-01-01 09:00:00], ~N[2017-01-02 11:00:00], ~N[2017-01-03 17:00:00]] |\u003e Enum.reduce(schedule, \u0026Cocktail.Schedule.add_recurrence_time(\u00262, \u00261))\n#Cocktail.Schedule\u003cDaily\u003e\n...\u003e schedule = Cocktail.Schedule.add_exception_time(schedule, ~N[2017-01-02 08:00:00])\n#Cocktail.Schedule\u003cDaily\u003e\n...\u003e Cocktail.Schedule.occurrences(schedule) |\u003e Enum.take(6)\n[~N[2017-01-01 08:00:00], ~N[2017-01-01 09:00:00], ~N[2017-01-02 11:00:00],\n ~N[2017-01-03 08:00:00], ~N[2017-01-03 17:00:00], ~N[2017-01-04 08:00:00]]\n```\n\n### iCalendar\n\nYou can convert schedules to and from the iCalendar format like this:\n\n```elixir\niex\u003e i_calendar = Cocktail.Schedule.to_i_calendar(schedule)\n\"DTSTART:20170101T000000\\nRRULE:FREQ=DAILY\"\n\n...\u003e Cocktail.Schedule.from_i_calendar(i_calendar)\n{:ok, #Cocktail.Schedule\u003cDaily\u003e}\n```\n\n## Roadmap\n\n-   [x] investigate and fix DST bugs when using zoned DateTime\n-   [ ] support all iCalendar RRULE options\n-   [ ] support week-start option\n-   [ ] support iCalendar EXRULE\n-   [ ] convert to/from JSON representation\n\n## Credits\n\nCocktail is heavily inspired by and based on a very similar Ruby library, [ice_cube](https://github.com/seejohnrun/ice_cube).\n\n## License\n\n[MIT](LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeek-travel%2Fcocktail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeek-travel%2Fcocktail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeek-travel%2Fcocktail/lists"}