[{"data":1,"prerenderedAt":535},["ShallowReactive",2],{"navigation_docs":3,"-api-zocam":101,"-api-zocam-surround":530},[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},"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":73,"body":103,"description":523,"extension":524,"links":525,"meta":526,"navigation":527,"path":74,"seo":528,"stem":75,"__hash__":529},"docs\u002F3.api\u002Fzocam.md",{"type":104,"value":105,"toc":506},"minimark",[106,129,138,141,146,156,219,225,229,261,265,284,339,346,360,366,372,396,402,405,411,437,443,457,463,467,478,484,493,496],[107,108,109,115,116,120,121,128],"p",{},[110,111,114],"span",{"className":112},[113],"ai-slop","AI SLOP"," An AI agent wrote the docstrings; ",[117,118,119],"code",{},"mix docs"," generated this page. ",[122,123,127],"a",{"href":124,"rel":125},"https:\u002F\u002Fgithub.com\u002Fyuri4n",[126],"nofollow","yuri4n",", a senior engineer, gave the direction and did the review. The review is human, thus errors can stay.",[107,130,131],{},[122,132,137],{"href":133,"rel":134,"className":135},"https:\u002F\u002Fgithub.com\u002Fyuri4n\u002Fzocam\u002Fblob\u002Fmain\u002Flib\u002Fzocam.ex#L13",[126],[136],"source-link","Source on GitHub ↗",[107,139,140],{},"A three-layer library for time: calendar things, sets of them, and\nconcrete intervals.",[142,143,145],"h2",{"id":144},"the-layers","The layers",[147,148,153],"pre",{"className":149,"code":151,"language":152},[150],"language-text","Zocam.Point ──▶ Zocam.Span ──▶ Zocam.Intervals\n(calendar        (sets: arcs,     (linear kernel:\n things:          unions,          concrete interval\n \"May\",           steps,           sets on the real\n \"the 23rd\",      nth, ...)        timeline)\n \"15:00\")\n","text",[117,154,151],{"__ignoreMap":155},"",[157,158,159,185,214],"ul",{},[160,161,162,164,165,168,169,172,173,176,177,180,181,184],"li",{},[117,163,85],{}," models one \"thing about time\": concrete\n(",[117,166,167],{},"\"May 2026\"",") or abstract (",[117,170,171],{},"\"May\"","). Points compose:\n",[117,174,175],{},"\"Jan\""," + ",[117,178,179],{},"\"the 23rd\""," = ",[117,182,183],{},"\"Jan 23, yearly\"",".",[160,186,187,189,190,194,195,198,199,202,203,206,207,210,211,184],{},[117,188,93],{}," models ",[191,192,193],"em",{},"sets"," of instants built from points: arcs\nwith closings and steps (",[117,196,197],{},"\"Fri..Mon\"",", ",[117,200,201],{},"\"every 15 minutes\"","),\nunions, intersections, complements, and ordinal selection\n(",[117,204,205],{},"\"last working day of the month\"","). Its two interpreters are\n",[117,208,209],{},"Zocam.Span.member?\u002F2"," and ",[117,212,213],{},"Zocam.Span.ground\u002F3",[160,215,216,218],{},[117,217,77],{}," is the linear kernel: concrete interval sets\nwith union, intersection, complement, and difference. Everything\na span grounds to lands here.",[107,220,221,222,224],{},"The calendar meets the real timeline in exactly one place:\n",[117,223,213],{}," resolves wall times in a timezone, which is\nwhere DST folds (a wall hour that exists twice) and gaps (a wall\nhour that never exists) are handled.",[142,226,228],{"id":227},"one-calendar","One calendar",[107,230,231,232,235,236,239,240,243,244,198,247,198,250,253,254,257,258,260],{},"zocam reads and writes ",[117,233,234],{},"Calendar.ISO"," numbers only: ",[117,237,238],{},":january"," is\nmonth 1, ",[117,241,242],{},":monday"," is weekday 1, and a year is a Gregorian year. A\n",[117,245,246],{},"%Date{}",[117,248,249],{},"%Time{}",[117,251,252],{},"%NaiveDateTime{}",", or ",[117,255,256],{},"%DateTime{}"," on any\nother calendar is refused at the function that takes it, with an\nerror that names the calendar and the repair. ",[117,259,81],{}," holds that\nrule and lists every place it is applied.",[142,262,264],{"id":263},"the-four-names","The four names",[107,266,267,268,271,272,275,276,279,280,283],{},"Four types carry all data in this library. Two questions place\neach one. Question one: does the value hold ",[191,269,270],{},"one piece"," of time,\nor a ",[191,273,274],{},"set"," of pieces? Question two: is the value ",[191,277,278],{},"symbolic"," (a\ncalendar shape that repeats, with no timezone), or ",[191,281,282],{},"concrete"," (a\nwindow on the real timeline, timezone already resolved)?",[285,286,287,301],"table",{},[288,289,290],"thead",{},[291,292,293,296,298],"tr",{},[294,295],"th",{},[294,297,270],{},[294,299,300],{},"a set of pieces",[302,303,304,322],"tbody",{},[291,305,306,313,317],{},[307,308,309,312],"td",{},[310,311,278],"strong",{}," (repeats)",[307,314,315],{},[117,316,97],{},[307,318,319],{},[117,320,321],{},"t:Zocam.Span.t\u002F0",[291,323,324,329,334],{},[307,325,326,328],{},[310,327,282],{}," (happens)",[307,330,331],{},[117,332,333],{},"t:Zocam.Intervals.interval\u002F0",[307,335,336],{},[117,337,338],{},"t:Zocam.Intervals.t\u002F0",[340,341,343,345],"h3",{"id":342},"zocamspanarc-one-symbolic-piece",[117,344,97],{}," — one symbolic piece",[107,347,348,349,351,352,355,356,359],{},"An arc is a struct: two bounds (",[117,350,85],{}," chains), one closing\nper side, an optional step, and an overflow policy. It ",[191,353,354],{},"repeats",":\n\"Fri..Mon\" happens once in every week. An arc never travels alone —\nit always sits inside an ",[117,357,358],{},"{:arcs, scope, grain, arcs}"," node of a\nspan, and the node owns the scope:",[147,361,364],{"className":362,"code":363,"language":152},[150],"iex> {:arcs, :week, :day, [arc]} =\n...>   Zocam.Span.arc!(\n...>     from: Zocam.Point.weekday(:friday),\n...>     until: Zocam.Point.weekday(:monday)\n...>   )\niex> {arc.from, arc.until}\n{[weekday: :friday], [weekday: :monday]}\n",[117,365,363],{"__ignoreMap":155},[340,367,369,371],{"id":368},"tzocamspant0-a-symbolic-set",[117,370,321],{}," — a symbolic set",[107,373,374,375,378,379,198,382,198,385,388,389,392,393,395],{},"A span is not a struct. It is a recursive tagged tuple — the\nexpression tree of a set algebra: ",[117,376,377],{},"{:arcs, ...}"," leaves combined\nwith ",[117,380,381],{},"{:union, ...}",[117,383,384],{},"{:intersection, ...}",[117,386,387],{},"{:complement, ...}",",\nand ",[117,390,391],{},"{:nth, ...}",". Even one point lifts to a one-arc ",[191,394,274],{},":",[147,397,400],{"className":398,"code":399,"language":152},[150],"iex> may = Zocam.Span.of(Zocam.Point.month(:may))\niex> match?({:arcs, :year, :month, [%Zocam.Span.Arc{}]}, may)\ntrue\n",[117,401,399],{"__ignoreMap":155},[107,403,404],{},"Why is the set primary, in both layers? Closure. The complement of\none arc is already two pieces, and a difference can cut one piece\ninto two. A lone piece cannot be closed under its own operators, so\nevery operator answers with a set.",[340,406,408,410],{"id":407},"tzocamintervalsinterval0-one-concrete-piece",[117,409,333],{}," — one concrete piece",[107,412,413,414,417,418,421,422,425,426,429,430,433,434,436],{},"A plain map with exactly four keys: ",[117,415,416],{},"%{from, until, left, right}",".\nThe endpoints are ",[117,419,420],{},"Time"," or ",[117,423,424],{},"DateTime"," values (or ",[117,427,428],{},"nil"," for an\nunbounded ray). Nothing repeats here: this window happens once.\nThe ",[117,431,432],{},"horizon"," argument of ",[117,435,213],{}," is exactly one\nsuch interval.",[340,438,440,442],{"id":439},"tzocamintervalst0-a-concrete-set",[117,441,338],{}," — a concrete set",[107,444,445,446,449,450,453,454,456],{},"The ",[117,447,448],{},"%Zocam.Intervals{}"," struct: a list of intervals, kept sorted\nand disjoint by ",[117,451,452],{},"Zocam.Intervals.compress\u002F1",". An empty list inside\nis the empty set. ",[117,455,213],{}," is the bridge from the\nsymbolic column to the concrete column — each arc instance lands as\n0, 1, or 2 concrete pieces (a DST gap, a normal day, a DST fold):",[147,458,461],{"className":459,"code":460,"language":152},[150],"iex> weds = Zocam.Span.of(Zocam.Point.weekday(:wednesday))\niex> may = Zocam.Span.of(Zocam.Point.month(:may))\niex> span = Zocam.Span.intersection([weds, may])\niex> horizon = %{\n...>   from: ~U[2026-05-01 00:00:00Z],\n...>   until: ~U[2026-06-01 00:00:00Z],\n...>   left: :closed,\n...>   right: :open\n...> }\niex> %Zocam.Intervals{intervals: intervals} =\n...>   Zocam.Span.ground(span, horizon, \"Etc\u002FUTC\")\niex> length(intervals)\n4\niex> hd(intervals).from\n~U[2026-05-06 00:00:00Z]\n",[117,462,460],{"__ignoreMap":155},[340,464,466],{"id":465},"one-rule-for-shapes-operations-answer-with-the-set","One rule for shapes: operations answer with the set",[107,468,469,471,472,475,476,395],{},[117,470,77],{}," accepts all three spellings of \"some intervals\" —\none bare map, a plain list, or the struct — and an operation on\nsets always answers with the set struct, whatever shape the\noperands came in. A piece constructor answers with a piece:\n",[117,473,474],{},"Zocam.Intervals.new!\u002F1"," builds one interval map. So \"nothing\nremains\" is always the empty set, never ",[117,477,428],{},[147,479,482],{"className":480,"code":481,"language":152},[150],"iex> block = Zocam.Intervals.new!(from: ~T[09:00:00], until: ~T[17:00:00])\niex> block\n%{from: ~T[09:00:00], until: ~T[17:00:00], left: :closed, right: :open}\niex> Zocam.Intervals.diff(block, block)\n%Zocam.Intervals{intervals: []}\niex> Zocam.Intervals.diff([block], [block])\n%Zocam.Intervals{intervals: []}\n",[117,483,481],{"__ignoreMap":155},[107,485,486,487,492],{},"The design records (the ADR series) are not part of this API\nreference. They live on the documentation site, at\n",[122,488,491],{"href":489,"rel":490},"https:\u002F\u002Fzocam.dev\u002Fdesign",[126],"zocam.dev\u002Fdesign",", because each record is a\nwebsite page with its own diagrams. This reference documents the code;\nthe site documents the decisions behind it.",[494,495],"hr",{},[107,497,498],{},[191,499,500,501,505],{},"Consult ",[122,502,504],{"href":503},"api-reference","api-reference.md"," for complete listing",{"title":155,"searchDepth":507,"depth":507,"links":508},2,[509,510,511],{"id":144,"depth":507,"text":145},{"id":227,"depth":507,"text":228},{"id":263,"depth":507,"text":264,"children":512},[513,516,518,520,522],{"id":342,"depth":514,"text":515},3,"Zocam.Span.Arc — one symbolic piece",{"id":368,"depth":514,"text":517},"t:Zocam.Span.t\u002F0 — a symbolic set",{"id":407,"depth":514,"text":519},"t:Zocam.Intervals.interval\u002F0 — one concrete piece",{"id":439,"depth":514,"text":521},"t:Zocam.Intervals.t\u002F0 — a concrete set",{"id":465,"depth":514,"text":466},"A three-layer library for time: calendar things, sets of them, and concrete intervals.","md",null,{},true,{"title":73,"description":523},"iKeMVwPvOO-elfqqfxjvoiKSUfyteBJ2h9Rv-afOoew",[531,533],{"title":67,"path":68,"stem":69,"description":532,"children":-1},"All public modules of zocam, generated from the Elixir docstrings by mix docs.",{"title":77,"path":78,"stem":79,"description":534,"children":-1},"The linear kernel: sets of concrete intervals on one axis, with union, intersection, complement, and difference.",1786065169577]