[{"data":1,"prerenderedAt":525},["ShallowReactive",2],{"navigation_docs":3,"landing":101},[4,23,66],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":22},"Guide","i-lucide-book-open","\u002Fguide","1.guide",[10,14,18],{"title":11,"path":12,"stem":13},"Introduction","\u002Fguide\u002Fintroduction","1.guide\u002F1.introduction",{"title":15,"path":16,"stem":17},"Getting started","\u002Fguide\u002Fgetting-started","1.guide\u002F2.getting-started",{"title":19,"path":20,"stem":21},"Pieces and sets","\u002Fguide\u002Fpieces-and-sets","1.guide\u002F3.pieces-and-sets",false,{"title":24,"icon":25,"path":26,"stem":27,"children":28,"page":-1},"Design (ADRs)","i-lucide-drafting-compass","\u002Fdesign","2.design",[29,32],{"title":30,"path":26,"stem":31},"Design decisions (ADRs)","2.design\u002Findex",{"title":33,"icon":34,"path":35,"stem":36,"children":37,"page":22},"Decision records","i-lucide-scroll-text","\u002Fdesign\u002Fadrs","2.design\u002Fadrs",[38,42,46,50,54,58,62],{"title":39,"path":40,"stem":41},"ADR-001: The refinement-chain model for calendar points","\u002Fdesign\u002Fadrs\u002F001-refinement-chain","2.design\u002Fadrs\u002F001-refinement-chain",{"title":43,"path":44,"stem":45},"ADR-002: Sets first — the Span algebra","\u002Fdesign\u002Fadrs\u002F002-set-primary-spans","2.design\u002Fadrs\u002F002-set-primary-spans",{"title":47,"path":48,"stem":49},"ADR-003: Overflow policy — clamp by default, skip on request","\u002Fdesign\u002Fadrs\u002F003-overflow-policy","2.design\u002Fadrs\u002F003-overflow-policy",{"title":51,"path":52,"stem":53},"ADR-004: Fortnights as every-k scopes","\u002Fdesign\u002Fadrs\u002F004-fortnight-scopes","2.design\u002Fadrs\u002F004-fortnight-scopes",{"title":55,"path":56,"stem":57},"ADR-005: One denotation function, and what DST does to it","\u002Fdesign\u002Fadrs\u002F005-shared-denotation","2.design\u002Fadrs\u002F005-shared-denotation",{"title":59,"path":60,"stem":61},"ADR-006: Zocam is a standalone, released library","\u002Fdesign\u002Fadrs\u002F006-standalone-library","2.design\u002Fadrs\u002F006-standalone-library",{"title":63,"path":64,"stem":65},"ADR-007: A set is one value — struct answers, enumerable shapes","\u002Fdesign\u002Fadrs\u002F007-one-value-sets","2.design\u002Fadrs\u002F007-one-value-sets",{"title":67,"path":68,"stem":69,"children":70,"icon":100},"API Reference","\u002Fapi","3.api\u002Findex",[71,72,76,80,84,88,92,96],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75},"Zocam","\u002Fapi\u002Fzocam","3.api\u002Fzocam",{"title":77,"path":78,"stem":79},"Zocam.Intervals","\u002Fapi\u002Fzocam-intervals","3.api\u002Fzocam-intervals",{"title":81,"path":82,"stem":83},"Zocam.ISO","\u002Fapi\u002Fzocam-iso","3.api\u002Fzocam-iso",{"title":85,"path":86,"stem":87},"Zocam.Point","\u002Fapi\u002Fzocam-point","3.api\u002Fzocam-point",{"title":89,"path":90,"stem":91},"Zocam.Point.ComposeError","\u002Fapi\u002Fzocam-point-composeerror","3.api\u002Fzocam-point-composeerror",{"title":93,"path":94,"stem":95},"Zocam.Span","\u002Fapi\u002Fzocam-span","3.api\u002Fzocam-span",{"title":97,"path":98,"stem":99},"Zocam.Span.Arc","\u002Fapi\u002Fzocam-span-arc","3.api\u002Fzocam-span-arc","i-lucide-braces",{"id":102,"title":103,"body":104,"description":103,"extension":517,"meta":518,"navigation":351,"path":519,"seo":520,"stem":523,"__hash__":524},"landing\u002Findex.md","",{"type":105,"value":106,"toc":513},"minimark",[107,167,186,191,255,260,305,313,317,320,451,459,509],[108,109,110,120,129,154],"u-page-hero",{},[111,112,113],"template",{"v-slot:headline":103},[114,115],"img",{"alt":116,"className":117,"src":119},"The zocam mark: turning orbit rings around one point.",[118],"hero-mark","\u002Fmark.svg",[111,121,122,123],{"v-slot:title":103},"ZOCAM",[124,125,128],"span",{"className":126},[127],"cursor","_",[111,130,131,148],{"v-slot:description":103},[132,133,134,135,139,140,143,144,147],"p",{},"Composable time for Elixir. ",[136,137,138],"code",{},"Point"," names a calendar thing, ",[136,141,142],{},"Span"," builds sets of instants over points, and ",[136,145,146],{},"ground\u002F3"," maps a set to concrete intervals in a timezone — DST included.",[132,149,150,153],{},[151,152,73],"em",{}," is the Muisca year: a cycle of twenty moons, recorded in colonial Bogotá and later studied by Humboldt. A library about calendars carries a calendar word.",[111,155,156,163],{"v-slot:links":103},[157,158,162],"u-button",{"color":159,"size":160,"to":12,"trailing-icon":161},"neutral","xl","i-lucide-arrow-right","Get started",[157,164,166],{"color":159,"size":160,"to":68,"variant":165},"outline","API reference",[168,169,172,177,178,185],"div",{"className":170},[171],"board-note",[124,173,176],{"className":174},[175],"ai-slop","AI SLOP"," An AI agent wrote this page. ",[179,180,184],"a",{"href":181,"rel":182},"https:\u002F\u002Fgithub.com\u002Fyuri4n",[183],"nofollow","yuri4n",", a senior engineer, gave the direction and did the review. The review is human, thus errors can stay.",[187,188,190],"h2",{"id":189},"the-two-layers","The two layers",[192,193,194,210],"table",{},[195,196,197],"thead",{},[198,199,200,204,207],"tr",{},[201,202,203],"th",{},"Layer",[201,205,206],{},"Module",[201,208,209],{},"What it holds",[211,212,213,228,241],"tbody",{},[198,214,215,219,225],{},[216,217,218],"td",{},"Calendar",[216,220,221],{},[179,222,223],{"href":86},[136,224,85],{},[216,226,227],{},"One calendar thing: \"May\", \"the 23rd\", \"15:00\"",[198,229,230,232,238],{},[216,231,218],{},[216,233,234],{},[179,235,236],{"href":94},[136,237,93],{},[216,239,240],{},"Sets of instants: arcs, steps, ordinals, set algebra",[198,242,243,246,252],{},[216,244,245],{},"Timeline",[216,247,248],{},[179,249,250],{"href":78},[136,251,77],{},[216,253,254],{},"Concrete intervals: union, intersection, complement, diff",[132,256,257],{},[151,258,259],{},"Figure 1 — The two layers of the library and the module that owns each. AI generated, human reviewed.",[261,262,266],"pre",{"className":263,"code":264,"language":265,"meta":103,"style":103},"language-mermaid shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","flowchart LR\n  P[\"Zocam.Point\u003Cbr\u002F>one calendar thing\u003Cbr\u002F>(May · the 23rd · 15:00)\"]\n  S[\"Zocam.Span\u003Cbr\u002F>sets of instants\u003Cbr\u002F>(arcs · steps · nth · algebra)\"]\n  I[\"Zocam.Intervals\u003Cbr\u002F>concrete intervals\u003Cbr\u002F>on the timeline\"]\n  P -- \"Span.of\u002F1 · arc!\u002F1\" --> S\n  S -- \"ground\u002F3 (timezone, DST)\" --> I\n","mermaid",[136,267,268,275,281,287,293,299],{"__ignoreMap":103},[124,269,272],{"class":270,"line":271},"line",1,[124,273,274],{},"flowchart LR\n",[124,276,278],{"class":270,"line":277},2,[124,279,280],{},"  P[\"Zocam.Point\u003Cbr\u002F>one calendar thing\u003Cbr\u002F>(May · the 23rd · 15:00)\"]\n",[124,282,284],{"class":270,"line":283},3,[124,285,286],{},"  S[\"Zocam.Span\u003Cbr\u002F>sets of instants\u003Cbr\u002F>(arcs · steps · nth · algebra)\"]\n",[124,288,290],{"class":270,"line":289},4,[124,291,292],{},"  I[\"Zocam.Intervals\u003Cbr\u002F>concrete intervals\u003Cbr\u002F>on the timeline\"]\n",[124,294,296],{"class":270,"line":295},5,[124,297,298],{},"  P -- \"Span.of\u002F1 · arc!\u002F1\" --> S\n",[124,300,302],{"class":270,"line":301},6,[124,303,304],{},"  S -- \"ground\u002F3 (timezone, DST)\" --> I\n",[132,306,307],{},[151,308,309,310,312],{},"Figure 2 — The two layers and the one crossing point: a span meets the real timeline only in ",[136,311,146],{},". AI generated, human reviewed.",[187,314,316],{"id":315},"one-recipe","One recipe",[132,318,319],{},"You want every second Friday, 09:00–12:00, as concrete UTC intervals. Name the day, set the rhythm, cut the hours, intersect, and ground:",[261,321,325],{"className":322,"code":323,"language":324,"meta":103,"style":103},"language-elixir shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","fridays =\n  Zocam.Point.weekday(:friday)\n  |> Zocam.Point.every(2, ~D[2026-01-02])\n  |> Zocam.Span.of()\n\nmorning =\n  Zocam.Span.arc!(\n    from: Zocam.Point.time(~T[09:00:00]),\n    until: Zocam.Point.time(~T[12:00:00])\n  )\n\nspan = Zocam.Span.intersection([fridays, morning])\n\nhorizon = %{\n  from: ~U[2026-01-01 00:00:00Z],\n  until: ~U[2026-02-01 00:00:00Z],\n  left: :closed,\n  right: :open\n}\n\nZocam.Span.ground(span, horizon, \"Etc\u002FUTC\").intervals\n#=> Jan 2, Jan 16, and Jan 30 — each 09:00–12:00 UTC\n","elixir",[136,326,327,332,337,342,347,353,358,364,370,376,382,387,393,398,404,410,416,422,428,434,439,445],{"__ignoreMap":103},[124,328,329],{"class":270,"line":271},[124,330,331],{},"fridays =\n",[124,333,334],{"class":270,"line":277},[124,335,336],{},"  Zocam.Point.weekday(:friday)\n",[124,338,339],{"class":270,"line":283},[124,340,341],{},"  |> Zocam.Point.every(2, ~D[2026-01-02])\n",[124,343,344],{"class":270,"line":289},[124,345,346],{},"  |> Zocam.Span.of()\n",[124,348,349],{"class":270,"line":295},[124,350,352],{"emptyLinePlaceholder":351},true,"\n",[124,354,355],{"class":270,"line":301},[124,356,357],{},"morning =\n",[124,359,361],{"class":270,"line":360},7,[124,362,363],{},"  Zocam.Span.arc!(\n",[124,365,367],{"class":270,"line":366},8,[124,368,369],{},"    from: Zocam.Point.time(~T[09:00:00]),\n",[124,371,373],{"class":270,"line":372},9,[124,374,375],{},"    until: Zocam.Point.time(~T[12:00:00])\n",[124,377,379],{"class":270,"line":378},10,[124,380,381],{},"  )\n",[124,383,385],{"class":270,"line":384},11,[124,386,352],{"emptyLinePlaceholder":351},[124,388,390],{"class":270,"line":389},12,[124,391,392],{},"span = Zocam.Span.intersection([fridays, morning])\n",[124,394,396],{"class":270,"line":395},13,[124,397,352],{"emptyLinePlaceholder":351},[124,399,401],{"class":270,"line":400},14,[124,402,403],{},"horizon = %{\n",[124,405,407],{"class":270,"line":406},15,[124,408,409],{},"  from: ~U[2026-01-01 00:00:00Z],\n",[124,411,413],{"class":270,"line":412},16,[124,414,415],{},"  until: ~U[2026-02-01 00:00:00Z],\n",[124,417,419],{"class":270,"line":418},17,[124,420,421],{},"  left: :closed,\n",[124,423,425],{"class":270,"line":424},18,[124,426,427],{},"  right: :open\n",[124,429,431],{"class":270,"line":430},19,[124,432,433],{},"}\n",[124,435,437],{"class":270,"line":436},20,[124,438,352],{"emptyLinePlaceholder":351},[124,440,442],{"class":270,"line":441},21,[124,443,444],{},"Zocam.Span.ground(span, horizon, \"Etc\u002FUTC\").intervals\n",[124,446,448],{"class":270,"line":447},22,[124,449,450],{},"#=> Jan 2, Jan 16, and Jan 30 — each 09:00–12:00 UTC\n",[132,452,453,454,458],{},"The same recipe opens the ",[179,455,456],{"href":94},[136,457,93],{}," reference, where it runs as a doctest — the test suite proves it stays true.",[460,461,462,465],"u-page-section",{},[111,463,464],{"v-slot:title":103},"One denotation, two questions",[111,466,467,479,490],{"v-slot:features":103},[468,469,471,474],"u-page-feature",{"icon":470,"to":86},"i-lucide-milestone",[111,472,473],{"v-slot:title":103},"Points: calendar values",[111,475,476,478],{"v-slot:description":103},[136,477,85],{}," models one calendar thing as a scope plus a refinement chain — concrete (\"May 2026\") or abstract (\"May\"). The shape of a point is a design decision on its own: see ADR-001.",[468,480,482,485],{"icon":481,"to":94},"i-lucide-route",[111,483,484],{"v-slot:title":103},"Spans: sets of instants",[111,486,487,489],{"v-slot:description":103},[136,488,93],{}," is a recursive set algebra over points and arcs: unions, intersections, complements, steps, and ordinal picks such as \"last working day of the month\". Sets come first; single moments are the special case.",[468,491,493,496],{"icon":492,"to":78},"i-lucide-train-track",[111,494,495],{"v-slot:title":103},"The interval kernel",[111,497,498,500,501,504,505,508],{"v-slot:description":103},[136,499,77],{}," is the linear kernel: sets of concrete intervals with union, intersection, complement, and difference. ",[136,502,503],{},"Span.member?\u002F2"," and ",[136,506,507],{},"Span.ground\u002F3"," share ONE denotation function, so the two answers can never disagree — even across a DST jump.",[510,511,512],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":103,"searchDepth":277,"depth":277,"links":514},[515,516],{"id":189,"depth":277,"text":190},{"id":315,"depth":277,"text":316},"md",{},"\u002F",{"title":521,"description":522},"Zocam — composable time for Elixir","A time library for Elixir: calendar points, span algebra over sets of instants, and an interval kernel. Grounded in a timezone, correct across DST.","index","q_pUq_Olt704S591RYu3LSZ1ZOXqrbryzB2bk-Vmn1o",1786316011573]