make_a_calendar_toolkit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +27 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +6 -0
  7. data/CODE_OF_CONDUCT.md +7 -0
  8. data/CONTRIBUTING.md +7 -0
  9. data/Gemfile +4 -0
  10. data/Gemfile.lock +21 -0
  11. data/LICENSE +21 -0
  12. data/README.md +154 -0
  13. data/Rakefile +11 -0
  14. data/SECURITY.md +5 -0
  15. data/docs/README.md +19 -0
  16. data/docs/advanced-examples.md +28 -0
  17. data/docs/api-reference.md +15 -0
  18. data/docs/architecture.md +5 -0
  19. data/docs/business-days.md +7 -0
  20. data/docs/calendar-rendering.md +5 -0
  21. data/docs/date-converters.md +5 -0
  22. data/docs/date-semantics.md +21 -0
  23. data/docs/fiscal-445.md +11 -0
  24. data/docs/getting-started.md +12 -0
  25. data/docs/holidays.md +7 -0
  26. data/docs/ics-export.md +5 -0
  27. data/docs/online-resources.md +12 -0
  28. data/docs/payroll-schedules.md +5 -0
  29. data/docs/printable-calendars.md +11 -0
  30. data/docs/recurring-dates.md +7 -0
  31. data/examples/01-monthly-printable.rb +3 -0
  32. data/examples/02-yearly-svg.rb +3 -0
  33. data/examples/03-federal-holidays.rb +4 -0
  34. data/examples/04-business-deadline.rb +4 -0
  35. data/examples/05-biweekly-payroll.rb +4 -0
  36. data/examples/06-rotating-shifts.rb +4 -0
  37. data/examples/07-fiscal-445.rb +4 -0
  38. data/examples/08-excel-serial.rb +3 -0
  39. data/examples/09-windows-filetime.rb +3 -0
  40. data/examples/10-holidays-ics.rb +4 -0
  41. data/examples/11-rails-style-service.rb +8 -0
  42. data/examples/12-ink-saver-planner.rb +3 -0
  43. data/exe/make-calendar +156 -0
  44. data/lib/make_a_calendar/calendar.rb +187 -0
  45. data/lib/make_a_calendar/converters.rb +90 -0
  46. data/lib/make_a_calendar/core/date_math.rb +86 -0
  47. data/lib/make_a_calendar/errors.rb +7 -0
  48. data/lib/make_a_calendar/export/ics.rb +52 -0
  49. data/lib/make_a_calendar/scheduling/business_days.rb +72 -0
  50. data/lib/make_a_calendar/scheduling/fiscal.rb +67 -0
  51. data/lib/make_a_calendar/scheduling/holidays.rb +60 -0
  52. data/lib/make_a_calendar/scheduling/recurring.rb +100 -0
  53. data/lib/make_a_calendar/version.rb +5 -0
  54. data/lib/make_a_calendar.rb +52 -0
  55. data/samples/calendar-2027.svg +982 -0
  56. data/samples/october-2027-ink-saver.svg +103 -0
  57. data/samples/october-2027.svg +103 -0
  58. data/samples/us-federal-holidays-2027.ics +83 -0
  59. data/samples/us-federal-holidays-2027.json +57 -0
  60. metadata +139 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7b1145ce898bcbfe87749ff4eadb6dff4bb610b0abde0bb8feecf1b0ced9b5e3
