aboutsummaryrefslogtreecommitdiff
path: root/lib/kernel/calendar.mli
blob: 9fbd7e74253ba21787e0eefc9622b111cbcadc8f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
(** Resolution across a whole liturgical year (spec §2.4).

    Transfers make per-date resolution impossible to do correctly: resolving
    25 March can push a feast onto 26 March, and RG 97-98 has coinciding
    I-class feasts transfer in table order, which needs global knowledge of
    the whole year. So [year] is the primitive -- it resolves every date in
    one pass -- and [day] is derived: it finds the liturgical year containing
    a date and indexes into it. Both are pure; neither caches.

    Once every day's temporal-vs-sanctoral contest is resolved, [year] places
    every deferred candidate (RG 96-98): a losing I-class candidate the
    rite's rules send to [Precedence.Transfer] does not stay put -- it moves
    to the next day [rite.transfer_target] names as admissible, and both
    ends of the move are recorded ([transferred_in] on the day it arrives,
    [transferred_out] on the day it left). Every deferred candidate is
    accounted for exactly once: placed, or -- only if the placement fixed
    point is not reached within the round guard, which nothing in the 1962
    calendar is expected to trigger -- left in [Liturgical_day.omitted] with
    a reason that says so, never silently dropped. See [calendar.ml]'s
    [place_transfers] for the algorithm and its termination argument. *)

(** [year rite layer y] resolves every day of the liturgical year that opens
    in civil year [y]: from [rite.year_start y] through the day before
    [rite.year_start (y + 1)], inclusive of both ends.

    Total over 1583..9999, including the boundary years, and beyond them too:
    [y] is clamped to [1582, 9999] before either bound is computed (not just
    guarded near the two edges independently -- see [year_bounds] in
    [calendar.ml] for why that distinction matters), so [year] never raises
    regardless of the [y] it is given, not only for values near the domain
    edge.
    - At [y] = 9999, [rite.year_start (y + 1)] would ask for civil year
      10000, out of {!Date}'s domain (this is the bug Plan 2 shipped in
      [Validate] and later fixed). The end of the walk clamps to 31 December
      9999 instead of computing that call; the returned year comes back
      truncated to whatever the rite's own temporal cycle covers between
      [rite.year_start 9999] and the last day of that civil year, not
      un-computable.
    - Symmetrically, [y] < 1583 clamps the start of the walk to 1 January
      1583 instead of calling [rite.year_start y] on an out-of-domain civil
      year. [year] is never called this way directly by anything in this
      module; {!day} is the only caller that can reach [y] = 1582 (one below
      the floor, never lower), when the date it was asked about sits in civil
      year 1583 before that year's own [rite.year_start] -- i.e. the sliver
      whose true liturgical year opened in civil year 1582, which the domain
      cannot represent. Calling [year] with such a [y] directly is also safe:
      it returns exactly that truncated sliver. *)
val year : ('s, 'r) Rite.t -> 'r Layer.t -> int -> ('s, 'r) Liturgical_day.t array

(** [day rite layer date] finds the liturgical year containing [date] -- the
    year [y] with [rite.year_start y <= date < rite.year_start (y + 1)] --
    and returns its slot for [date]. Recomputes that whole year on every
    call: pure, no cache, no mutable state. Acceptable cost for the natural
    usage (dump a year, sweep years for validation), which pays it once. *)
val day : ('s, 'r) Rite.t -> 'r Layer.t -> Date.t -> ('s, 'r) Liturgical_day.t