4
+ data.tar.gz: 4060c5b3ade3f1a1cabcd6704d9d77b186ac5772151cafbf1bf22ffba22679fb
5
+ SHA512:
6
+ metadata.gz: ef360e90269be4d60dfda75aa937f991990bb1d4176b51a8c942e1ae8d08d3e6bda9fc7aee4f182d5dc6e662c5ef0327e8ff4753f00541866877e160eca5b930
7
+ data.tar.gz: 3e7d94d67856eab5874e7f83ba8ff292e04b5d7ea24f1c8632e6cfb5e41583755427c50e7777ce81148b39635ec923194d0448c4374fd32be8a4a30775c8eff5
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ /.bundle/
2
+ /vendor/
3
+ *.gem
4
+ coverage/
5
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --format documentation
data/.rubocop.yml ADDED
@@ -0,0 +1,27 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.7
3
+ NewCops: disable
4
+ SuggestExtensions: false
5
+ Exclude:
6
+ - "vendor/**/*"
7
+
8
+ Layout/LineLength:
9
+ Max: 160
10
+
11
+ Metrics/AbcSize:
12
+ Enabled: false
13
+
14
+ Metrics/ClassLength:
15
+ Enabled: false
16
+
17
+ Metrics/MethodLength:
18
+ Max: 30
19
+
20
+ Style/Documentation:
21
+ Enabled: false
22
+
23
+ Style/GuardClause:
24
+ Enabled: false
25
+
26
+ Style/IfUnlessModifier:
27
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.0
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-10-12
4
+
5
+ - Initial public release of calendar grids, date arithmetic, US federal holiday rules, business-day operations, recurring pay dates, shift schedules, NRF-style retail fiscal calendars, date converters, print-ready SVG/HTML, JSON/CSV, ICS, and CLI commands.
6
+ - Core operations use Ruby's standard library and run offline.
@@ -0,0 +1,7 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ We are committed to a welcoming, respectful community. Be considerate, patient, and constructive. Harassment, discriminatory language, personal attacks, and unwanted attention are not acceptable.
4
+
5
+ Project maintainers may remove, edit, or reject contributions that do not follow this code and may temporarily or permanently exclude contributors for unacceptable behavior. Report concerns privately through the repository's GitHub contact options.
6
+
7
+ This code applies in project spaces and when someone is representing the project publicly.
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,7 @@
1
+ # Contributing
2
+
3
+ Bug reports and focused pull requests are welcome. Please include the Ruby version, a minimal reproduction, expected result, and actual result. Date changes should include independent calendar references or clearly stated rules.
4
+
5
+ Run the local checks with `ruby -Ilib spec/all_spec.rb`, `ruby -c` on changed Ruby files, and `gem build make_a_calendar_toolkit.gemspec`. Keep runtime dependencies at zero and document any new public behavior in the README or `docs/`.
6
+
7
+ Do not include credentials, private data, generated files that are not deliberate samples, or changes copied from the Make a Calendar website's private implementation.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,21 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ make_a_calendar_toolkit (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ minitest (5.11.3)
10
+ rake (12.3.3)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ make_a_calendar_toolkit!
17
+ minitest (~> 5.0)
18
+ rake (~> 12.0)
19
+
20
+ BUNDLED WITH
21
+ 2.5.23
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ethan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # Make a Calendar Toolkit
2
+
3
+ An offline Ruby toolkit for calendar grids, business scheduling, holiday dates, fiscal periods, date conversion, printable SVG/HTML, and iCalendar exports.
4
+
5
+ [![CI](https://github.com/makeacalendar/make-a-calendar-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/makeacalendar/make-a-calendar-ruby/actions/workflows/ci.yml)
6
+
7
+ ## Contents
8
+
9
+ - [What it is](#what-it-is)
10
+ - [Install and start](#install-and-start)
11
+ - [Calendar grids and print output](#calendar-grids-and-print-output)
12
+ - [Business days and US federal holidays](#business-days-and-us-federal-holidays)
13
+ - [Pay and shift schedules](#pay-and-shift-schedules)
14
+ - [Retail fiscal calendars](#retail-fiscal-calendars)
15
+ - [Converters](#converters)
16
+ - [ICS export](#ics-export)
17
+ - [Command line](#command-line)
18
+ - [Rails use](#rails-use)
19
+ - [Date rules and limitations](#date-rules-and-limitations)
20
+ - [Development](#development)
21
+ - [Documentation and related tools](#documentation-and-related-tools)
22
+ - [Contributing, security, license](#contributing-security-license)
23
+
24
+ ## What it is
25
+
26
+ Make a Calendar Toolkit packages reusable date and scheduling behavior for Ruby applications. It creates month and year grids, counts business days, applies a documented set of US federal holiday rules, builds pay and rotating-shift schedules, maps NRF-style 4-4-5/4-5-4/5-4-4 fiscal periods, converts common date representations, and exports calendars as SVG, print-oriented HTML, JSON, CSV, or date-only ICS.
27
+
28
+ Core features work offline using Ruby's standard library. The gem does not call the Make a Calendar website and does not reproduce its private implementation. Rails is not a runtime dependency.
29
+
30
+ The project was created by Ethan, the developer behind [Make a Calendar](https://make-a-calendar.com/), a browser-based calendar and date-tools platform.
31
+
32
+ ## Install and start
33
+
34
+ ```sh
35
+ gem install make_a_calendar_toolkit
36
+ ```
37
+
38
+ ```ruby
39
+ require "date"
40
+ require "make_a_calendar"
41
+
42
+ calendar = MakeACalendar.month(year: 2027, month: 10, week_start: :monday)
43
+ puts calendar.to_json
44
+ File.write("october-2027.svg", calendar.to_svg(theme: :editorial, page_size: :letter))
45
+ ```
46
+
47
+ The library declares Ruby `>= 2.6` and has no runtime gem dependencies.
48
+
49
+ ## Calendar grids and print output
50
+
51
+ Month grids contain four, five, or six rows unless `fixed_rows: 6` is requested. Cells carry civil `Date` values, adjacent-month information, weekdays, and ISO week data. A `Date` stays a date; no UTC instant is constructed to determine its weekday.
52
+
53
+ ```ruby
54
+ month = MakeACalendar.month(year: 2027, month: 10, week_start: :sunday, fixed_rows: 6)
55
+ puts month.to_csv
56
+ File.write("planner.html", month.to_html(theme: :ink_saver, page_size: :letter_landscape))
57
+ ```
58
+
59
+ Available print themes are `:editorial`, `:business`, `:academic`, and `:ink_saver`. Paper choices are `:letter`, `:a4`, `:letter_landscape`, and `:a4_landscape`. HTML includes print CSS; SVG is standalone and has accessible title and description elements. `MakeACalendar.year(year: 2027)` returns a twelve-month calendar suitable for one-page SVG or HTML output.
60
+
61
+ ## Business days and US federal holidays
62
+
63
+ Date ranges include both endpoints by default. `inclusive: false` removes both endpoints. Saturday and Sunday are the default weekend (`Date#wday` values 6 and 0); pass your own weekend list for another work pattern. Adding a nonzero number of business days starts counting after the supplied date; zero returns that date unchanged.
64
+
65
+ ```ruby
66
+ holidays = MakeACalendar.federal_holidays(2027)
67
+ count = MakeACalendar.business_days_between(
68
+ Date.new(2027, 1, 1), Date.new(2027, 3, 31), holidays: holidays
69
+ )
70
+ deadline = MakeACalendar.add_business_days(Date.new(2027, 2, 1), 30, holidays: holidays)
71
+ ```
72
+
73
+ Each federal `Holiday` keeps its legal date and observed weekday separately. The rule set includes effective-date distinctions for MLK Day, Juneteenth, the Monday holiday changes, and Veterans Day's 1971–1977 observance. It is a federal calendar reference, not state law, court rules, bank policy, or an employer's closure schedule. Add caller-owned holidays when a business uses different rules.
74
+
75
+ ## Pay and shift schedules
76
+
77
+ `MakeACalendar::Scheduling.pay_dates` supports weekly, biweekly, semi-monthly, and monthly dates. Weekend/holiday adjustments must be selected explicitly with `:none`, `:following`, `:preceding`, or `:modified_following`. The library does not assume one employer's payday convention.
78
+
79
+ `shift_dates` accepts a repeating list such as `[2, 2, 3]` or `"2-2-3"`; entries alternate on-duty and off-duty blocks, beginning on duty. Results are date labels only and do not represent hours worked or a fixed-length UTC shift across daylight-saving changes.
80
+
81
+ ## Retail fiscal calendars
82
+
83
+ `MakeACalendar.fiscal_calendar(year: 2029, pattern: :four_four_five)` uses the Sunday nearest February 1. The default label is the ending year, so a fiscal year labeled 2029 starts in 2028. `:four_four_five`, `:four_five_four`, and `:five_four_four` are supported. A 53rd week is assigned to period 12 by default; use `extra_week: :first_period` to assign it to period 1. This is one documented convention, not a claim that every company's accounting calendar matches it.
84
+
85
+ ## Converters
86
+
87
+ `MakeACalendar::Converters` includes Unix seconds/milliseconds/microseconds/nanoseconds with rational arithmetic, Excel 1900 and 1904 serial dates, Windows FILETIME, ISO-8601 timestamps that require an explicit offset, and unambiguous `YYYY-DDD` / `YYYYDDD` ordinal dates. Excel 1900 serial 60 raises because it represents Excel's fictitious 1900-02-29. Two-digit ordinal years and historical Julian calendar conversions are not inferred.
88
+
89
+ ## ICS export
90
+
91
+ `MakeACalendar.to_ics` exports date-only events with CRLF line endings, escaped text fields, folded content lines, stable UID defaults, and exclusive `DTEND` dates. It does not emit time-zone definitions or promise full recurrence-rule support.
92
+
93
+ ```ruby
94
+ ics = MakeACalendar.to_ics([
95
+ { date: "2027-10-12", summary: "Planning day", description: "Quarterly review" }
96
+ ])
97
+ File.write("planning.ics", ics)
98
+ ```
99
+
100
+ ## Command line
101
+
102
+ ```sh
103
+ make-calendar month --year 2027 --month 10 --format svg --output october.svg
104
+ make-calendar year --year 2027 --format html
105
+ make-calendar holidays --year 2027 --country us --observed
106
+ make-calendar business-days --from 2027-01-01 --to 2027-03-31 --observed
107
+ make-calendar add-business-days --date 2027-02-01 --days 30
108
+ make-calendar fiscal --year 2029 --pattern 445
109
+ make-calendar shifts --start 2027-01-01 --to 2027-01-31 --pattern 2-2-3
110
+ make-calendar convert excel --serial 45000 --system 1900
111
+ make-calendar convert unix --serial 1234567890 --system seconds
112
+ make-calendar export-ics --input events.json --output events.ics
113
+ ```
114
+
115
+ Output goes to standard output unless `--output` is supplied. Existing files are protected unless `--force` is used. Run `make-calendar --help` for the full syntax. The CLI accepts US holidays only in this release.
116
+
117
+ ## Rails use
118
+
119
+ Rails is optional. In a Rails application, add the gem to the application's Gemfile, then call the Ruby API in a service object:
120
+
121
+ ```ruby
122
+ # app/services/monthly_report_calendar.rb
123
+ class MonthlyReportCalendar
124
+ def self.call(year:, month:)
125
+ MakeACalendar.month(year: year, month: month, week_start: :monday).to_svg
126
+ end
127
+ end
128
+ ```
129
+
130
+ No Rails modules are loaded by the gem.
131
+
132
+ ## Date rules and limitations
133
+
134
+ Gregorian civil dates are represented by Ruby `Date`. Month grids use Sunday-first or Monday-first ordering. ISO weeks and week-years follow Ruby's ISO calendar fields. The standard `Date` implementation defines the supported range; invalid dates and invalid month values raise errors. Holiday rules are limited to the documented US federal rule set; local and organization-specific holidays remain caller data. Payroll dates and fiscal-week policies are configurable where the library has a defined option. PDF/PNG generation, time-zone-aware timed events, state holidays, and astronomical/historic calendar systems are outside 0.1.0.
135
+
136
+ ## Development
137
+
138
+ ```sh
139
+ ruby -Ilib spec/all_spec.rb
140
+ find lib exe spec examples -name '*.rb' -print0 | xargs -0 -n1 ruby -c
141
+ gem build make_a_calendar_toolkit.gemspec
142
+ ```
143
+
144
+ CI runs tests, Ruby syntax checks, package build, archive inspection, and CLI help on Ruby 2.7, 3.2, and 3.4. The test suite uses independent date expectations and covers calendar boundaries, holidays, business schedules, fiscal periods, converters, renderer escaping, ICS, and CLI behavior.
145
+
146
+ ## Documentation and related tools
147
+
148
+ Technical guides are in [`docs/`](docs/). Helpful browser-based references include [monthly calendar templates](https://make-a-calendar.com/monthly-calendars), [date calculators](https://make-a-calendar.com/date-tools), [business-day calculator](https://make-a-calendar.com/business-days-calculator), [4-4-5 calendar overview](https://make-a-calendar.com/445-calendar), [date converters](https://make-a-calendar.com/converters), and the [iCalendar generator](https://make-a-calendar.com/ical-generator). Those pages are separate web tools; this gem runs locally and does not depend on them.
149
+
150
+ ## Contributing, security, license
151
+
152
+ See [CONTRIBUTING.md](CONTRIBUTING.md), [SECURITY.md](SECURITY.md), and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). Released under the [MIT License](LICENSE).
153
+
154
+ Created by Ethan, the developer behind [Make a Calendar](https://make-a-calendar.com/).
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rake/testtask"
4
+ require "bundler/gem_tasks"
5
+
6
+ Rake::TestTask.new(:spec) do |task|
7
+ task.libs << "lib"
8
+ task.pattern = "spec/**/*_spec.rb"
9
+ end
10
+
11
+ task default: :spec
data/SECURITY.md ADDED
@@ -0,0 +1,5 @@
1
+ # Security policy
2
+
3
+ Please report suspected vulnerabilities privately through GitHub's security advisory reporting for this repository. Include affected versions, impact, and a reproducible example when possible. Do not post credentials or sensitive personal information in a public issue.
4
+
5
+ The library has no network client and no runtime gem dependencies. Treat user-provided paths as application input, validate them before use, and do not render untrusted HTML outside the provided escaped calendar renderers.
data/docs/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # Documentation
2
+
3
+ - [Getting started](getting-started.md)
4
+ - [Architecture](architecture.md)
5
+ - [API reference map](api-reference.md)
6
+ - [Date semantics](date-semantics.md)
7
+ - [Calendar rendering](calendar-rendering.md)
8
+ - [Printable calendars](printable-calendars.md)
9
+ - [Business-day arithmetic](business-days.md)
10
+ - [US federal holidays](holidays.md)
11
+ - [Pay and shift schedules](recurring-dates.md)
12
+ - [Fiscal 4-4-5 calendars](fiscal-445.md)
13
+ - [Date converters](date-converters.md)
14
+ - [iCalendar export](ics-export.md)
15
+ - [Rails integration](rails-integration.md)
16
+ - [Advanced examples](advanced-examples.md)
17
+ - [Related online resources](online-resources.md)
18
+
19
+ These guides document the behavior shipped in the gem. A dedicated documentation website is not configured in version 0.1.0; GitHub serves these source documents publicly.
@@ -0,0 +1,28 @@
1
+ # Advanced examples
2
+
3
+ ## Fiscal period lookup
4
+
5
+ ```ruby
6
+ fiscal = MakeACalendar.fiscal_calendar(year: 2029, pattern: :four_five_four)
7
+ period = fiscal.period_for(Date.new(2028, 10, 1))
8
+ puts [fiscal.label_year, period.quarter, period.number].join(" / ")
9
+ ```
10
+
11
+ ## Excel date validation
12
+
13
+ ```ruby
14
+ begin
15
+ date = MakeACalendar::Converters.excel(60, system: "1900")
16
+ rescue ArgumentError => error
17
+ warn error.message
18
+ end
19
+ ```
20
+
21
+ ## iCalendar holiday export
22
+
23
+ ```ruby
24
+ events = MakeACalendar.federal_holidays(2027).map do |holiday|
25
+ { date: holiday.observed_date, summary: holiday.name }
26
+ end
27
+ File.write("federal-holidays.ics", MakeACalendar.to_ics(events))
28
+ ```
@@ -0,0 +1,15 @@
1
+ # API reference map
2
+
3
+ Require `make_a_calendar`.
4
+
5
+ - `MakeACalendar.month`, `MakeACalendar.year`
6
+ - `MakeACalendar.business_days_between`, `MakeACalendar.add_business_days`
7
+ - `MakeACalendar.federal_holidays`, `MakeACalendar.fiscal_calendar`, `MakeACalendar.to_ics`
8
+ - `MakeACalendar::DateMath` for date grids, quarters, date ranges, ordinals, and ISO weeks
9
+ - `MakeACalendar::BusinessDays` for iteration and month/year totals
10
+ - `MakeACalendar::Scheduling` for pay dates and shift cycles
11
+ - `MakeACalendar::Converters` for Unix, Excel, FILETIME, ISO 8601, and ordinal values
12
+ - `Calendar#to_json`, `#to_csv`, `#to_html`, and `#to_svg`
13
+ - `YearCalendar#to_json`, `#to_html`, and `#to_svg`
14
+
15
+ See the README and focused guides for boundary conventions and examples.
@@ -0,0 +1,5 @@
1
+ # Architecture
2
+
3
+ The `DateMath` module owns civil date operations and month-grid geometry. Calendar renderers consume immutable grids. Scheduling modules implement holiday rules, workday iteration, pay dates, rotating patterns, and NRF-style fiscal periods. Converter methods make source epochs and units explicit. The `ICS` module serializes date-only events. The executable maps options to these public modules and does not contain a separate date engine.
4
+
5
+ The gem uses the Ruby standard library (`date`, `time`, `json`, `csv`, `cgi`, and `optparse`) and no runtime dependencies. It does not request data from Make a Calendar or claim to reproduce the site's private code.
@@ -0,0 +1,7 @@
1
+ # Business-day arithmetic
2
+
3
+ Use `MakeACalendar.business_days_between(from, to, weekend: [0, 6], holidays: [], inclusive: true)` to count working dates. Ruby weekday numbers are Sunday 0 through Saturday 6. A `Holiday` contributes its observed date; a `Date` or ISO date string contributes itself.
4
+
5
+ `MakeACalendar.add_business_days(date, count, ...)` counts after the start for nonzero values. `BusinessDays.each_workday` yields dates in the requested range. `in_month` and `in_year` count weekdays with the same options.
6
+
7
+ The US federal holiday rules are convenience inputs. Add caller-owned dates for company closures and verify contract, court, payroll, and state rules independently.
@@ -0,0 +1,5 @@
1
+ # Calendar rendering
2
+
3
+ `Calendar#to_svg` returns a standalone SVG with a title, description, legible day cells, and an optional holiday label. `Calendar#to_html` returns a document with print CSS. Both escape user-facing text and offer `:editorial`, `:business`, `:academic`, and `:ink_saver` themes. Paper dimensions accept Letter or A4 in portrait or landscape orientation.
4
+
5
+ The yearly renderer lays out 12 month grids on one page. PDF and raster exports are not included; print HTML through a browser or convert SVG with an application chosen by the caller.
@@ -0,0 +1,5 @@
1
+ # Date converters
2
+
3
+ `Converters.unix` takes a value and explicit unit (`:seconds`, `:milliseconds`, `:microseconds`, or `:nanoseconds`) and returns UTC `Time`. `Converters.to_unix` reverses the conversion.
4
+
5
+ `Converters.excel` accepts the 1900 or 1904 system; 1900 serial 60 is rejected. Fractional days return a UTC `Time`. `Converters.filetime` and `to_filetime` convert 100-nanosecond ticks since 1601-01-01 UTC. `parse_time` requires an explicit UTC marker or numeric offset. `ordinal` accepts only four-digit-year formats `YYYY-DDD` and `YYYYDDD`.
@@ -0,0 +1,21 @@
1
+ # Date semantics
2
+
3
+ ## Civil dates
4
+
5
+ Pass a `Date` or ISO `YYYY-MM-DD` string to date-only APIs. A civil date has no time zone; its weekday is calculated directly as a calendar date.
6
+
7
+ ## Month grids
8
+
9
+ Week starts are `:sunday` (Ruby `Date#wday` 0) or `:monday`. Natural grids use four through six rows. `fixed_rows: 6` creates a consistent print height. Cells outside the month carry adjacent dates. ISO week number and week-year are attached per cell.
10
+
11
+ ## Business-day ranges
12
+
13
+ `BusinessDays.between` includes both endpoints by default, skips the configured weekend, and excludes the supplied holiday date or each holiday's `observed_date`. Set `inclusive: false` to exclude both range endpoints. Adding a nonzero number of workdays moves forward or backward after the start date.
14
+
15
+ ## Holiday history
16
+
17
+ US federal rules distinguish actual dates from weekend-observed dates. Monday observances reflect the post-1971 Uniform Monday Holiday rules; Veterans Day's 1971–1977 Monday observance is accounted for. Juneteenth begins in 2021. Federal observance is not a proxy for state law, financial market closures, or a company's policy.
18
+
19
+ ## Timestamp conversion
20
+
21
+ Timestamp functions require an explicit unit. ISO timestamps require a UTC marker or numeric offset. Excel's 1900 system rejects serial 60, and FILETIME uses 100-nanosecond ticks since 1601-01-01 UTC.
@@ -0,0 +1,11 @@
1
+ # Retail 4-4-5 fiscal calendars
2
+
3
+ The retail calendar starts on the Sunday nearest February 1. By default, the year label is the ending year: a calendar labeled 2029 begins at the anchor Sunday nearest February 1, 2028.
4
+
5
+ ```ruby
6
+ fiscal = MakeACalendar.fiscal_calendar(year: 2029, pattern: :four_four_five)
7
+ puts fiscal.to_h
8
+ puts fiscal.period_for(Date.new(2029, 1, 10)).number
9
+ ```
10
+
11
+ The 12 periods repeat the selected 4-4-5, 4-5-4, or 5-4-4 week sequence. A 53rd week goes to period 12 unless `extra_week: :first_period` is selected. Organizations can use different fiscal anchors or adjustment policies; this implementation does not claim universal accounting compatibility.
@@ -0,0 +1,12 @@
1
+ # Getting started
2
+
3
+ Install `make_a_calendar_toolkit`, require `make_a_calendar`, and call the same API from scripts, services, or Rails applications. Runtime code has no external gem dependencies and performs no network requests.
4
+
5
+ ```ruby
6
+ require "make_a_calendar"
7
+
8
+ calendar = MakeACalendar.month(year: 2027, month: 10, week_start: :monday)
9
+ File.write("october.svg", calendar.to_svg)
10
+ ```
11
+
12
+ For command-line use, install the gem then run `make-calendar --help`. By default, commands print to standard output; `--output FILE` writes a file and refuses to overwrite it unless `--force` is given.
data/docs/holidays.md ADDED
@@ -0,0 +1,7 @@
1
+ # US federal holiday dates
2
+
3
+ `MakeACalendar.federal_holidays(year)` returns `Holiday` entries with a legal date and a weekend-observed date. The model covers federal holidays in the modern statutory era and distinguishes important changes: Memorial Day's pre-1971 May 30 date, Washington's Birthday's pre-1971 February 22 date, Columbus Day from 1971, Veterans Day's 1971–1977 October observance, Juneteenth from 2021, and Thanksgiving's 1939 move to the fourth Thursday.
4
+
5
+ The older Thanksgiving dates use a recurring November rule as a practical calendar approximation; Presidential proclamations varied in some early years. This is not an authoritative legal history or a state, bank, or employer closure calendar. Supply custom `Date` values or `Holiday` objects when a caller follows other rules.
6
+
7
+ For a range spanning year boundaries, `Holidays.observed_dates(first_year, last_year)` includes adjacent legal years so a New Year's observed date on December 31 is available.
@@ -0,0 +1,5 @@
1
+ # iCalendar export
2
+
3
+ `MakeACalendar.to_ics(events, name: ...)` writes date-only VEVENT entries with a one-day exclusive `DTEND`. It escapes text fields, folds lines at the RFC 5545 octet limit, and writes CRLF separators. UIDs are deterministic for an ordered input list unless an event supplies one. `DTSTAMP` records the export time.
4
+
5
+ This subset omits `VTIMEZONE`, timed events, and recurrence rules. Use it for all-day planning data, not for local-time meeting schedules where daylight-saving behavior matters.
@@ -0,0 +1,12 @@
1
+ # Online calendar resources
2
+
3
+ This gem is an offline Ruby library. For interactive browser workflows, the creator also maintains [Make a Calendar](https://make-a-calendar.com/).
4
+
5
+ - [Monthly calendars](https://make-a-calendar.com/monthly-calendars) provides customizable month pages and printable layouts.
6
+ - [Date tools](https://make-a-calendar.com/date-tools) groups business-day, pay-period, shift, and fiscal calculators.
7
+ - [Business-day calculator](https://make-a-calendar.com/business-days-calculator) counts weekdays with observed US federal holidays.
8
+ - [4-4-5 calendar](https://make-a-calendar.com/445-calendar) documents the site's retail calendar generator.
9
+ - [Date converters](https://make-a-calendar.com/converters) covers timestamp and spreadsheet formats.
10
+ - [iCalendar generator](https://make-a-calendar.com/ical-generator) builds all-day calendar files in the browser.
11
+
12
+ These links are contextual resources; the Ruby toolkit uses its own original implementation and does not access the website.
@@ -0,0 +1,5 @@
1
+ # Payroll schedules
2
+
3
+ `Scheduling.pay_dates` supports weekly and biweekly anchors plus semi-monthly and monthly schedules. Semi-monthly defaults to the 15th and the month's last day. Monthly schedules use the anchor's day and clamp to the last day in shorter months.
4
+
5
+ Choose a non-working-day adjustment explicitly: `:none`, `:following`, `:preceding`, or `:modified_following`. Pass weekend dates and holiday dates as appropriate to the organization. No adjustment should be assumed to match every payroll contract.
@@ -0,0 +1,11 @@
1
+ # Printable calendars
2
+
3
+ Monthly SVG output uses a fixed page viewBox and scalable geometry. HTML output adds print CSS for A4/Letter paper in portrait or landscape. The `:ink_saver` theme uses a white background and dark lines; `:editorial`, `:business`, and `:academic` adjust the color palette. No remote fonts, logos, or tracking are added.
4
+
5
+ ```ruby
6
+ calendar = MakeACalendar.month(year: 2027, month: 10, week_start: :monday, fixed_rows: 6)
7
+ File.write("planner.svg", calendar.to_svg(theme: :ink_saver, page_size: :a4_landscape))
8
+ File.write("planner.html", calendar.to_html(theme: :business, page_size: :letter))
9
+ ```
10
+
11
+ SVG and HTML are provided; PDF and PNG are not. Print the HTML in a browser or use an external converter selected by your application.
@@ -0,0 +1,7 @@
1
+ # Pay dates and shift rotations
2
+
3
+ `Scheduling.pay_dates` creates weekly, biweekly, semi-monthly, or monthly dates. Weekly schedules use a seven-day anchor interval; biweekly uses fourteen days. Semi-monthly dates default to the 15th and month end. Monthly dates preserve the anchor's day and clamp to the last day in shorter months. The caller chooses weekend/holiday handling.
4
+
5
+ `Scheduling.shift_dates` accepts alternating on/off block lengths. `"2-2-3"` means two on, two off, three on, then the cycle repeats. An anchor date establishes cycle day 1. The library returns civil dates and does not infer shift duration, timezone, or daylight-saving behavior.
6
+
7
+ Generated date ranges are limited to 100 years to keep accidental oversized requests bounded.
@@ -0,0 +1,3 @@
1
+ # October 2027 monthly calendar as print-friendly SVG.
2
+ require "make_a_calendar"
3
+ puts MakeACalendar.month(year: 2027, month: 10).to_svg(theme: :ink_saver)
@@ -0,0 +1,3 @@
1
+ # Twelve-month 2027 calendar on a single SVG page.
2
+ require "make_a_calendar"
3
+ puts MakeACalendar.year(year: 2027).to_svg
@@ -0,0 +1,4 @@
1
+ # Legal and observed US federal holidays for 2027.
2
+ require "json"
3
+ require "make_a_calendar"
4
+ puts JSON.pretty_generate(MakeACalendar.federal_holidays(2027).map(&:to_h))
@@ -0,0 +1,4 @@
1
+ # Add 30 weekdays after a date, excluding observed federal holidays.
2
+ require "make_a_calendar"
3
+ holidays = MakeACalendar::Holidays.observed_dates(2027)
4
+ puts MakeACalendar.add_business_days("2027-02-01", 30, holidays: holidays)
@@ -0,0 +1,4 @@
1
+ # Generate a biweekly Friday payroll schedule.
2
+ require "make_a_calendar"
3
+ dates = MakeACalendar::Scheduling.pay_dates(start_date: "2027-01-01", end_date: "2027-12-31", frequency: :biweekly, anchor: "2027-01-01", adjust: :preceding)
4
+ puts dates.map(&:iso8601)
@@ -0,0 +1,4 @@
1
+ # Repeat a 2-on, 2-off, 3-on rotation over January 2027.
2
+ require "make_a_calendar"
3
+ rows = MakeACalendar::Scheduling.shift_dates(start_date: "2027-01-01", end_date: "2027-01-31", pattern: "2-2-3", anchor: "2027-01-01")
4
+ puts rows.select { |row| row[:on_duty] }.map { |row| row[:date].iso8601 }
@@ -0,0 +1,4 @@
1
+ # NRF-style fiscal periods labeled by their ending year.
2
+ require "json"
3
+ require "make_a_calendar"
4
+ puts JSON.pretty_generate(MakeACalendar.fiscal_calendar(year: 2029, pattern: :four_four_five).to_h)
@@ -0,0 +1,3 @@
1
+ # Convert an Excel 1900-system serial date.
2
+ require "make_a_calendar"
3
+ puts MakeACalendar::Converters.excel(45_000, system: "1900")
@@ -0,0 +1,3 @@
1
+ # Convert Windows FILETIME ticks to UTC.
2
+ require "make_a_calendar"
3
+ puts MakeACalendar::Converters.filetime("134000000000000000").utc.iso8601
@@ -0,0 +1,4 @@
1
+ # Export 2027 observed federal holidays as date-only iCalendar events.
2
+ require "make_a_calendar"
3
+ events = MakeACalendar.federal_holidays(2027).map { |holiday| { date: holiday.observed_date, summary: holiday.name } }
4
+ print MakeACalendar.to_ics(events, name: "US Federal Holidays 2027")
@@ -0,0 +1,8 @@
1
+ # A service object for a Rails app; Rails itself is not required to run this example.
2
+ require "make_a_calendar"
3
+ class MonthlyCalendarService
4
+ def self.call(year:, month:)
5
+ MakeACalendar.month(year: year, month: month, week_start: :monday).to_html(theme: :business)
6
+ end
7
+ end
8
+ puts MonthlyCalendarService.call(year: 2027, month: 10).include?("<table>")
@@ -0,0 +1,3 @@
1
+ # A fixed six-row black-and-white planner with Monday-first weeks.
2
+ require "make_a_calendar"
3
+ puts MakeACalendar.month(year: 2027, month: 10, week_start: :monday, fixed_rows: 6).to_svg(theme: :ink_saver, page_size: :a4_landscape)