---
title: Dec Time
author:
  - name: Martin Laptev
    url: https://maptv.github.io
image: /asset/daywide.svg
description: >
  Introducing Declock, a timekeeping system that displays time in decimal days using math notation without the need for hours, minutes, or seconds.
draft: true
citation:
  url: https://maptv.github.io/dec/time
aliases:
  - /time
  - /dt
license: CC BY-SA
lightbox: false
toc: true
toc-depth: 5
bread-crumbs: false
format:
  html:
    grid:
      body-width: 850px
    shift-heading-level-by: 3
    include-after-body:
      - ../../asset/cite.html
      - ../../asset/style.html
      - ../../asset/stamp.html
      - ../../asset/tooltip.html
  commonmark: default
notebook-view: false
format-links:
  - html
  - text: Quarto markdown (qmd)
    icon: file-code
    href: index.qmd
  - format: commonmark
    text: CommonMark markdown (md)
    icon: file-code
  - text: Python notebook (ipynb)
    icon: file-code
    href: eot.ipynb
filters:
  - ../../asset/date.lua
engine: knitr
---

::: {#timenav}
{{< include /asset/_decnav.qmd >}}
:::

My website provides many examples of the [Quarto](https://quarto.org) publishing and the [Dec](/dec) measurement systems in action. I leverage Quarto support for the [Observable](https://observablehq.com/) data analysis and visualization system to create animated and interactive graphics like the [analog clocks](https://en.wikipedia.org/wiki/Clock#:~:text=indicate%20time%20with%20a%20traditional%20clock%20face%20and%20moving%20hands)🕓, [bar📊charts](https://en.wikipedia.org/wiki/Bar_chart), [solar☀️terminator](https://en.wikipedia.org/wiki/Terminator_%28solar%29#:~:text=a%20moving%20line%20that%20divides%20the%20daylit%20side%20and%20the%20dark%20night%20side%20of%20a%20planetary%20body) map🗺, [Earth🌍orbit](https://en.wikipedia.org/wiki/Earth%27s_orbit) diagram, and [daylight](https://en.wikipedia.org/wiki/Daylight#:~:text=the%20combination%20of%20all%20direct%20and%20indirect%20sunlight%20during%20the%20daytime) [area chart](https://en.wikipedia.org/wiki/Area_chart#:~:text=The%20area%20between%20axis%20and%20line%20are%20commonly%20emphasized%20with%20colors) below.

# Fractional day time {#fdt .hiddenheading}

Dec times are measured in [fractional days](https://en.wikipedia.org/wiki/Decimal_time#Fractional_days:~:text=a%20decimal%20fraction%20of%20a%20day). The shortest, longest, and thinnest clock🕓hands and the top, middle, and bottom bars📊indicate the [decidays](https://en.wikipedia.org/wiki/Decimal_time#:~:text=dividing%20the%20day%20into%2010%20decidays){.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}, [millidays]{.tool data-bs-toggle="tooltip" data-bs-title="thousandths of a day"}, and [centimillidays]{.tool data-bs-toggle="tooltip" data-bs-title="hundred thousandths of a day"}, respectively, of the time since the start, [+\${decTime}]{.point1}, or until the end, [-\${decTimeN}]{.point0}, of the day in the Dec [time zone](https://en.wikipedia.org/wiki/Time_zone#:~:text=an%20area%20which%20observes%20a%20uniform%20standard%20time), \${decZoneHsl}, at the location of the red⭕️circle on the map🗺️beneath the bars📊.

## Ticking analog clocks {#tac .hiddenheading}

::: clocks
\${clock}\${clock1}
:::

## Bar chart clocks {#bcc .hiddenheading}

```{ojs}
//| echo: false
// https://observablehq.com/@fheyen/barchart-clock
barChart = {
  const W = 800;
  const H = 88;
  const barX = 1;
  const firstBarY = 1;
  const svg = d3
    .create("svg")
    .attr("width", W)
    .attr("viewBox", [0, 0, W / 1.14, H]);
  const xRange = [0, W - 100];
  const scaleDD = d3.scaleLinear()
    .domain([0, 10])
    .range(xRange);
  const scaleMandB = d3.scaleLinear()
    .domain([0, 100])
    .range(xRange);
  // Background bars to show where 100% lies
  svg.selectAll('.background')
    .data([
      'dd', "mils", 'beats'])
    .enter()
    .append('rect')
    .attr('class', 'background timeBar')
    .attr('width', W-100)
    .attr('y', (d,i)=>i*30+firstBarY)
  // Beats
  svg
    .append('rect')
    .attr('class', 'timeBar')
    .attr('y', firstBarY+60)
    .attr('width', d => scaleMandB(Number(barBeats)))
  svg
    .append('rect')
    .attr('class', 'timeBarFull')
    .attr('y', firstBarY+60)
    .attr('width', d => scaleMandB(barBeats))
  // Cents/Mils
  svg
    .append('rect')
    .attr('class', 'timeBar')
    .attr('y', firstBarY)
    .attr('width', d => scaleDD(Number(barDD)+Number(barMils)/100+Number(barBeats)/10000))
  svg
    .append('rect')
    .attr('class', 'timeBarFull')
    .attr('y', firstBarY)
    .attr('width', d => scaleDD(barDD))
  svg
    .append('rect')
    .attr('class', 'timeBar')
    .attr('y', firstBarY+30)
    .attr('width', d => scaleMandB(Number(barMils)+Number(barBeats)/100))
  svg
    .append('rect')
    .attr('class', 'timeBarFull')
    .attr('y', firstBarY+30)
    .attr('width', d => scaleMandB(barMils))
  // Cent ticks
  svg.selectAll('.tickC')
    .data(d3.range(width > 500 ? 10 : 10, 100))
    .enter()
    .append('rect')
    .attr('class', 'tickC')
    .attr('x', d=>scaleDD(d/10)+barX)
    .attr('y', firstBarY+30)
    .attr('height', d=>d%2===0? 8:5)
  svg.selectAll('.tickB1')
    .data(d3.range(width > 500 ? 10 : 10, 100))
    .enter()
    .append('rect')
    .attr('class', 'tickB1')
    .attr('x', d=>scaleDD(d/10)+barX)
    .attr('y', d=>d%2===0? firstBarY+77:firstBarY+80)
    .attr('height', d=>d%2===0? 8:5)
  svg.selectAll('.tickC1')
    .data(d3.range(width > 500 ? 10 : 10, 100))
    .enter()
    .append('rect')
    .attr('class', 'tickC1')
    .attr('x', d=>scaleDD(d/10)+barX)
    .attr('y', d=>d%2===0? firstBarY+47:firstBarY+50)
    .attr('height', d=>d%2===0? 8:5)
  // Mil ticks
  svg.selectAll('.tickM')
    .data(d3.range(width > 500 ? 1 : 1, 10))
    .enter()
    .append('rect')
    .attr('class', 'tickM')
    .attr('x', d=>scaleDD(d)+barX)
    .attr('y', firstBarY+20)
    .attr('height', 6)
  svg.selectAll('.tickLabel1')
    .data(d3.range(width > 500 ? 1 : 1, 10))
    .enter()
    .append('text')
    .attr('class', 'tickLabel1')
    .attr('x', d=>scaleDD(d)+barX+.5)
    .attr('y', firstBarY+18)
    //.style("font-size", `{W < 550 ? 12 : W < 650 ? 14 : W < 750 ? 16 : W < 850 ? 18 : 20}px`)
    .text(d=>d)
  // Cent ticks
  svg.selectAll('.tickC2')
    .data(d3.range(width > 500 ? 10 : 10, 100))
    .enter()
    .append('rect')
    .attr('class', 'tickC2')
    .attr('x', d=>scaleDD(d/10)+barX)
    .attr('y', firstBarY+10)
    .attr('height', d=>d%2===0? 9:6)
  // Beat ticks
  svg.selectAll('.tickB')
    .data(d3.range(width > 500 ? 10 : 10, 100))
    .enter()
    .append('rect')
    .attr('class', 'tickB')
    .attr('x', d=>scaleDD(d/10)+barX)
    .attr('y', firstBarY+60)
    .attr('height', d=>d%2===0? 9:6)
  // Labels
  svg.selectAll('.timeLabel')
    .data([`+${barDD}`, `${barMils}`, `${barBeats}`])
    .enter()
    .append('text')
    .attr('class', 'timeLabel')
    .attr('x', barX+2)
    .attr('y', (d,i)=>i*30+firstBarY+20)
    .style("font-size", `${W < 300 ? 14 : W < 400 ? 16 : W < 500 ? 18 : W < 600 ? 20 : 22}px`)
    .text(d=>d);
  svg.attr("id", "topbar");
  svg.attr('class', 'barclock')
  return svg.node();
}
barChart1 = {
  const W = 800;
  const H = 88;
  const barX = 1;
  const firstBarY = 1;
  const svg = d3
    .create("svg")
    .attr("width", W)
    .attr("viewBox", [0, 0, W / 1.14, H]);
  const xRange = [0, W - 100];
  const scaleDD = d3.scaleLinear()
    .domain([0, 10])
    .range(xRange);
  const scaleMandB = d3.scaleLinear()
    .domain([0, 100])
    .range(xRange);
  // const scaleDek = d3.scaleLinear()
  //  .domain([0, 37])
  //  .range(xRange);
  // Background bars to show where 100% lies
  svg.selectAll('.background')
    .data([
      // 'dek', 'dotd',
      'dd', "mils", 'beats'])
    .enter()
    .append('rect')
    .attr('class', 'background timeBar')
    .attr('width', W-100)
    .attr('y', (d,i)=>i*30+firstBarY)
  // Beats
  svg
    .append('rect')
    .attr('class', 'timeBar')
    .attr('y', firstBarY+60)
    .attr('width', d => scaleMandB(Number(barBeatsN)))
  svg
    .append('rect')
    .attr('class', 'timeBarFullN')
    .attr('y', firstBarY+60)
    .attr('width', d => scaleMandB(barBeatsN))
  // Cents/Mils
  svg
    .append('rect')
    .attr('class', 'timeBar')
    .attr('y', firstBarY)
    .attr('width', d => scaleDD(Number(barDDN)+Number(barMilsN)/100+Number(barBeatsN)/10000))
  svg
    .append('rect')
    .attr('class', 'timeBarFullN')
    .attr('y', firstBarY)
    .attr('width', d => scaleDD(barDDN))
  svg
    .append('rect')
    .attr('class', 'timeBar')
    .attr('y', firstBarY+30)
    .attr('width', d => scaleMandB(Number(barMilsN)+Number(barBeatsN)/100))
  svg
    .append('rect')
    .attr('class', 'timeBarFullN')
    .attr('y', firstBarY+30)
    .attr('width', d => scaleMandB(barMilsN))
  // Cent ticks
  svg.selectAll('.tickC')
    .data(d3.range(width > 500 ? 10 : 10, 100))
    .enter()
    .append('rect')
    .attr('class', 'tickC')
    .attr('x', d=>scaleDD(d/10)+barX)
    .attr('y', firstBarY+30)
    .attr('height', d=>d%2===0? 8:5)
  svg.selectAll('.tickB1')
    .data(d3.range(width > 500 ? 10 : 10, 100))
    .enter()
    .append('rect')
    .attr('class', 'tickB1')
    .attr('x', d=>scaleDD(d/10)+barX)
    .attr('y', d=>d%2===0? firstBarY+77:firstBarY+80)
    .attr('height', d=>d%2===0? 8:5)
  svg.selectAll('.tickC1')
    .data(d3.range(width > 500 ? 10 : 10, 100))
    .enter()
    .append('rect')
    .attr('class', 'tickC1')
    .attr('x', d=>scaleDD(d/10)+barX)
    .attr('y', d=>d%2===0? firstBarY+47:firstBarY+50)
    .attr('height', d=>d%2===0? 8:5)
  // Mil ticks
  svg.selectAll('.tickM')
    .data(d3.range(width > 500 ? 1 : 1, 10))
    .enter()
    .append('rect')
    .attr('class', 'tickM')
    .attr('x', d=>scaleDD(d)+barX)
    .attr('y', firstBarY+20)
    .attr('height', 6)
  svg.selectAll('.tickLabel1')
    .data(d3.range(width > 500 ? 1 : 1, 10))
    .enter()
    .append('text')
    .attr('class', 'tickLabel1')
    .attr('x', d=>scaleDD(d)+barX+.5)
    .attr('y', firstBarY+18)
    //.style("font-size", `{W < 350 ? 12 : W < 450 ? 14 : W < 550 ? 16 : W < 650 ? 18 : 20}px`)
    .text(d=>d)
  // Cent ticks
  svg.selectAll('.tickC2')
    .data(d3.range(width > 500 ? 10 : 10, 100))
    .enter()
    .append('rect')
    .attr('class', 'tickC2')
    .attr('x', d=>scaleDD(d/10)+barX)
    .attr('y', firstBarY+10)
    .attr('height', d=>d%2===0? 9:6)
  // Beat ticks
  svg.selectAll('.tickB')
    .data(d3.range(width > 500 ? 10 : 10, 100))
    .enter()
    .append('rect')
    .attr('class', 'tickB')
    .attr('x', d=>scaleDD(d/10)+barX)
    .attr('y', firstBarY+60)
    .attr('height', d=>d%2===0? 9:6)
  // Labels
  svg.selectAll('.timeLabel')
    .data([`-${barDDN}`, `${barMilsN}`, `${barBeatsN}`])
    .enter()
    .append('text')
    .attr('class', 'timeLabel')
    .attr('x', barX+2)
    .attr('y', (d,i)=>i*30+firstBarY+20)
    .style("font-size", `${W < 300 ? 14 : W < 400 ? 16 : W < 500 ? 18 : W < 600 ? 20 : 22}px`)
    .text(d=>d);
  svg.attr("id", "btmbar");
  svg.attr('class', 'barclock')
  return svg.node();
}
```

## Longitude latitude map {#llm .hiddenheading}

```{ojs}
//| echo: false
viewof location = worldMapCoordinates([162, 0], [width * .998, ((21 / 40) * width)])
```

## Daylight area chart {#dac .hiddenheading}

```{ojs}
//| echo: false
// https://observablehq.com/@dbridges/visualizing-seasonal-daylight
app = {
  const svg = d3.select(DOM.svg(width, height * (width < 300 ? .97 : width < 350 ? .96 : width < 400 ? .95 : width < 450 ? .94 : width < 500 ? .93 : width < 550 ? .92 : width < 600 ? .9 : width < 650 ? .86 : width < 700 ? .82 : .78)));
  svg.style("user-select", "none").style("-webkit-user-select", "none").attr("id", "daylightapp");
  const margin = {top: 20, left: 16, right: 16, bottom: 0, inner: 32};
  const contentWidth = width - margin.left - margin.right - margin.inner;
  const columnWidth = contentWidth / 2;
  let selection = {
    date: date2022,
    hour: date2022.getHours()
  }
  const renderPlot = () => {
    svg.selectAll("#plot *").remove();
    svg.select("#plot").call(daylightPlot, {
    vizwidth: columnWidth / (width < 300 ? 1 : width < 400 ? 1.05 : width < 450 ? 1.1 : width < 500 ? 1.15 : width < 550 ? 1.2 : width < 600 ? 1.25 : width < 650 ? 1.3 : width < 700 ? 1.4 : 1.48),
      height: height * (width < 400 ? 1.62 : width < 500 ? 1.6 : width < 700 ? 1.58 : 1.56),
      year: 2022,
      latitude: location[1],
      defaultDate: selection.date,
      defaultHour: selection.hour
    })
  }
  const renderSolarSystem = () => {
    svg.selectAll("#solar-system *").remove();
    svg.selectAll("#solar-system").call(solarSystem,
                                        columnWidth * 2.02,
                                        location,
                                        selection.date,
                                        selection.hour,
                                        window.darkmode);
  }
  // const renderGlobe = () => {
  //   svg.selectAll("#globe *").remove();
  //   svg.selectAll("#globe").call(globe, { vizwidth: columnWidth / 1.28, location, ...selection });
  // }
  const setSelection = (newSelection, forceRender = false) => {
    const prev = {...selection};
    selection = newSelection;
    svg.node().value = selection;
    set(viewof selectedDate, selection.date);
    set(viewof selectedHour, selection.hour);
    if (forceRender) {
      renderPlot();
      renderSolarSystem();
  //    renderGlobe();
    } else if (prev.hour !== selection.hour || prev.date !== selection.date) {
      renderSolarSystem();
  //    renderGlobe();
}
  }
  const plot = svg.append("g")
    .attr("id", "plot")
    .attr("transform", `translate(${margin.left + 0}, ${height / 5 + (width < 600 ? 12 : 5)})`);
  svg.append("g")
    .attr("id", "solar-system")
    .attr("transform", `translate(${margin.left + 12}, ${margin.top + width / 22 - 6 - 5 * (width < 400)})`);
  // svg.append("g")
  //   .attr("id", "globe")
  //   .attr("transform", `translate(${margin.left + margin.inner + columnWidth / 2 + 20}, ${margin.top + height / 1.2 + 4})`);
  setSelection(selection, true);
  const handleDateHourChange = ({ target, detail: { date, hour }}) => {
    if (date != null && hour != null) setSelection({...selection, date, hour});
  }
  svg.node().addEventListener(EventType.DateHourChange, handleDateHourChange, false);
  return svg.node();
}
// https://observablehq.com/@d3/simple-clock
// https://observablehq.com/@drio/lets-build-an-analog-clock
clock = {
  const clockRadius = 200,
    margin = 50,
    w = (clockRadius + margin) * 2,
    h = (clockRadius + margin) * 2,
    hourHandLength = (2 * clockRadius) / 3,
    minuteHandLength = clockRadius,
    secondHandLength = clockRadius - 12,
    secondHandBalance = 30,
    secondTickStart = clockRadius,
    secondTickLength = -10,
    hourTickStart = clockRadius,
    hourTickLength = -18,
    secondLabelRadius = clockRadius + 16,
    secondLabelYOffset = 5,
    hourLabelRadius = clockRadius - 40,
    hourLabelYOffset = 7,
    radians = Math.PI / 180;
  const ten = d3
    .scaleLinear()
    .range([0, 360])
    .domain([0, 10]);
  const sto = d3
    .scaleLinear()
    .range([0, 360])
    .domain([0, 100]);
  const handData = [
    {
      type: "hour",
      value: 0,
      length: -hourHandLength,
      scale: ten
    },
    {
      type: "minute",
      value: 0,
      length: -minuteHandLength,
      scale: sto
    },
    {
      type: "second",
      value: 0,
      length: -secondHandLength,
      scale: sto,
      balance: secondHandBalance
    }
  ];
  function drawClock() {
    // create all the clock elements
    updateData(); //draw them in the correct starting position
    const face = svg
      .append("g")
      .attr("id", "clock-face")
      .attr("transform", `translate(${[w / 2, h / 2]})`);
    // add marks for seconds
    face
      .selectAll(".second-tick")
      .data(d3.range(0, 100))
      .enter()
      .append("line")
      .attr("class", "second-tick")
      .attr("x1", 0)
      .attr("x2", 0)
      .attr("y1", secondTickStart)
      .attr("y2", secondTickStart + secondTickLength)
      .attr("transform", d => `rotate(${sto(d)})`);
    // and labels...
    face
      .selectAll(".second-label")
      .data(d3.range(0, 100, 5))
      .enter()
      .append("text")
      .attr("class", "second-label")
      .attr("text-anchor", "middle")
      .attr("x", d => secondLabelRadius * Math.sin(sto(d) * radians))
      .attr(
        "y",
        d =>
          -secondLabelRadius * Math.cos(sto(d) * radians) + secondLabelYOffset
      )
      .text(d => d);
    // ... and hours
    face
      .selectAll(".hour-tick")
      .data(d3.range(0, 10, 1))
      .enter()
      .append("line")
      .attr("class", "hour-tick")
      .attr("x1", 0)
      .attr("x2", 0)
      .attr("y1", hourTickStart)
      .attr("y2", hourTickStart + hourTickLength)
      .attr("transform", d => `rotate(${ten(d)})`);
    face
      .selectAll(".hour-label")
      .data(d3.range(0, 10, 1))
      .enter()
      .append("text")
      .attr("class", "hour-label")
      .attr("text-anchor", "middle")
      .attr("x", d => hourLabelRadius * Math.sin(ten(d) * radians))
      .attr(
        "y",
        d => -hourLabelRadius * Math.cos(ten(d) * radians) + hourLabelYOffset
      )
      .text(d => d);
    const hands = face.append("g").attr("id", "clock-hands");
    hands
      .selectAll("line")
      .data(handData)
      .enter()
      .append("line")
      .attr("class", d => d.type + "-hand")
      .attr("x1", 0)
      .attr("y1", d => d.balance || 0)
      .attr("x2", 0)
      .attr("y2", d => d.length)
      .attr("transform", d => `rotate(${d.scale(d.value)})`);
    face
      .append("g")
      .attr("id", "face-overlay")
      .append("circle")
      .attr("class", "hands-cover")
      .attr("x", 0)
      .attr("y", 0)
      .attr("r", clockRadius / 20);
  }
  function moveHands() {
    const sel = d3
      .select("#clock-hands-final")
      .selectAll("line")
      .data(handData)
      .transition();
    if (fancySecondsOFF) sel.ease(d3.easeElastic.period(0.5));
    sel.attr("transform", d => `rotate(${d.scale(d.value)})`);
  }
  function updateData() {
    handData[0].value = !fancySecondsOFF ? Math.floor(selectedExact * 10) : decTime[0];
    handData[1].value = !fancySecondsOFF ? Math.floor(selectedExact * 10 % 1 * 100) : decTime.slice(2, 4);
    handData[2].value = !fancySecondsOFF ? selectedExact * 10 % 1 * 100 % 1 * 100 : decTime.slice(4, 6);
  }
  const svg = d3
    .create("svg")
    .attr("viewBox", [0, 0, w, h])
    .style("max-width", `${width / 2.1}px`)
    .attr("class", "analogclock")
    .attr("id", "topclock");
  svg
    .append("text")
    .text(`+${decTime}-${selectedZone}`)
    .attr("x", clockRadius + margin)
    .attr("y", clockRadius * 2 + margin * 2.1)
    .attr("text-anchor", "middle")
    .attr("font-size", 32)
    .attr("font-family", "monospace");
  drawClock();
  // Animation
  const interval = setInterval(
    () => {
      updateData();
      moveHands();
    },
    !fancySecondsOFF ? 10 : 864
  );
  invalidation.then(() => clearInterval(interval));
  return svg.node();
}
clock1 = {
  const clockRadius = 200,
    margin = 50,
    w = (clockRadius + margin) * 2,
    h = (clockRadius + margin) * 2,
    hourHandLength = (2 * clockRadius) / 3,
    minuteHandLength = clockRadius,
    secondHandLength = clockRadius - 12,
    secondHandBalance = 30,
    secondTickStart = clockRadius,
    secondTickLength = -10,
    hourTickStart = clockRadius,
    hourTickLength = -18,
    secondLabelRadius = clockRadius + 16,
    secondLabelYOffset = 5,
    hourLabelRadius = clockRadius - 40,
    hourLabelYOffset = 7,
    radians = Math.PI / 180;
  const ten = d3
    .scaleLinear()
    .range([0, 360])
    .domain([0, 10]);
  const sto = d3
    .scaleLinear()
    .range([0, 360])
    .domain([0, 100]);
  const handData = [
    {
      type: "hour",
      value: 0,
      length: -hourHandLength,
      scale: ten
    },
    {
      type: "minute",
      value: 0,
      length: -minuteHandLength,
      scale: sto
    },
    {
      type: "second",
      value: 0,
      length: -secondHandLength,
      scale: sto,
      balance: secondHandBalance
    }
  ];
  function drawClock() {
    // create all the clock elements
    updateData(); //draw them in the correct starting position
    const face = svg
      .append("g")
      .attr("id", "clock-face")
      .attr("transform", `translate(${[w / 2, h / 2]})`);
    // add marks for seconds
    face
      .selectAll(".second-tick")
      .data(d3.range(0, 100))
      .enter()
      .append("line")
      .attr("class", "second-tick")
      .attr("x1", 0)
      .attr("x2", 0)
      .attr("y1", secondTickStart)
      .attr("y2", secondTickStart + secondTickLength)
      .attr("transform", d => `rotate(${sto(d)})`);
    // and labels...
    face
      .selectAll(".second-label")
      .data(d3.range(0, 100, 5))
      .enter()
      .append("text")
      .attr("class", "second-label")
      .attr("text-anchor", "middle")
      .attr("x", d => secondLabelRadius * Math.sin(sto(d) * radians))
      .attr(
        "y",
        d =>
          -secondLabelRadius * Math.cos(sto(d) * radians) + secondLabelYOffset
      )
      .text(d => d);
    // ... and hours
    face
      .selectAll(".hour-tick")
      .data(d3.range(0, 10, 1))
      .enter()
      .append("line")
      .attr("class", "hour-tick")
      .attr("x1", 0)
      .attr("x2", 0)
      .attr("y1", hourTickStart)
      .attr("y2", hourTickStart + hourTickLength)
      .attr("transform", d => `rotate(${ten(d)})`);
    face
      .selectAll(".hour-label")
      .data(d3.range(0, 10, 1))
      .enter()
      .append("text")
      .attr("class", "hour-label")
      .attr("text-anchor", "middle")
      .attr("x", d => hourLabelRadius * Math.sin(ten(d) * radians))
      .attr(
        "y",
        d => -hourLabelRadius * Math.cos(ten(d) * radians) + hourLabelYOffset
      )
      .text(d => d);
    const hands = face.append("g").attr("id", "clock-hands");
    hands
      .selectAll("line")
      .data(handData)
      .enter()
      .append("line")
      .attr("class", d => d.type + "-hand")
      .attr("x1", 0)
      .attr("y1", d => d.balance || 0)
      .attr("x2", 0)
      .attr("y2", d => d.length)
      .attr("transform", d => `rotate(${d.scale(d.value)})`);
    face
      .append("g")
      .attr("id", "face-overlay")
      .append("circle")
      .attr("class", "hands-cover")
      .attr("x", 0)
      .attr("y", 0)
      .attr("r", clockRadius / 20);
  }
  function moveHands() {
    const sel = d3
      .select("#clock-hands-final")
      .selectAll("line")
      .data(handData)
      .transition();
    if (fancySecondsOFF) sel.ease(d3.easeElastic.period(0.5));
    sel.attr("transform", d => `rotate(${d.scale(d.value)})`);
  }
  function updateData() {
    handData[0].value = !fancySecondsOFF ? Math.floor(selectedExactN * 10) : decTimeN[0];
    handData[1].value = !fancySecondsOFF ? Math.floor(selectedExactN * 10 % 1 * 100) : decTimeN.slice(2, 4);
    handData[2].value = !fancySecondsOFF ? selectedExactN * 10 % 1 * 100 % 1 * 100 : decTimeN.slice(4, 6);
  }
  const svg = d3
    .create("svg")
    .attr("viewBox", [0, 0, w, h])
    .style("max-width", `${width / 2.1}px`)
    .attr("class", "analogclock")
    .attr("id", "btmclock");
  svg
    .append("text")
    .text(`-${decTimeN}-${selectedZone}`)
    .attr("x", clockRadius + margin)
    .attr("y", clockRadius * 2 + margin * 2.1)
    .attr("text-anchor", "middle")
    .attr("font-size", 32)
    .attr("font-family", "monospace");
  drawClock();
  // Animation
  const interval = setInterval(
    () => {
      updateData();
      moveHands();
    },
    !fancySecondsOFF ? 10 : 864
  );
  invalidation.then(() => clearInterval(interval));
  return svg.node();
}
```

To rotate the globe🌐in the Earth🌏orbit diagram, drag the red⭕️circle horizontally↔️or slide the red🔴dot on the daylight area chart vertically↕. The red⭕️circle's vertical↕position determines the yearly daylight pattern visualized by the area chart. Shift the red<font color=red>—</font>line on the area chart horizontally↔️to move the globe🌐along the ellipse of the Earth🌎orbit.

## Yearly day aggregate (yda) {#yda .hiddenheading}

The red<font color=red>—</font>line indicates a "day of year" ([doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"}), \${selDateHsl}, and the red🔴dot denotes a "time of day" ([tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}): \${selTimeDay}. A [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} identifies a day in a year like a [Gregorian calendar](https://en.wikipedia.org/wiki/Gregorian_calendar#:~:text=the%20calendar%20used%20in%20most%20parts%20of%20the%20world) month and "day of month" ([dom]{.tool data-bs-toggle="tooltip" data-bs-title="day of month"}). A [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} specifies a point in a day like an "hour minute second" ([hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"}) triplet.
Together, a [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} and [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} can form a "yearly day aggregate" ([yda]{.tool data-bs-toggle="tooltip" data-bs-title="yearly day aggregate"}): \${selSnapDay}.

$$\text{yda} = \text{doy} + \text{tod}$$

$$\lfloor\text{yda}\rfloor = \text{doy}$$

$$\text{yda} - \text{doy} = \text{tod}$$

As their names suggest, [doys]{.tool data-bs-toggle="tooltip" data-bs-title="days of year"} and [ydas]{.tool data-bs-toggle="tooltip" data-bs-title="yearly day aggregates"} are measured in days. The [measurement unit](https://en.wikipedia.org/wiki/Unit_of_measurement#:~:text=a%20definite%20magnitude%20of%20a%20quantity) of a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} can be a day or a [submultiple](https://en.wikipedia.org/wiki/Multiple_%28mathematics%29#Submultiple:~:text=of%20%22a%20being-,a%20unit%20fraction,-of%20b%22%20) of a day. By changing how a decimal [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} is measured, we can shift its [decimal separator](https://en.wikipedia.org/wiki/Decimal_separator#:~:text=a%20symbol%20that%20separates%20the%20integer%20part%20from%20the%20fractional%20part%20of%20a%20number) or turn it into an integer. The [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} along the y-axis of the area chart are integers because they have three digits and are measured in [millidays]{.tool data-bs-toggle="tooltip" data-bs-title="thousandths of a day"}.

## Epochal day aggregate (eda) {#eda .hiddenheading}

We can turn an [yda]{.tool data-bs-toggle="tooltip" data-bs-title="yearly day aggregate"} into a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} by [keeping the remainder after dividing](https://en.wikipedia.org/wiki/Modulo#:~:text=returns%20the%20remainder) by one to isolate the [decimal part](https://en.wikipedia.org/wiki/Fractional_part#:~:text=the%20excess%20beyond%20that%20number%27s%20integer%20part) of the [quotient](https://en.wikipedia.org/wiki/Quotient#:~:text=a%20quantity%20produced%20by%20the%20division%20of%20two%20numbers): \${zeroYdaHsl} [mod](https://en.wikipedia.org/wiki/Modulo#:~:text=returns%20the%20remainder) 1 = \${zeroTimeHsl0}. We can use this same approach to obtain a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} from an "epochal day aggregate" ([eda]{.tool data-bs-toggle="tooltip" data-bs-title="epochal day aggregate"}): \${zeroDoteHsl} mod 1 = \${zeroTimeHsl1}. The current [eda]{.tool data-bs-toggle="tooltip" data-bs-title="epochal day aggregate"} tells us how many days have passed since the Dec [epoch](https://en.wikipedia.org/wiki/Epoch#:~:text=an%20instant%20in%20time%20chosen%20as%20the%20origin%20of%20a%20particular%20calendar%20era).

$$\text{tod} = \text{yda mod } 1 = \text{eda mod } 1$$

## UNIX time equation {#ute .hiddenheading}

Similarly, [UNIX time](https://en.wikipedia.org/wiki/Unix_time#:~:text=the%20number%20of%20non%2Dleap%20seconds%20that%20have%20elapsed%20since%2000%3A00%3A00%20UTC%20on%201%C2%A0January%201970%2C%20the%20Unix%20epoch) tallies the seconds since the [UNIX epoch](https://en.wikipedia.org/wiki/Unix_time#:~:text=00%3A00%3A00%20UTC%20on%201%C2%A0January%201970), which is exactly 719468 days after the Dec epoch. To get the [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} in Zone [0]{.color0}, the Dec time zone that is in between the two leftmost vertical lines on the map🗺️, we can divide UNIX time by the [number of seconds in a day](https://en.wikipedia.org/wiki/Day#:~:text=average%2C%20this%20is-,24%20hours%20(86%2C400%20seconds),-.%20As%20a%20day) and then keep the remainder after dividing the resulting days by one:

$$\text{tod} = \text{unix} \div 86400 \text{ mod } 1$$

## Julian time equation {#jte .hiddenheading}

[Julian dates](https://en.wikipedia.org/wiki/Julian_day#:~:text=the%20Julian%20day%20number%20plus%20the%20fraction%20of%20a%20day%20since%20the%20preceding%20noon) track the days since the beginning of the [Julian period](https://en.wikipedia.org/wiki/Julian_day#:~:text=a%20chronological%20interval%20of%207980%C2%A0years%2C%20derived%20from%20three%20multi%2Dyear%20cycles:%20the%20Indiction%2C%20Solar%2C%20and%20Lunar%20cycles) and thus are akin to [edas]{.tool data-bs-toggle="tooltip" data-bs-title="epochal day aggregates"}. We can produce a Zone [5]{.color5} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} from a [Julian date](https://en.wikipedia.org/wiki/Julian_day#:~:text=the%20Julian%20day%20number%20plus%20the%20fraction%20of%20a%20day%20since%20the%20preceding%20noon) simply by keeping the remainder after dividing by one. If we want a Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} instead, we should add [5]{.color5} [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} to the Julian date before converting it to a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} to ensure that the final result is less than one day:

$$\text{tod} = (\text{julian} + 0.5) \text{ mod } 1$$

## Hour minute second {#hms .hiddenheading}

We can also obtain a Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} from a [Coordinated Universal Time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time#:~:text=the%20primary%20time%20standard%20globally%20used%20to%20regulate%20clocks%20and%20time) ([UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}) [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet by summing its components after converting them to fractional days, as shown in the equation below. The [computer programming](https://en.wikipedia.org/wiki/Computer_programming#:~:text=the%20composition%20of%20sequences%20of%20instructions%2C%20called%20programs%2C%20that%20computers%20can%20follow%20to%20perform%20tasks) code in the [tabset panel](https://quarto.org/docs/interactive/layout.html#tabset-panel) beneath the equation compares [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} derived from [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} and UNIX time as Quarto was [rendering](https://quarto.org/docs/get-started/hello/rstudio.html#rendering:~:text=When%20rendering%2C%20Quarto%20generates%20a%20new%20file%20that%20contains%20selected%20text%2C%20code%2C%20and%20results) this webpage.

$$\text{tod} = \frac{\text{hour}}{24} + \frac{\text{minute}}{1440} + \frac{\text{second}}{86400}$$

:::{.panel-tabset group="language"}
### Julia

```{julia}
using Dates
hms = now(UTC)
hour(hms) / 24 +
minute(hms) / 1440 +
second(hms) / 86400 +
millisecond(hms) / 864e5
datetime2unix(hms) / 86400 % 1
```

### Observable JavaScript

```{ojs}
hms = new Date();
hms.getUTCHours() / 24 +
hms.getUTCMinutes() / 1440 +
hms.getUTCSeconds() / 86400 +
hms.getUTCMilliseconds() / 864e5;
hms.getTime() / 864e5 % 1;
```

### Python

```{python}
from datetime import datetime, timezone
hms = datetime.now(timezone.utc)
hms.hour / 24 + \
hms.minute / 1440 + \
hms.second / 86400 + \
hms.microsecond / 864e8
hms.timestamp() / 86400 % 1
```

### R

```{r}
hms <- as.POSIXlt(Sys.time(), tz = "UTC")
hms$hour / 24 +
hms$min / 1440 +
hms$sec / 86400
(as.numeric(as.POSIXct(hms)) / 86400) %% 1
```

:::

The equations below turn UNIX time or a Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} into the three components of an [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet: the "hour of day" ([hod]{.tool data-bs-toggle="tooltip" data-bs-title="hour of day"}), "minute of hour" ([moh]{.tool data-bs-toggle="tooltip" data-bs-title="minute of hour"}), and "second of minute" ([som]{.tool data-bs-toggle="tooltip" data-bs-title="second of minute"}), using a "daily second aggregate" ([dsa]{.tool data-bs-toggle="tooltip" data-bs-title="daily second aggregate"}) and "hourly second aggregate" ([hsa]{.tool data-bs-toggle="tooltip" data-bs-title="hourly second aggregate"}). While both count seconds, [dsas]{.tool data-bs-toggle="tooltip" data-bs-title="daily second aggregates"} start at midnight and [hsas]{.tool data-bs-toggle="tooltip" data-bs-title="hourly second aggregates"} begin at the [top of the hour](https://en.wiktionary.org/wiki/top_of_the_hour).

$$\text{dsa} = \text{tod} \times 86400 = \text{unix mod } 86400$$

$$\text{hsa} = \text{dsa mod } 3600$$

$$\text{hod} = \lfloor \text{dsa} \div 3600 \rfloor$$

$$\text{moh} = \lfloor \text{hsa} \div 60 \rfloor$$

$$\text{som} = \lfloor \text{hsa mod } 60 \rfloor$$

:::{.panel-tabset group="language"}
### Julia

```{julia}
using Dates
dsa = datetime2unix(now(UTC)) / 86400 % 1 * 86400
hsa = dsa % 3600
map(x -> floor(Int, x), (dsa / 3600, hsa / 60, hsa % 60))
```

### Observable JavaScript

```{ojs}
dsa = Date.now() / 864e5 % 1 * 86400;
hsa = dsa % 3600;
[dsa / 3600, hsa / 60, hsa % 60].map(Math.floor)
```

### Python

```{python}
from datetime import datetime, timezone
dsa = datetime.now(timezone.utc).timestamp() / 86400 % 1 * 86400
hsa = dsa % 3600
tuple(map(int, [dsa // 3600, hsa // 60, hsa % 60 // 1]))
```

### R

```{r}
dsa <- (as.numeric(as.POSIXct(Sys.time())) / 86400) %% 1 * 86400
hsa <- dsa %% 3600
sapply(c(dsa %/% 3600, hsa %/% 60, hsa %% 60), as.integer)
```

:::

## Universal time offset {.hiddenheading #uto}

The [Global Positioning System](https://en.wikipedia.org/wiki/Global_Positioning_System#:~:text=a%20satellite%2Dbased%20hyperbolic%20navigation%20system), [BeiDou](https://en.wikipedia.org/wiki/BeiDou#:~:text=a%20satellite%2Dbased%20radio%20navigation%20system), and [Galileo](https://en.wikipedia.org/wiki/Galileo_(satellite_navigation)#:~:text=a%20global%20navigation%20satellite%20system%20(GNSS)%20created%20by%20the%20European%20Union) [global navigation satellite systems](https://en.wikipedia.org/wiki/Satellite_navigation#:~:text=a%20satellite%20navigation%20system%20with%20global%20coverage) along with most --- if not all --- [programming languages](https://en.wikipedia.org/wiki/Programming_language#:~:text=a%20system%20of%20notation%20for%20writing%20source%20code%20such%20as%20used%20to%20produce%20a%20computer%20program) do not account for [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment), which appears to be for the best given that leap seconds will be [abolished by 2035](https://en.wikipedia.org/wiki/Leap_second#:~:text=at%20the%2027th%20General%20Conference%20on%20Weights%20and%20Measures%2C%20it%20was%20decided%20to%20abandon%20the%20leap%20second%20by%20or%20before%202035). The goal of leap seconds is to keep [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} within [25/24](https://en.wikipedia.org/wiki/Leap_second#:~:text=to%20ensure%20that%20the%20difference%20between%20the%20UTC%20and%20UT1%20readings%20will%20never%20exceed%200.9%20seconds) [centimillidays]{.tool data-bs-toggle="tooltip" data-bs-title="hundred thousands of a day"} ([cmds]{.tool data-bs-toggle="tooltip" data-bs-title="centimillidays"}) of [Universal Time](https://en.wikipedia.org/wiki/Universal_Time#Versions:~:text=a%20time%20standard%20based%20on%20Earth%27s%20rotation) ([UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"}).

Instead of leap seconds, Dec matches [UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"} using a "[universal time offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place)" ([uto]{.tool data-bs-toggle="tooltip" data-bs-title="universal time offset"}). With the [leap second insertion dates](https://en.wikipedia.org/wiki/Leap_second#:~:text=Announced%20leap%20seconds%20to%20date) provided by the [International Earth Rotation and Reference Systems Service](https://en.wikipedia.org/wiki/International_Earth_Rotation_and_Reference_Systems_Service#:~:text=the%20body%20responsible%20for%20maintaining%20global%20time%20and%20reference%20frame%20standards), we can approximate the [uto]{.tool data-bs-toggle="tooltip" data-bs-title="universal time offset"} that yields [UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"} when added to the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} on the [Dec date](/dec/date) chosen by the [range](https://observablehq.com/framework/inputs/range)🎚️inputs below: \${leapCountHsl} &div; 8640 = \${leapTzoHsl0}.

```{ojs}
//| echo: false
//| label: dateinput
viewof leapSecondYear = Inputs.range([1970, 2020], {label: "Year", value: 1995, step: 1})
viewof leapSecondDate = Inputs.range([0, 365], {label: "Day", value: 182, step: 1})
```

## Rounded offset decimal {#rod .hiddenheading}

Of the twenty eight [utos]{.tool data-bs-toggle="tooltip" data-bs-title="universal time offsets"} that can be shown in the equation above, one is an integer, one is a [terminating decimal](https://en.wikipedia.org/wiki/Repeating_decimal#:~:text=a%20finite%20number%20of%20nonzero%20digits), and the rest are [repeating decimals](https://en.wikipedia.org/wiki/Repeating_decimal#:~:text=the%20same%20sequence%20of%20digits%20is%20repeated%20forever). To express a repeating decimal [uto]{.tool data-bs-toggle="tooltip" data-bs-title="universal time offset"}, Dec uses an [irreducible fraction](https://en.wikipedia.org/wiki/Irreducible_fraction#:~:text=a%20fraction%20in%20which%20the%20numerator%20and%20denominator%20are%20integers%20that%20have%20no%20other%20common%20divisors%20than%201) that is called an "exact offset fraction" ([eof]{.tool data-bs-toggle="tooltip" data-bs-title="exact offset fraction"}) when by itself or a "[rounding error](https://en.wikipedia.org/wiki/Round-off_error#:~:text=the%20difference%20between%20the%20result%20produced%20by%20a%20given%20algorithm%20using%20exact%20arithmetic%20and%20the%20result%20produced%20by%20the%20same%20algorithm%20using%20finite%2Dprecision%2C%20rounded%20arithmetic) fraction" ([ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"}) if it follows a "rounded offset decimal" ([rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"}).

In the equation below, the [uto]{.tool data-bs-toggle="tooltip" data-bs-title="universal time offset"} is the minuend, the [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"} is the subtrahend, and the [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"} is the difference. Dec uses the term minuend expansion to describe the replacement of a minuend with a subtrahend and a difference. By replacing a repeating decimal [uto]{.tool data-bs-toggle="tooltip" data-bs-title="universal time offset"} with a [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"} and a [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"}, we can show the initial digits of the [uto]{.tool data-bs-toggle="tooltip" data-bs-title="universal time offset"} as a decimal and the rest as a fraction.

$$\text{uto} - \text{rod} = \text{ref}$$

Use the first three range🎚️inputs below to select an [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet to be converted to [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}, plugged into the equation above as the [uto]{.tool data-bs-toggle="tooltip" data-bs-title="universal time offset"}, rounded to the number of digits chosen by the fourth range🎚️input, and inserted into the equation as the [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"}. Once the left-hand side of the equation is complete, we can solve it to get the [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"}: \${hmsTzoHsl} -- \${hmsRodHsl} = \${hmsRefHsl}.

```{ojs}
//| echo: false
//| label: hmsinput
viewof hmsinput = Inputs.form([
  Inputs.range([0, 23], {label: "Hour", value: 11, step: 1}),
  Inputs.range([0, 59], {label: "Minute", value: 0, step: 1}),
  Inputs.range([0, 59], {label: "Second", value: 0, step: 1}),
])
```

```{ojs}
//| echo: false
//| label: diginput
viewof digits = Inputs.range([1, 9], {label: "Digits", value: 3, step: 1})
```

# Time zone offset {.hiddenheading #tzo}

In Dec, a [uto]{.tool data-bs-toggle="tooltip" data-bs-title="universal time offset"} can be any type of number, a "time zone offset" ([tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}) is an integer, a "solar time offset" ([sto]{.tool data-bs-toggle="tooltip" data-bs-title="solar time offset"}) is a terminating decimal, and an [eof]{.tool data-bs-toggle="tooltip" data-bs-title="exact offset fraction"} is a repeating decimal. If we derived [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} offsets from all 86400 of the [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplets that can be selected by the range🎚️inputs above, we would have 10 [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, 3190 [stos]{.tool data-bs-toggle="tooltip" data-bs-title="solar time offsets"}, and 83200 [eofs]{.tool data-bs-toggle="tooltip" data-bs-title="exact offset fractions"} or [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"} and [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"} pairs.

## Coordinated Universal Time (UTC) {#utc .hiddenheading}

When we do the same to the [38](https://en.wikipedia.org/wiki/List_of_UTC_offsets) [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} offsets, we get only [eofs]{.tool data-bs-toggle="tooltip" data-bs-title="exact offset fractions"} or [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"} and [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"} pairs unless the number of leaps seconds included is zero or a multiple of 27. If the leap second count is zero or a multiple of 8640, we will get 3 [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, 9 [stos]{.tool data-bs-toggle="tooltip" data-bs-title="solar time offsets"}, and 26 [eofs]{.tool data-bs-toggle="tooltip" data-bs-title="exact offset fractions"} or [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"} and [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"} pairs. The 3 [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} will be [stos]{.tool data-bs-toggle="tooltip" data-bs-title="solar time offsets"} if the number of leap seconds is a multiple of 27 but not 8640.

There are 14 negative and 24 positive [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} offsets. The [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone with [the most negative offset](https://en.wikipedia.org/wiki/UTC%E2%88%9212:00#:~:text=a%20nautical%20time%20zone%20comprising%20the%20high%20seas%20between%20180%C2%B0%20and%20172%C2%B030%E2%80%B2W%20longitude) is completely uninhabited. The bar📊chart below visualizes [Socioeconomic Data and Applications Center](https://www.earthdata.nasa.gov/centers/sedac-daac) data from 2020 regarding the population of each [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone. The vast majority of all people live in [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zones with positive offsets.

```{ojs}
//| echo: false
//| label: timezonepoptoggles
//| class: /togs
// https://observablehq.com/@mattdzugan/population-by-time-zone-creating-a-dataset
viewof sortParams = Inputs.form([
  Inputs.toggle({ label: "Sort ascending" }),
  Inputs.toggle({ label: "Sort by offset" }),
  ])
```

```{ojs}
//| echo: false
//| label: timezonepopstackedbar
//| class: stackedBar
// https://observablehq.com/@mattdzugan/population-by-time-zone-creating-a-dataset
Plot.plot({
  width: width,
  marginBottom: 50,
  style: `overflow: visible;font-size:16px;`,
  color: {scheme: "RdBu", className: "barPlotLegend"},
  marginLeft: 75,
  y: { label: null },
  x: { grid: true, label: "Population (billions)", labelOffset: 38, transform: d => d / 1e9 },
  marks: [
    Plot.barX(sortedPop, {x: "pop", y: "Sign", fill: "Offset", stroke: "black", tip: true }),
  ]
})
```

Negative [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} offsets only exist in [the Americas](https://en.wikipedia.org/wiki/Americas#:~:text=a%20landmass%20comprising%20the%20totality%20of%20North%20America%20and%20South%20America) and islands in the [Atlantic](https://en.wikipedia.org/wiki/List_of_islands_in_the_Atlantic_Ocean) and [Pacific](https://en.wikipedia.org/wiki/List_of_islands_in_the_Pacific_Ocean) Oceans. Therefore, the bar📊chart above is essentially comparing the Americas to the rest of the world. According to 2021 [United Nations Department of Economic and Social Affairs](https://en.wikipedia.org/wiki/United_Nations_Department_of_Economic_and_Social_Affairs#:~:text=part%20of%20the%20United%20Nations%20Secretariat) data, about one billion out of a total of almost eight billion people live in the Americas.

Whenever a negative offset is associated with a Dec date, a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, or both a date and a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, Dec will add one day to the date and ten decidays to the offset without modifying the [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}. This typically occurs after the conversion of an [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet to a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} or a "year month day" ([ymd]{.tool data-bs-toggle="tooltip" data-bs-title="year month day"}) triplet to a Dec date. As a result, all Dec dates and [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} have positive offsets.

Dec will not change a negative offset or its associated [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} if the result of adding one day to the [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} is uncertain. This uncertainly can only exist if we do not know whether a [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} that is equal to 364 belongs to a common or leap year. The day after Day [364]{.tool data-bs-toggle="tooltip" data-bs-title="February 28"} of a common year is Day [0]{.tool data-bs-toggle="tooltip" data-bs-title="March 1"} of the subsequent year. In a leap year, Day [364]{.tool data-bs-toggle="tooltip" data-bs-title="February 28"} precedes Day [365]{.tool data-bs-toggle="tooltip" data-bs-title="February 29"}.

## Day of week {#dow .hiddenheading}

Even though it has no effect on the [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, adding one day to the [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} also increments the "day of month" ([dom]{.tool data-bs-toggle="tooltip" data-bs-title="day of month"}) and "day of week" ([dow]{.tool data-bs-toggle="tooltip" data-bs-title="day of week"}) shown by Dec. The table below shows how someone accustomed to a negative offset could intrepret Dec [dow]{.tool data-bs-toggle="tooltip" data-bs-title="day of week"} numbers. From the perspective of a negative offset user, the [dom]{.tool data-bs-toggle="tooltip" data-bs-title="day of month"} and [dow]{.tool data-bs-toggle="tooltip" data-bs-title="day of week"} in Dec will be one day ahead.

:::{.overflowtable style="overflow-x:auto;overflow-y:hidden;"}
| Saturday | Sunday | Monday | Tuesday | Wednesday | Thursday | Friday |
| -------- | ------ | ------ | ------- | --------- | -------- | ------ |
|    0     |   1    |   2    |    3    |     4     |    5     |   6    |
|   -7     |  -6    |  -5    |   -4    |    -3     |   -2     |  -1    |
:::

The one day difference between positive and negative offsets may make Dec [dow]{.tool data-bs-toggle="tooltip" data-bs-title="day of week"} numbers more intuitive than [POSIX](https://pubs.opengroup.org/onlinepubs/007904875/utilities/date.html#:~:text=weekday%20as%20a%20decimal%20number%20%5B0%2C6%5D%20(0%3Dsunday)) [dow]{.tool data-bs-toggle="tooltip" data-bs-title="day of week"} numbers for people who consider [Sunday to be the first [dow]{.tool data-bs-toggle="tooltip" data-bs-title="day of week"}](https://en.wikipedia.org/wiki/Names_of_the_days_of_the_week#:~:text=Sunday%20comes%20first,-in%20order%20in). According to the [Common Locale Data Repository](https://en.wikipedia.org/wiki/Week#:~:text=World%20map%20showing%20the%20first%20day%20of%20the%20week%20used%20in%20different%20countries) and a [2023 population ranking](https://en.wikipedia.org/w/index.php?title=List_of_countries_in_the_Americas_by_population&oldid=1310903194#Table), over 89% of people in the Americas live in a country that starts the week on Sunday.

## Longitude and offsets {.hiddenheading #lao}

In Dec, offsets are closely related to [longitude](https://en.wikipedia.org/wiki/Longitude#:~:text=denoted%20by%20the%20Greek%20letter%20lambda). Dec measures longitude in [parallels](https://en.wikipedia.org/wiki/Circle_of_latitude#:~:text=an%20abstract%20east%E2%80%93west%20small%20circle%20connecting%20all%20locations%20around%20Earth%20(ignoring%20elevation)%20at%20a%20given%20latitude%20coordinate%20line) ([&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="parallel"}) or submultiples of [&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="parallels"} like [deci[parallels](https://en.wikipedia.org/wiki/Circle_of_latitude#:~:text=an%20abstract%20east%E2%80%93west%20small%20circle%20connecting%20all%20locations%20around%20Earth%20(ignoring%20elevation)%20at%20a%20given%20latitude%20coordinate%20line)]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a parallel"} ([d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"}). A [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} is essentially a [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallel"} longitude that had its [decimal part](https://en.wikipedia.org/wiki/Fractional_part#:~:text=the%20excess%20beyond%20that%20number%27s%20integer%20part) removed via [rounding](https://en.wikipedia.org/wiki/Rounding#:~:text=the%20process%20of%20adjusting%20a%20number%20to%20an%20approximate%2C%20more%20convenient%20value), [flooring](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions#:~:text=takes%20as%20input%20a%20real%20number%20x%2C%20and%20gives%20as%20output%20the%20greatest%20integer%20less%20than%20or%20equal%20to%20x), [truncating](https://en.wikipedia.org/wiki/Truncation#Truncation_and_floor_function:~:text=truncation%20is%20limiting%20the%20number%20of%20digits%20right%20of%20the%20decimal%20point), or [ceiling](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions#:~:text=maps%20x%20to%20the%20least%20integer%20greater%20than%20or%20equal%20to%20x). Whereas [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} have one digit, [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} and [stos]{.tool data-bs-toggle="tooltip" data-bs-title="solar time offsets"} typically have up to four digits after the [decimal separator](https://en.wikipedia.org/wiki/Decimal_separator#:~:text=a%20symbol%20that%20separates%20the%20integer%20part%20from%20the%20fractional%20part%20of%20a%20number).

## Centimilliday  {.hiddenheading #cmd}

The fourth digit in the decimal part of any current deciday [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} increments every [centimilliday]{.tool data-bs-toggle="tooltip" data-bs-title="a hundred thousandth of a day"} ([cmd]{.tool data-bs-toggle="tooltip" data-bs-title="centimilliday"}). The clocks at the top of this page tick every 100 beats per [milliday]{.tool data-bs-toggle="tooltip" data-bs-title="a thousandth of a day"}, once per [cmd]{.tool data-bs-toggle="tooltip" data-bs-title="centimilliday"}, or one [inverse](https://en.wikipedia.org/wiki/Multiplicative_inverse#:~:text=x%2C%20denoted%20by-,1/x%20or%20x%E2%88%921,-%2C%20is%20a%20number) of [b]{.tool data-bs-toggle="tooltip" data-bs-title="beat"} ([iob]{.tool data-bs-toggle="tooltip" data-bs-title="inverse of b"}). This frequency is the [lower bound](https://en.wikipedia.org/wiki/Upper_and_lower_bounds#:~:text=an%20element%20of%20K%20that%20is%20less%20than%20or%20equal%20to%20every%20element%20of%20S) of the [normal resting heart rate](https://en.wikipedia.org/wiki/Heart_rate#:~:text=normal%20resting%20adult%20human%20heart%20rate%20is%2060–100%20bpm) of an adult. A [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} with [cmds]{.tool data-bs-toggle="tooltip" data-bs-title="centimillidays"} is 125/108 times more precise than an [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet with an integer [som]{.tool data-bs-toggle="tooltip" data-bs-title="second of minute"}.

If needed, we can always increase the level of precision tenfold by appending an additional digit. In [everyday life](https://en.wikipedia.org/wiki/Everyday_life), we probably will have no need for time units smaller than [cmds]{.tool data-bs-toggle="tooltip" data-bs-title="centimillidays"}, such as [microdays]{.tool data-bs-toggle="tooltip" data-bs-title="millionths of a day"} and [decimicrodays]{.tool data-bs-toggle="tooltip" data-bs-title="ten millionths of a day"}. When shown as part of the current [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, [microdays]{.tool data-bs-toggle="tooltip" data-bs-title="millionths of a day"} change too quickly to be read out loud and [decimicrodays]{.tool data-bs-toggle="tooltip" data-bs-title="ten millionths of a day"} change so fast that they appear as a blur. At the Equator, longitudes measured in [decimicroparallels]{.tool data-bs-toggle="tooltip" data-bs-title="ten millionths of a parallel"} ([d&micro;&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="decimicroparallels"}) are accurate to within about ten [zems]{.tool data-bs-toggle="tooltip" data-bs-title="zone equatorial meters"} (z) or four [meters](https://en.wikipedia.org/wiki/Metre#:~:text=the%20base%20unit%20of%20length%20in%20the%20International%20System%20of%20Units), which is roughly the length of a [subcompact car](https://www.dimensions.com/collection/subcompact-cars-b-segment) or the width of a [U-shaped living room layout](https://www.dimensions.com/collection/living-room-layouts).

The Equator is approximately $10^5$ [kilozems]{.tool data-bs-toggle="tooltip" data-bs-title="a thousand zone equatorial meters"} ([kz]{.tool data-bs-toggle="tooltip" data-bs-title="kilozem"}) long and there are $10^5$ [beats]{.tool data-bs-toggle="tooltip" data-bs-title="centimillidays"} in a day. Therefore, if we move one [kz]{.tool data-bs-toggle="tooltip" data-bs-title="kilozem"} along the Equator, our solar [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} will change by roughly one [beat]{.tool data-bs-toggle="tooltip" data-bs-title="centimilliday"}. As we move along a meridan away from the Equator towards the North or South Pole, the length of a [&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="parallel"} decreases, while our longitude and solar [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} remain unchanged.

## Mean solar time {.hiddenheading #mst}

The two types of [solar time](https://en.wikipedia.org/wiki/Solar_time#:~:text=a%20calculation%20of%20the%20passage%20of%20time%20based%20on%20the%20position%20of%20the%20Sun%20in%20the%20sky) are ["mean solar time"](https://en.wikipedia.org/wiki/Solar_time#Mean_solar_time:~:text=it%20follows%20an%20imaginary%20%22mean%20Sun%22%20that%20moves%20along%20the%20celestial%20equator%20at%20a%20constant%20rate%20that%20matches%20the%20real%20Sun%27s%20average%20rate%20over%20the%20year) ([mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"}) and ["apparent solar time"](https://en.wikipedia.org/wiki/Solar_time#Mean_solar_time:~:text=it%20follows%20an%20imaginary%20%22mean%20Sun%22%20that%20moves%20along%20the%20celestial%20equator%20at%20a%20constant%20rate%20that%20matches%20the%20real%20Sun%27s%20average%20rate%20over%20the%20year) ([ast]{.tool data-bs-toggle="tooltip" data-bs-title="apparent solar time"}). Shifting our [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallel"} longitude to the West by 0.5 [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} gives us a solar [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} that we can add to the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} to get our [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"}. This solar [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} will match our zonal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} when we are at the center of a Dec time zone. In Dec, our zonal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} is always the first digit of our longitude.

The sum of our zonal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} and the current Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} is our zonal time. The difference between a zonal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} and a solar [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} is a "solar time offset" ([sto]{.tool data-bs-toggle="tooltip" data-bs-title="solar time offset"}). To calculate our offset from [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"}, we subtract the [fractional part](https://en.wikipedia.org/wiki/Fractional_part#:~:text=the%20excess%20beyond%20that%20number%27s%20integer%20part) of our [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallel"} longitude from 0.5. We can then add this difference to the result of the [equation of time](https://en.wikipedia.org/wiki/Equation_of_time#:~:text=the%20discrepancy%20between%20two%20kinds%20of%20solar%20time) ([eot]{.tool data-bs-toggle="tooltip" data-bs-title="equation of time"}) to obtain our offset from [ast]{.tool data-bs-toggle="tooltip" data-bs-title="apparent solar time"}.

The difference between our [sto]{.tool data-bs-toggle="tooltip" data-bs-title="solar time offset"} from will be highest at the border between two adjacent time zones.


Once we have The sum of our [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"}, the difference between our solar time and our [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"}, and our solar [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}, is current Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}.

to give us a better idea  To display [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"}, Dec  display our [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"} along the associated [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} as part of a math expressions that evaluate to the

[decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}.

To obtain our zonal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}, we floor our [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallel"} longitude. When calculcating [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} and [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, Dec ensures that the result is positive and less than ten [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}. When provided with a longitude measured in degrees, Dec first converts to [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"}. The degree2lambda() function below accepts degrees and returns First, Dec performs the [modulo](https://en.wikipedia.org/wiki/Modulo#:~:text=returns%20the%20remainder%20or%20signed%20remainder%20of%20a%20division) operation according to the [truncated division definition](https://en.wikipedia.org/wiki/Modulo#Variants_of_the_definition:~:text=Many%20implementations%20use-,truncated%20division,-%2C%20for%20which%20the) to bring a longitude . between If we in negative degrees, Dec converts degrees to [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"}, sums  the current Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} along with ten [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} to ensure a positive result, adds the current and keeps the remainder after dividing by ten [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} so that the result is less than ten [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"}.
We can obtain our zonal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} by flooring our [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallel"} longitude to  remove its
facilitate
 the difference between our [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"} and our zonal time will go from 0 to 0.5 [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}. In Dec, [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"} is shifted by 0.5 [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} so that the
Without this shift, we would have to round instead of flooring.

To find the UTC [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of a given longitude and latitude, we could use an [application programming interface](https://en.wikipedia.org/wiki/API#:~:text=a%20type%20of%20software%20interface%2C%20offering%20a%20service%20to%20other%20pieces%20of%20software) (API) or a [database](https://observablehq.com/@jcolot/time-zone-service). If we only have longitude, we need to first round degrees to zero or the nearest multiple of fifteen for whole hour [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, 7.5 for half hour [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, or 3.75 for quarter hour [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} and then divide by fifteen to convert degrees to hours.

In contrast, the first digit of any longitude shown by Dec tells us its the zonal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of any longitude shown by Dec is evident at a glance without the need for APIs, databases, or even any calculations, because Dec processes longitudes such that the first digit of a longitude is always its first digit. First, Dec

$$(\text d\lambda + 10) \text{ mod } 10$$

We can incorporate a 0.5 [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} shift into the expression above to turn a [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} longitude into the difference between the [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"} at that longitude and the current Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}. [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}
This requirement also unifies the truncated, floored, and Euclidean definitions of modulo.

[tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} + tzo = mst - tzo
Unlike rounding, flooring does never changes the first digit of a positive number regardless of the remaining digits.

We could achieve the same effect with all numbers greater than negative ten and less than ten, -10 &lt; d&lambda; &lt; 10, by truncating instead of flooring.

We could Dec has no need for the In mathematics, flooring can be explained as $\text{trunc(x)} = \text{x} - \text{x} \text{ mod } 1$ and rounding is expressed as $\text{round(x)} = \lfloor\text{x} + 0.5\rfloor$. We can explain flooring as

Flooring is certainly faster than the complex logic needed for UTC [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, but the superiority of Dec is most clear in situations when calculations are unnessecary its [integer part](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions#:~:text=The%20floor%20of%20x%20is%20also%20called%20the%20integral%20part%2C%20integer%20part%2C%20greatest%20integer%2C%20or%20entier%20of%20x). Instead of doing calculations, you can zero if there is no digit to the left of the decimal separator. When confronted with a  contrast, it is difficult to differentiate between highest [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} that rounds to 4 and lowest [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} that rounds to 5. 4.4994 that rounds to 4 and this  immediately know which time zone the
zones have no such shift not  and [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"} matches the time in the middle of  a zonal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} to the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} gives us the [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"} in the middle of the time zone associated with that zonal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}.




$$\text{round(x)} = \lfloor\text{x} + 0.5\rfloor$$






that we can find the time zone that corresponds to a given mst by flooring its the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and the zonal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} we get from
we can add to the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} to obtain our
and that the [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"} matched zonal time in the middle of a time zone and matches its corresponding zonal time in .

If it is midnight in Zone [0]{.color0}, the mst  [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} to  [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"}, and [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} must be above negative ten and below ten: -10 &lt; x &lt; 10. While negative [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} may be a negative longitude, [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, or [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} is not expressly required, Dec will add ten [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} and keep the remainder after dividing by ten.

the
add it to the Zone [0]{.color0} [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, the result will be our [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"}.

$$\text{mst} = (\text{tod} + \lambda + 0.95) \text{ mod } 1$$




one [&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="parallel"}
always translates to a one day change in our

When we convert longitude into a solar [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}, a change of one [kilozem]{.tool data-bs-toggle="tooltip" data-bs-title="a thousand zone equatorial meters"} in longitude at the Equator results in a difference of one [beat]{.tool data-bs-toggle="tooltip" data-bs-title="centimilliday"} in the corresponding solar [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}. If Dec We should not expect that people [decimicroparallels]{.tool data-bs-toggle="tooltip" data-bs-title="ten millionths of a parallel"} ([d&micro;&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="microparallels"}).

that has five digits after its decimal separator will measure Typical timekeeping Millidays and [beats]{.tool data-bs-toggle="tooltip" data-bs-title="centimillidays"} are analogous to minutes and a three-digit milliday [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}  small enough for most timekeeping tasks can show additional digits in a static timestamp pre even greater precision is required  the precision of [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} and solar [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} so that [microdays]{.tool data-bs-toggle="tooltip" data-bs-title="millionths of a day"} are never displayed as part of the current [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}. will have up to five digits when expressed as [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}. The number of digits in [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} and solar [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} is limited to five because any additional digits appear as a blur when displayed as part of the current [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}: . The duration of the fifth digit is


A longitude a [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} longitude with 5 digits will be accurate to within about one [kilozem]{.tool data-bs-toggle="tooltip" data-bs-title="a thousand zone equatorial meters"} (kz). As a reference point, a perfectly cubic house with a side length of surface area of 1000 square zems (z^2^) would have a is a reasonable surface area for a house. With 6 digits, we  after the As we move from the Equator toward the North or South Pole, a longitude will eventually need fewer digits for the same level of accuracy. If we round a solar [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}to one digit afterrange for [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} and [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallel"} longitudes is 0 &lt; x &lt; 10. a single-digit positive integer that

1001.875 "zone equatorial meters" ([zems]{.tool data-bs-toggle="tooltip" data-bs-title="zone equatorial meter"}) or . As we approach the
 thus is one of ten values with an infinite number of decimals in between. If we measure , the only way we can

the result of flooring a [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallel"} longitude. to obtain an integer [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}. If we shift a [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} longitude westward by half a [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"}, we get the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of the ["mean solar time"](https://en.wikipedia.org/wiki/Solar_time#Mean_solar_time:~:text=it%20follows%20an%20imaginary%20%22mean%20Sun%22%20that%20moves%20along%20the%20celestial%20equator%20at%20a%20constant%20rate%20that%20matches%20the%20real%20Sun%27s%20average%20rate%20over%20the%20year) that corresponds to that longitude.

[d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} longitude by shifting westward by half a [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} to produce the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of its corresponding

half a [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} to produce a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} that we can add to Zone 0 .


We can distinguish a  zonal and solar time has a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}.
In the middle of a time zone, the
Dec will add one [&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="parallel"} or the equivalent amount in a [&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="parallel"} submultiple to any negative longitude.

Dec classifies every possible time as “zonal”, “solar”, or “other” based on its corresponding [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}.


measured in [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"},to make it positive. When we floor a [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} longitude, we get the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of its corresponding Dec time zone. If we subtract half a [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} to the longitude instead of flooring it, we will have the difference between the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and the ["mean solar time"](https://en.wikipedia.org/wiki/Solar_time#Mean_solar_time:~:text=it%20follows%20an%20imaginary%20%22mean%20Sun%22%20that%20moves%20along%20the%20celestial%20equator%20at%20a%20constant%20rate%20that%20matches%20the%20real%20Sun%27s%20average%20rate%20over%20the%20year) ([mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"}).

The equations in the article always assume that we are working with like units. the [ydas]{.tool data-bs-toggle="tooltip" data-bs-title="yearly day aggregates"}, [doys]{.tool data-bs-toggle="tooltip" data-bs-title="days of year"} and [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} are measured in days. To convert to a submultiple of a day, we multiply the terms on one side of any equation by a multiple of 10.


$$\text{tzo} = \lfloor\text{d}\lambda\rfloor$$

If we subtract half a

 starting from Longitude [0]{.color0}, the Dec [prime meridian](https://en.wikipedia.org/wiki/Prime_meridian#:~:text=an%20arbitrarily%2Dchosen%20meridian%20%28a%20line%20of%20longitude%29%20in%20a%20geographic%20coordinate%20system%20at%20which%20longitude%20is%20defined%20to%20be%200%C2%B0) and ["international date line"](https://en.wikipedia.org/wiki/International_Date_Line#:~:text=the%20line%20between%20the%20South%20and%20North%20Poles%20that%20is%20the%20boundary%20between%20one%20calendar%20day%20and%20the%20next) ([idl]{.tool data-bs-toggle="tooltip" data-bs-title="international date line"}). To find the Dec time zone and [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} at a location



year+364.tod-tzo
364-tzo
364+tzo

otherwise. to positive [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} by adding one day to the [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} and the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}. Dec will add one day to the adds one the [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet as described above, but adds one day to both the date and the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}. negative [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} to positive [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}.

To convert between Dec and Gregorian calendar, Dec stores the negative tzo
The [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} and [dom]{.tool data-bs-toggle="tooltip" data-bs-title="day of month"} equations below are able to adapt to negative tzos.
From the perspective of anyone who uses a negative [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}, the  should interpret Dec [doms]{.tool data-bs-toggle="tooltip" data-bs-title="days of month"} as zero-based numbers and [dows]{.tool data-bs-toggle="tooltip" data-bs-title="days of week"} according to the table below.
The range input below represents the birthday of someone born in [the Americas](https://en.wikipedia.org/wiki/Americas#:~:text=a%20landmass%20comprising%20the%20totality%20of%20North%20America%20and%20South%20America) who thinks they were born on Day 183 but was actually born on It could be a  and therefore is shifted in relation. "day of week" ([dow]{.tool data-bs-toggle="tooltip" data-bs-title="day of week"}) or The [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of the most populous [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone in the Western Hemisphere is therefore -25/12 + [10]{.color0} = 95/12. When converting the Gregorian calendar birthday of anyone born in a  will have increment their b add one day. in the uses a tzo of -25/12 will think that the  exactly one behind everyone  Using this approach, Dec can match any possible [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}. but anyone using [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zones with negative offsets.
The top range input below represents a Dec refers to The [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} in  [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}-25/12 is roughly one day behind Zone 8. and but   The time zone is one day behind. To match  -25/12. To find the Dec time zone that has the smallest time difference is closest If we add ten decidays to this [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}, we get 95/12 or rather than Zone By default, Dec adds ten decidays to all negative tzos to make them positive. Dec refers to .  is -25/12 decidays behind UTC. but this approach needs to use a negative [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} to avoid mismatches by one day. That are one day ahead of dates in [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zones with negative [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} will be one day behind this approach results in dates that differ by one day. but

The [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} of the ten Dec time zones are all single-digit positive integers.
The chart above does not take into account ["daylight savings time"](https://en.wikipedia.org/wiki/Daylight_saving_time#:~:text=the%20practice%20of%20advancing%20clocks%20to%20make%20better%20use%20of%20the%20longer%20daylight%20available%20during%20summer) ([dst]{.tool data-bs-toggle="tooltip" data-bs-title="daylight savings time"}). Dec considers [dst]{.tool data-bs-toggle="tooltip" data-bs-title="daylight savings time"} and negative [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} to be special requests for a minority of users. and UTC time zones offerEach of the ten time zones has a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} that is a single-digit positive integer.

The most populous UTC time zone with a negative [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} is -25/12 decidays behind UTC. Some places only use this [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} for part of the year because of daylight savings time.
A central design principle of Dec is to meet users where they are. Rather than inform people born in a  chart above shows that this problem affects a Any date associated with a negative [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} will exactly one day behind . Dates with negative  negative [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} because it can match any possible [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} using only  time measurement. match the time in any [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone and in fact using only positive [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}. to match any possible . Even if Dec even those associated with a negative [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}, but the date produced by the negative [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} will be one day behind. Date mismatches lead to unexpected results when translating dates between the Dec and Gregorian calendars or when a “day of week” is included as part of a Dec date. We can subtract ten decidays from any positive Dec [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} to make it negative.We can add or subtract ten [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} to switch between a positive and negative [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} without changing its corresponding [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}. To stay within the correct [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} range for [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} and [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, -10 < x < 10, we keep only the remainder after dividing by ten.

 and range from [-5]{.color5} to [35/6]{.color583} [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} without leap seconds.
and from [-1276/320]{.color5} to [5603/960]{.color5} [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} with [[27]{.color1by320} leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=27%20leap%20seconds%20have%20been%20added%20to%20UTC).



Of the 86390 [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet-derived fractions that can be shown above, there are 8639 [simple fractions](https://en.wikipedia.org/wiki/Fraction#Simple,_common,_or_vulgar_fractions) and 77751 [improper fractions](https://en.wikipedia.org/wiki/Fraction#:~:text=When%20the%20numerator%20and%20the%20denominator%20are%20both%20positive%2C%20the%20fraction%20is%20called%20proper%20if%20the%20numerator%20is%20less%20than%20the%20denominator%2C%20and%20improper%20otherwise). Among these fractions, we would find 96 unique denominators. Fractions that have different denominators are difficult to compare.
Similarly, a Dec times is essentially a math expression with two terms, a tod and a tzo, that can be combined into a Zone 0 tod. We can also have a Dec time that consists of a tod, [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"}, and [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"}

In addition to replacing a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} with a [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"} and a [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"},  . In minuend expansion, the minuend is expanded into a the first equation below, the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} is the , and the [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"} is the difference. The second equation below shows that we can replace a minuend with a subtrahend and a difference.

In general, comparing fractions --- especially [unlike fractions]() --- is more difficult than comparing decimals. Dec always displays [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} and [rods]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"} in decimal form for easy comparison.

The [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"} is the difference between the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} and the [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"}:

$$\text{tzo} = \text{rod} + \text{ref}$$

The range🎚️input above chooses the number of digits in the rod.
 [rounding error](https://en.wikipedia.org/wiki/Round-off_error#:~:text=the%20difference%20between%20the%20result%20produced%20by%20a%20given%20algorithm%20using%20exact%20arithmetic%20and%20the%20result%20produced%20by%20the%20same%20algorithm%20using%20finite%2Dprecision%2C%20rounded%20arithmetic). When rounded to the number of digits chosen by the range🎚️input below, the [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet selected by the range🎚️inputs above is \${hmsTzoHsl1} and the rounding error is \${hmsRoeHsl}.



In addition to splitting a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} into a [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"} and a [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"}, we can split a [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"}, [yda]{.tool data-bs-toggle="tooltip" data-bs-title="yearly day aggregate"}, or [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} into a subtrahend and a difference via a process called minuend expansion.  [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} or a  the difference. Dec uses the terms minuend, subtrahend, and difference to label different parts of a [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"}, [yda]{.tool data-bs-toggle="tooltip" data-bs-title="yearly day aggregate"}, [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, or [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} that have undergone minuend expansion. When a  splitting a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"} and a [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"} is an example of minuend expansion.

In the equation below, the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} is the minuend, the [rod]{.tool data-bs-toggle="tooltip" data-bs-title="rounded offset decimal"} is the subtrahend, and the [ref]{.tool data-bs-toggle="tooltip" data-bs-title="roundoff error fraction"} is the difference.
$$\text{tzo} - \text{rod} = \text{ref}$$



When we round a decimal number, we are essentially removing the round-off error.

In general, the presence of a fraction indicates that goal is to match either UT or a time in a UTC time zone.

After being converted to [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}, the [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplets that can be selected by range🎚️inputs below to [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"},

from a Each of the ten Dec time zones has a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} that is a positive single-digit [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} integer.

The vast majority of the [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplets that can be selected by the range🎚️inputs above,   expressed the remaining 8639 out of 8640 [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplets using fractions.

cannot be expressed the remaining 26/27 [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplets thatas fractions

Most Using fractions, Dec can precisely match any UTC tzo with any number of leap seconds.
Dec uses fractions for decimal tzos that are derived from hms triplets like the one selected by the range🎚️inputs below. Using fractions, Dec can match any UTC tzo. Instead of showing
To facilitate the comparison of a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and a tzo that comprise a Dec time,   easier the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} shown above can be represented by a math expression that the sum of a and its associated [round-off error](https://en.wikipedia.org/wiki/Round-off_error#:~:text=the%20difference%20between%20the%20result%20produced%20by%20a%20given%20algorithm%20using%20exact%20arithmetic%20and%20the%20result%20produced%20by%20the%20same%20algorithm%20using%20finite%2Dprecision%2C%20rounded%20arithmetic) ([roe]{.tool data-bs-toggle="tooltip" data-bs-title="round-off error"}) fraction: [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} = [rdo]{.tool data-bs-toggle="tooltip" data-bs-title="rounded decimal offset"} + [roe]{.tool data-bs-toggle="tooltip" data-bs-title="round-off error"}.

After being converted to decidays, 26 out of [38](https://en.wikipedia.org/wiki/List_of_UTC_offsets) [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} are [repeating decimals](https://en.wikipedia.org/wiki/Repeating_decimal#:~:text=the%20same%20sequence%20of%20digits%20is%20repeated%20forever), 9 are [terminating decimal](https://en.wikipedia.org/wiki/Repeating_decimal#:~:text=a%20finite%20number%20of%20nonzero%20digits), and 3 are integers. Instead of displaying a decimal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} as a fraction, Dec can round and display it along with its the [round-off error](https://en.wikipedia.org/wiki/Round-off_error#:~:text=the%20difference%20between%20the%20result%20produced%20by%20a%20given%20algorithm%20using%20exact%20arithmetic%20and%20the%20result%20produced%20by%20the%20same%20algorithm%20using%20finite%2Dprecision%2C%20rounded%20arithmetic) ([roe]{.tool data-bs-toggle="tooltip" data-bs-title="round-off error"}) as a fraction.
Dec displays [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} derived from the [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplets, like the one selected by the range🎚️inputs below, as a fraction:

In its most basic form, a Dec time consists of a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}. Typically, all of the components of a Dec time are measured in [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}. Dec times are essentially math expressions that can be simplified to Zone [0]{.color0} [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"}.

In  The "Hour" range input above cannot be used to select a negative value.  In essence, Dec times are math expressions that can be simplified to the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}: \${leapTodHsl1} -- \${leapTzoHsl2} = \${zeroTimeHsl4}.

If we include a sum of leap seconds that is not zero or a multiple of 8640, none of the [38](https://en.wikipedia.org/wiki/List_of_UTC_offsets) [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} will be an integer. You can The deciday value of the


The fractions we will have a UTC will match Zone 0 from [-1276/320]{.color5} to [5603/960]{.color5}. With leap seconds, none of  [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} have [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} the range of [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} is [-5]{.color5} to [35/6]{.color583} [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}.

Using [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} expressed as fractions, Dec can match the time in UTC time zones, Dec often has to To avoid date mismatches with [[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zones](https://en.wikipedia.org/wiki/List_of_UTC_offsets) that have negative [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, we can subtract ten [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} from any positive [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} to make it negative: \${decOffsetHslP} -- [10]{.color0} = \${decOffsetHslN}.

```{ojs}
frac(27).div(8640).add(1, 320).toFraction()
```

```{ojs}
//| echo: false
//| label: offinput
viewof offset = Inputs.range([-10, 9], {label: "Offset", value: 0, step: 1})
```

Disregarding leap seconds, the [[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[-5]{.color5}](https://en.wikipedia.org/wiki/UTC%E2%88%9212:00#:~:text=a%20nautical%20time%20zone%20comprising%20the%20high%20seas%20between%20180°%20and%20172°30′W%20longitude) time zone is exactly one day behind Zone [5]{.color5} and thus has the same time but a different date.
If date mismatches are not a concern,
Negative [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} associated with a date, Dec will standardize its bring its that has an integer [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} will belong to one of the ten Dec time zones. If a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} is not an integer, Dec will either express it as All other [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} will not be compatible with any of the twn Dec time zones, but may match either [UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"} or the time in a [[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone](https://en.wikipedia.org/wiki/List_of_UTC_offsets).

Any [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} that is an integer will produce a time that matches the time in one of the ten Dec time zones.
After being converted to [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}, the latest [UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"} [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} that can be selected above is a [terminating decimal](https://en.wikipedia.org/wiki/Repeating_decimal#:~:text=a%20finite%20number%20of%20nonzero%20digits) and all of the others are [repeating decimals](https://en.wikipedia.org/wiki/Repeating_decimal#:~:text=the%20same%20sequence%20of%20digits%20is%20repeated%20forever). In contrast, 26 out of [38](https://en.wikipedia.org/wiki/List_of_UTC_offsets) [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} are repeating decimals, 9 are terminating decimals, and 3 are integers.
Dec can round it
he current Zone [0]{.color0} time is \${zeroTimeHsl3}[-]{.mono}[0]{.color0}.
where the [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} is the minuend and the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} is a .

A Dec time consists of a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}. We can evaluate any Dec time as Dec can display a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} together as , we get a Dec time. and a tzo that differs from the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} is defined as the sum of the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}. The ten Dec time zones are labeled [0]{.color0} to [9]{.color9} based on their [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}. To find the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of a location, we floor its deciparallel longitude. of the all single-digit positive integers: . To find the Dec time zone with the closest to a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone with a negative [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} can be  have a similar time

We can combine the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of any of the ten Dec time zones with a tod to create a .time all single-digit positive integers. We can combine an UT can be measured using vlbi with a precision greater than a fifth of a microday.

D
Dec can either display
Each of the ten Dec time zones has a tzo that is a single-digit positive integer. We can make any  Dec displays [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} based on hours, minutes, and seconds as fractions to avoid rounding recurring decimal numbers. ec measures tzos in decidays. The tzos of the ten Dec time zones are all single-digit positive integers. Dec displays

[UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"} does not belong to any of the ten Dec time zones. Similarly, In general, the difference between needed to is able to support any number kk we can a zonal time is the sum of a Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}. The tzo of any zonal time is a floored longitude. and solar times


## International date line {.hiddenheading #idl}


Dec measures longitude in [parallels](https://en.wikipedia.org/wiki/Circle_of_latitude#:~:text=an%20abstract%20east%E2%80%93west%20small%20circle%20connecting%20all%20locations%20around%20Earth%20(ignoring%20elevation)%20at%20a%20given%20latitude%20coordinate%20line) ([&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="parallels"}) or submultiples of [&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="parallels"} starting from Longitude [0]{.color0}, the Dec [prime meridian](https://en.wikipedia.org/wiki/Prime_meridian#:~:text=an%20arbitrarily%2Dchosen%20meridian%20%28a%20line%20of%20longitude%29%20in%20a%20geographic%20coordinate%20system%20at%20which%20longitude%20is%20defined%20to%20be%200%C2%B0) and ["international date line"](https://en.wikipedia.org/wiki/International_Date_Line#:~:text=the%20line%20between%20the%20South%20and%20North%20Poles%20that%20is%20the%20boundary%20between%20one%20calendar%20day%20and%20the%20next) ([idl]{.tool data-bs-toggle="tooltip" data-bs-title="international date line"}).

To calculate the [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"} for a location, we add its longitude in [&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} to the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and then subtract 5 [centidays]{.tool data-bs-toggle="tooltip" data-bs-title="hundredths of a day"}. If the result is negative, we can make it positive by

$$\text{mst} = \text{tod} + \lambda - 0.05$$

$$\text{mst} = (\text{tod} + \lambda + 0.95) \text{ mod } 1$$



## Apparent solar time {.hiddenheading #ast}


Longitude [0]{.color0} separates Zones [9]{.color9} and [0]{.color0}.

In the middle of Zone [0]{.color0} is Longitude [0.5]{.color05}, the Dec solar time prime meridian, which is not shown on the map🗺️above.


Longitude [0]{.color0}




 Zonal times match [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"} only in the centers of time zones.

In between Longitudes [0]{.color0} and [1]{.color1} is Zone [0]{.color0}.
From the perspective of Zone 0, During solar noon, when the Sun is at its highest point, the solar time

the leftmost vertical line on the map🗺️above, which cuts across the Atlantic Ocean through Iceland🇮🇸just West of Africa.

 Arranging Dec time zones from 0 to 9 yields a [Pacific-centric](https://en.wikipedia.org/wiki/orld_map#:~:text=south%2Dup%20map-,Pacific%2Dcentric%20map,-(more%20commonly%20used)) map🗺️.

At any given moment, there is just one UT for the entire world, a zonal time for every time zone, and two types of solar time for every longitude: “mean
solar time” (mst) and “apparent solar time” (ast).



To The two types of , [UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"}, and [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} in general must be greater that negative one and less than one day: -1 < t < 1. If we ever encounter a tod outside these bounds, we can

$$-1 < \text{tod} < 1$$

In Dec, [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"}, [msts]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar times"}, [&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"}, and [asts]{.tool data-bs-toggle="tooltip" data-bs-title="apparent solar times"} are bound between -1 and 1. equations above make sure that the The equation above works for any [tod] in days and longitude in [&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="parallels"}, even those that are outside the typical bounds. In Dec, less than zero or greater than one (0 &le; x &lt; 1). If we ever need to deal with an negative values, we can always add one and then keep the remainder after dividing by one. Zone [0]{.color0} starts at a longitude of 0 [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} and is 1 [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} wide. In contrast,  0.5 [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} it is midnight in , the [mst] in  Unlike [UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"}, [ast]{.tool data-bs-toggle="tooltip" data-bs-title="apparent solar time"} also varies by longitude and is cyclical on a yearly basis. To approximate [ast]{.tool data-bs-toggle="tooltip" data-bs-title="apparent solar time"} for a given [deci[parallel](https://en.wikipedia.org/wiki/Circle_of_latitude#:~:text=an%20abstract%20east%E2%80%93west%20small%20circle%20connecting%20all%20locations%20around%20Earth%20(ignoring%20elevation)%20at%20a%20given%20latitude%20coordinate%20line)]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a parallel"} [longitude](https://en.wikipedia.org/wiki/Longitude#:~:text=denoted%20by%20the%20Greek%20letter%20lambda) ([d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"}) and [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"}, we sum the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"}, and the result obtained from plugging the [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} into the [equation of time](https://en.wikipedia.org/wiki/Equation_of_time#:~:text=the%20discrepancy%20between%20two%20kinds%20of%20solar%20time) ([eot]{.tool data-bs-toggle="tooltip" data-bs-title="equation of time"}): \${zeroTimeHsl2} + \${longInputHsl} + \${eotHsl} = \${eotSumHsl}.

$$\text{mst} = (\text{tod} + \lambda + 0.95) \text{ mod } 1$$


```{ojs}
//| echo: false
//| label: longinput
viewof longInput = Inputs.range([0, 10], {label: "Longitude", value: 5, step: 0.01})
```

The [National Oceanic and Atmospheric Administration](https://www.noaa.gov) ([NOAA]{.tool data-bs-toggle="tooltip" data-bs-title="National Oceanic and Atmospheric Administration"}) provides [yearly and daily [eot]{.tool data-bs-toggle="tooltip" data-bs-title="equation of time"} values](https://gml.noaa.gov/grad/solcalc/calcdetails.html). To create a Dec version of the [eot]{.tool data-bs-toggle="tooltip" data-bs-title="equation of time"}, we can sort the yearly [NOAA]{.tool data-bs-toggle="tooltip" data-bs-title="National Oceanic and Atmospheric Administration"} [eot]{.tool data-bs-toggle="tooltip" data-bs-title="equation of time"} values by their [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} and then [fit a curve](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html) to the sorted values so that we can use the fitted model coefficients ($\beta_0$ to $\beta_4$) as the [eot]{.tool data-bs-toggle="tooltip" data-bs-title="equation of time"} constants in the [NOAA]{.tool data-bs-toggle="tooltip" data-bs-title="National Oceanic and Atmospheric Administration"} [General Solar Position Calculations](https://gml.noaa.gov/grad/solcalc/solareqns.PDF):

$$\tau = 2 \times \pi$$

$$\text{toy} = \text{doy} \div \text{n}$$

$$\gamma = \tau \times \text{toy}$$

$$\begin{split}
\text{eot}(\gamma) & = \beta_0 \\
& + \beta_1 \times \cos(\gamma) \\
& + \beta_2 \times \sin(\gamma) \\
& + \beta_3 \times \cos(2\gamma) \\
& + \beta_4 \times \sin(2\gamma)
\end{split}$$

$$\text{ast} = (\text{mst} + \text{eot}(\gamma) + 10) \mod 10$$

## Equation of time {.hiddenheading #eot}

In the equations above, $\tau$ is two times $\pi$, n is the number of days in a year, the "time of year" ([toy]{.tool data-bs-toggle="tooltip" data-bs-title="time of year"}) is the [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} divided by n, $\gamma$ is the [toy]{.tool data-bs-toggle="tooltip" data-bs-title="time of year"} multiplied by $\tau$, "mean solar time" ([mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"}) is the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} plus [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"}. We can refer to [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} as the [mst]{.tool data-bs-toggle="tooltip" data-bs-title="mean solar time"} [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} and the sum of [d&lambda;]{.tool data-bs-toggle="tooltip" data-bs-title="deciparallels"} and [eot]{.tool data-bs-toggle="tooltip" data-bs-title="equation of time"}($\gamma$) as the [ast]{.tool data-bs-toggle="tooltip" data-bs-title="apparent solar time"} [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}. Using the coefficients shown below, we can plot [eot]{.tool data-bs-toggle="tooltip" data-bs-title="equation of time"}($\gamma$) against [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"}:

{{< embed eot.ipynb#eot >}}

```{ojs}
//| echo: false
//| label: eotplot
// https://observablehq.com/@mcmcclur/plot-for-mathematicians
{
  let w = 800;
  let h = 0.625 * w;
  let samples = build_samples(
    getEot, -366, 365, { N: 150 }
  );
  let plot = Plot.plot({
    marginLeft: 60,
    width: w,
    height: h,
    style: "font-size:19;",
    y: {label: "time zone offset"},
    x: {label: "day of year"},
    marks: [
      Plot.line(samples, {
        strokeWidth: 4,
        stroke: "steelblue",
        tip: true
      }),
      Plot.ruleX([-366]),
      Plot.ruleY([0]),
      Plot.axisX({ y: 0 }),
      Plot.axisY({ x: -366 })
    ]
  });
  return plot;
}
```

## Solar declination angle {.hiddenheading #sda}

We can subtract the [ast]{.tool data-bs-toggle="tooltip" data-bs-title="apparent solar time"} [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} from five to get the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} of [solar noon](https://en.wikipedia.org/wiki/Noon#:~:text=reaching%20its%20highest%20position%20above%20the%20horizon%20on%20that%20day%20and%20casting%20the%20shortest%20shadow) at the given longitude. Before we can find the sunrise and sunset [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, we first need to calculate the solar declination angle ([sda]{.tool data-bs-toggle="tooltip" data-bs-title="solar declination angle"}). For simplicity, we can use the [eot]{.tool data-bs-toggle="tooltip" data-bs-title="equation of time"} for [sda]{.tool data-bs-toggle="tooltip" data-bs-title="solar declination angle"}, even though the [NOAA]{.tool data-bs-toggle="tooltip" data-bs-title="National Oceanic and Atmospheric Administration"} [General Solar Position Calculations](https://gml.noaa.gov/grad/solcalc/solareqns.PDF) propose the more complex model shown below.

$$\text{noon} = (5 - \text{d}\lambda - \text{eot}(\gamma) + 10) \mod 10$$

$$\begin{split}
\text{sda}(\gamma) & = \beta_0 \\
& + \beta_1 \times \cos(\gamma) \\
& + \beta_2 \times \sin(\gamma) \\
& + \beta_3 \times \cos(2\gamma) \\
& + \beta_4 \times \sin(2\gamma) \\
& + \beta_5 \times \cos(3\gamma) \\
& + \beta_6 \times \sin(3\gamma) \\
\end{split}$$

## Solar hour angle {.hiddenheading #sha}

If the "solar zenith angle" ([sza]{.tool data-bs-toggle="tooltip" data-bs-title="solar zenith angle"}) in the equation below is 0.2523 turns, the equation will yield a sunrise "solar hour angle" ([sha]{.tool data-bs-toggle="tooltip" data-bs-title="solar hour angle"}) that we can use to get a sunrise or sunset [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}. Dec measures angles in turns. The trigonometric functions of most --- if not all -- programming languages require radians. To convert turns into radians, we multiply by $\tau$.

$$\text{radian} = \text{turn} \times \tau = \text{degree} \times \tau \div 360$$

$$\text{turn} = \text{radian} \div \tau = \text{degree} \div 360$$

$$\text{degree} = \text{radian} \div \tau \div 360 = \text{turn} \times 360$$

$$\text{sha} = \arccos\left( \frac{\cos(\text{sza}\times\tau)}{\cos(\phi\times\tau) \cdot \cos(\text{sda}\times\tau)} - \tan(\text{$\phi\times\tau$}) \cdot \tan(\text{sda}\times\tau) \right)$$

In the equation above, latitude is measured in turns called meridians ($\phi$). The difference between a solar noon and sunrise [sha]{.tool data-bs-toggle="tooltip" data-bs-title="solar hour angle"} is a sunrise [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}. Likewise, the sum of a solar noon and sunrise [sha]{.tool data-bs-toggle="tooltip" data-bs-title="solar hour angle"} is a sunset [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}. To get the daylight duration in decidays, we can either subtract the sunset [tod]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} from the sunrise [tod]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} or multiply the sunrise [sha]{.tool data-bs-toggle="tooltip" data-bs-title="solar hour angle"} by twenty.

$$\text{sunrise} = \text{noon} - \text{sha}$$

$$\text{sunset} = \text{noon} + \text{sha}$$

$$\text{duration} = \text{sunset} - \text{sunrise} = \text{sha} \times 20$$

The sunrise and sunset times in the equations above depend on the time zone of solar noon. To select a time zone  may be strange to consider The range🎚️inputs below set the [geographic coordinates](https://en.wikipedia.org/wiki/Geographic_coordinate_system#:~:text=positions%20directly%20on%20Earth%20as%20latitude%20and%20longitude) that are used for the equations above. The [line chart](https://en.wikipedia.org/wiki/Line_chart#:~:text=a%20type%20of%20chart%20that%20displays%20information%20as%20a%20series%20of%20data%20points%20called%20%27markers%27%20connected%20by%20straight%20line%20segments) beneath the inputs visualizes sunrise and sunset for every [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"}, similar to the daylight area chart beneath the map🗺above. The main difference between the charts is that the area chart shows local [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} and thus is independent of longitude, whereas the line chart displays [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} and therefore changes with longitude.

In general, computer programmers and mathematicians seem to prefer radians over degrees.  are better because the Dec base units of time, longitude, and latitude can be multiplied by $\tau$ to can convert days, parallels, and meridians into radians simply by multiplying to . Apart from such as solar noon,
In Dec, any [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} can be expanded to show a subtrahend and a difference. specific point in the day called a subtrahend. The difference between the original [tod]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} and a . A [tod]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} without the diff is called a minuend and Positive diffs show how much time has passed and negative diffs show how much time is left.

$$\text{minuend} = \text{subtrahend} + \text{diff}$$

$$\text{minuend} = \text{subtrahend} + \text{diff}$$

The Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} relative to the solar noon that corresponds to the [doy]{.tool data-bs-toggle="tooltip" data-bs-title="day of year"} and longitude selected by the range🎚️inputs above is \${solarNoonHsl}\${solarSign}\${solarDiffHsl}.

In Zone [0]{.color0}, this was our solar noon, we could  could all agree to center our daily schedules on the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} of our local solar noon, there would be no need for time zones.  could start work two decidays before solar noon and finish two decidays after solar noon.

 depends on [longitude](https://en.wikipedia.org/wiki/Longitude#:~:text=denoted%20by%20the%20Greek%20letter%20lambda).
At any given moment, there is only one [UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"} and 10^5^ five-digit mean solar times.
The [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} we use to get the [mean solar time](https://en.wikipedia.org/wiki/Solar_time#Mean_solar_time:~:text=it%20follows%20an%20imaginary%20%22mean%20Sun%22%20that%20moves%20along%20the%20celestial%20equator%20at%20a%20constant%20rate%20that%20matches%20the%20real%20Sun%27s%20average%20rate%20over%20the%20year) of a location is equal to its [deci[parallel](https://en.wikipedia.org/wiki/Circle_of_latitude#:~:text=an%20abstract%20east%E2%80%93west%20small%20circle%20connecting%20all%20locations%20around%20Earth%20(ignoring%20elevation)%20at%20a%20given%20latitude%20coordinate%20line)]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a parallel"} longitude. We can use the [equation of time](https://en.wikipedia.org/wiki/Equation_of_time#:~:text=the%20discrepancy%20between%20two%20kinds%20of%20solar%20time) to turn the mean solar time of into [apparent solar time](https://en.wikipedia.org/wiki/Solar_time#Apparent_solar_time:~:text=the%20true%20sun%20as%20seen%20by%20an%20observer%20on%20Earth).

sum of a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} and the Zone 0 tod. We can use the equation of time to turn the mean solar time of a location
Similarly, the [deci[parallel](https://en.wikipedia.org/wiki/Circle_of_latitude#:~:text=an%20abstract%20east%E2%80%93west%20small%20circle%20connecting%20all%20locations%20around%20Earth%20(ignoring%20elevation)%20at%20a%20given%20latitude%20coordinate%20line)]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a parallel"} longitude of the red⭕️circle on the map above is the tzo that we sum with the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} to get [mean solar time](https://en.wikipedia.org/wiki/Solar_time#Mean_solar_time:~:text=it%20follows%20an%20imaginary%20%22mean%20Sun%22%20that%20moves%20along%20the%20celestial%20equator%20at%20a%20constant%20rate%20that%20matches%20the%20real%20Sun%27s%20average%20rate%20over%20the%20year).

Without leap seconds, the duration of a day is constant, each [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet occurs only once per day, [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplets can be derived directly from UNIX time or a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} independently of the date as shown above, and the [som]{.tool data-bs-toggle="tooltip" data-bs-title="second of minute"} component stays within its bounds: 0 &le; [som]{.tool data-bs-toggle="tooltip" data-bs-title="second of minute"} < 60.
[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} is based on [atomic clocks](https://en.wikipedia.org/wiki/Atomic_clock#:~:text=a%20clock%20that%20measures%20time%20by%20monitoring%20the%20resonant%20frequency%20of%20atoms) and [UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"} is determined by the [rotation of the Earth](https://en.wikipedia.org/wiki/Earth%27s_rotation#:~:text=the%20rotation%20of%20planet%20Earth%20around%20its%20own%20axis). rom the perspective of Dec,

 that represents the difference between [UT]{.tool data-bs-toggle="tooltip" data-bs-title="Universal Time"} and the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}.

To display [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplets, Dec uses math expressions that evaluate to a [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and leave no doubt about the measurement unit of each component: [hod]{.tool data-bs-toggle="tooltip" data-bs-title="hour of day"}/2.4+[moh]{.tool data-bs-toggle="tooltip" data-bs-title="minute of hour"}/144+[som]{.tool data-bs-toggle="tooltip" data-bs-title="second of minute"}/8640. Like the [Julia](https://en.wikipedia.org/wiki/Julia_(programming_language)#:~:text=a%20dynamic%20general%2Dpurpose%20programming%20language), [Matlab](https://en.wikipedia.org/wiki/MATLAB#:~:text=a%20proprietary%20multi%2Dparadigm%20programming%20language), and [R](https://en.wikipedia.org/wiki/R_(programming_language)#:~:text=a%20programming%20language%20for%20statistical%20computing%20and%20data%20visualization) programming languages, Dec uses colons for numeric sequences such as 12:15, which means 12, 13, 14, and 15 instead of 12.25 hours.

Dec uses centimillidays ([cmds]{.tool data-bs-toggle="tooltip" data-bs-title="centimillidays"}) in lieu of seconds. Centimillidays Instead of inserting a submultiple of a day into tods, would be to follow the switch from base 10 to base 11 on a specific date and then switch back. The last tod on that date would be 9.999Abbbbbbbbbbbbb  able to take leap seconds into account without changing the duration of a day, repeating a tod within the same day, handles leap seconds by converting them to [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} and adding them to a "[time zone offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place)" ([tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}). This way, Dec can match any time with any number of leap seconds the duration of a day never changes, [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplets never repeat within the same day,
Dec can match any possible  All of the  we can be certain that leap seconds do not exist, meaning that In Dec, days always have the same duration, we can obtain a tod without knowing the date, and tods never go outside their bounds or repeat within the same day. ,  of decimal  inserts leap days to increase the duration of leap year from 365 to 366 days, but leap seconds cannot exist.
Leap seconds /

Negative leap seconds are evidence  If an hms triplet repeats, we will know that a had just been inserted. If an hms triplet exceeds its bounds, we will know that a positive leap second had just been inserted. In general, we cannot know how many leap seconds have been inserted thus far simply by looking at an hms triplet.

of sixty seconds in a minute. In Dec, every [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} leap seconds are literally impossible, because days always have the same duration and [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} are decimal numbers.


[Python](https://en.wikipedia.org/wiki/Python_(programming_language)#:~:text=a%20high%2Dlevel%2C%20general%2Dpurpose%20programming%20language)

In Dec, days always have the same duration and [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} calculations are independent of the date.
Currently, 27 leap seconds
To know how many leap seconds have been inserted by a given date, we have to consult a table. The duration of the days into which its are inserted. Instead of changing the duration of certain days, Dec handles leap seconds by converting them to decidays and adding them to a “time zone offset” (tzo).

The languages in the tabset panels in this article, Julia, Python, Observable JavaScript, and R, do not differ in this regard which Dec refers to as the "[Quarto principal languages](https://quarto.org/docs/faq/#:~:text=principal%20languages%20supported%20by%20Quarto%20are%20Python%2C%20R%2C%20Julia%2C%20and%20Observable%20JavaScript)" (Qpls).

With the code above we can convert between a Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet. According to Dec and all four of the programming languages used above, [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} does not have any [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment).

Dec always measures [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} in [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}. The [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} of the ten Dec time zones are all single-digit positive integers. The difference between these ten [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, [0]{.color0} to [9]{.color9}, we can match the time in any [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone to within 0.5 [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}.

If more precise matches are required, Dec can use [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} that have more than one digit. The level of precision required depends on the situtation. Let us say that we want to schedule a meeting with someone If we want to replicate a shift form make the time in UTC time zones that have a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of [-5]{.color5}, [0]{.color0}, or [5]{.color5}, a . At some point the increased precision of additional digits will no If we lived in Zone [0]{.color0} and wanted to schedule a meeting with someone on a particular date, we might  two digits, the time difference will not exceed 5 millidays and will be able to shift [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} by one centiday, which is less a quarter hour. With four digits, the difference between Dec and UTC [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} would be either zero or 288 milliseconds. We can choose to have more than four digits, but the difference is not likely to be noticeable. Therefore, four digits is a sensible If we wanted to match The [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} used by the highest number of people in the world is [10/3]{.color10by3}.

There are three types of  purpose of time zones is to keep To match the time in a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone exactly, Dec will often need to use a decimal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}.

[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}, UNIX time, and Zone [0]{.color0} all have a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of [0]{.color0}. [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} and because both have a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} of . If we add [[27]{.color1by320} leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=27%20leap%20seconds%20have%20been%20added%20to%20UTC) to [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}, Dec would describe the result as a Zone [0.003125]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}.

Each leap second shifts a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} by [1/8640]{.color1by8640}.
By default, Dec rounds decimal [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} to the near deciday: &LeftFloor;tzo + 0.5&RightFloor;. When necessary, Dec is able to exactly match times that include leap seconds or a decimal [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}.

The result of adding leap seconds to a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} depends on how many leap seconds we add. If we add a number of leap seconds that is a multiple of 8640, we get a

and deals with negative tzos keeping the remainder after adding ten and then dividing by ten: (tzo + 10) mod 10.

After combining a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}, Dec first combines it with to [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}, Dec rounds decimal [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} to the nearest [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"}.  and makes negative [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} that are positive integers.  and therefore rounds

Unless To support leap seconds and the vast majority of [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, Dec [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} that are . If we add leap seconds to these [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"}, they will no longer be integers

[

If a tzo is a [repeating decimal](https://en.wikipedia.org/wiki/Repeating_decimal#:~:text=a%20number%20whose%20digits%20are%20eventually%20periodic), Dec will display it as a fraction.

[0003125]{.color1by320}. new [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} will be [0.003125]{.color1by320} and the new [uzi]{.tool data-bs-toggle="tooltip" data-bs-title="unique zone identifier"} will be . the Dec time will be [-]{.mono}[0003125]{.color1by320}. The [0003125]{.color1by320} The [uzi]{.tool data-bs-toggle="tooltip" data-bs-title="unique zone identifier"} tells us that the go from [0]{.color0} to [0003125] and the D

an [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet into a Dec time, we need to know its [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}, and how many leap seconds it includes.
a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, from a programming language, it is  can assume that leap seconds are not included.  [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}The Dec equivalent of UTC with
is a Dec [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset index"}, [uzi]{.tool data-bs-toggle="tooltip" data-bs-title="unique zone identifier"}, If we add [[27]{.color1by320} leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=27%20leap%20seconds%20have%20been%20added%20to%20UTC) We can combine the [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} in any Dec time zone by summing the Zone [0]{.color0}, [[27]{.color1by320} leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=27%20leap%20seconds%20have%20been%20added%20to%20UTC) to a Zone \${decOffsetHsl0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, we get add the result deciday and the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset index"} selected by the range🎚️input below is [0.003125] + \${decOffsetHsl0} = \${decTimeOffLeapTzoHsl}. If we add the resulting [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset index"} to the Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}, we get \${decTimeOffLeapTzoHsl}. last two digits of this [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset index"} and [uzi]{.tool data-bs-toggle="tooltip" data-bs-title="unique zone identifier"} are not visible in a five-digit [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}
If we remove the decimal separator from this [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset index"}, we get its [uzi]{.tool data-bs-toggle="tooltip" data-bs-title="unique zone identifier"}: ${decTimeOffLeapUziHsl}.

Every [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} has a corresponding "time zone index" ([tzi]{.tool data-bs-toggle="tooltip" data-bs-title="time zone index"}). In the case of the ten Dec time zones, the [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} and [tzi]{.tool data-bs-toggle="tooltip" data-bs-title="time zone index"} are identical. The [tzi]{.tool data-bs-toggle="tooltip" data-bs-title="time zone index"} that corresponds to the  Dec measures [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} in decidays. If a tzo is a single-digit integer, it likely  or fractions. The tzos of the ten Dec time zones are positive integers.
 contain leap seconds as fractions. Even if we disregard leap seconds, fractions  in [tods]{.tool data-bs-toggle="tooltip" data-bs-title="times of day"} and [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} to are single-digit integers or fractions. Dec only uses  ten Dec time zones each have a [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} that is a : [0]{.color0} to [9]{.color9} [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}. In contrast, [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} range range from [-5]{.color5} to [5.83̅]{.color583} [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}. A [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone with a negative [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} will be between  have a similar time To avoid date mismatches with , we can subtract ten [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} from any positive Dec [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} to make it negative: \${decOffsetHslP} -- [10]{.color0} = \${decOffsetHslN}.

 far increase the Each leap second shifts the [ozi]{.tool data-bs-toggle="tooltip" data-bs-title="ordinal zone offset"} by

Finding the Dec time zone with the closest [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} to a given [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} entails converting an [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet to decidays, adding ten, keeping the remainder after dividing by ten, and then rounding to the nearest deciday. matching a  tzo of -5 yields the same tod as  exactly one day behind Zone [5
Dec avoids incompatible with the ten Dec time zones. Dec expresses incompatibles [tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} as fractions. Officially, t
Dec refers to [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} with [27]{.color1by320} leap seconds as [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[+]{.mono}[00:00:27]{.color1by320} or [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[+]{.mono}[1/320]{.color1by320}.
Dec can relax its requirement that each [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} be a single-digit positive integer [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} to match any [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"}.

[tzos]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offsets"} is

Dec Positive and negative offsets that differ by exactly ten [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} yield identical times, but result in dates that are precisely one day apart.


https://stackoverflow.com/a/23575642
Use fractions.js to turn non standard offsets into fractions.

To determine which Dec time zone you are in, Dec would need to know your longitude. In general, Dec allows for everyone to use whatever [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} they want, regardless of their geographic location. The UTC [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} provided by your web browser is -300 minutes ÷ 144 = -2.083333 dd. In the absence of any other information, Dec would round this [tzo]{.tool data-bs-toggle="tooltip" data-bs-title="time zone offset"} to the nearest deciday (dd), , and infer that you are in Zone 8. which Dec time zone you are in unless  Rounding UTC tzos can result in a time difference of up to 0.5 dd. Adding 27 leap seconds increases the maximum time difference to 161/320 dd. With time zone rounding, the time difference between your Dec and UTC time zones is 11.52 ÷ 144 = 0.08 dd. With 27 leap seconds, this difference is /320.



The [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} offset provided by your web browser is \${utcOffHslM} &div; 144 = \${utcOffHslD} [dd]{.tool data-bs-toggle="tooltip" data-bs-title="decidays"}. The Dec time zone that corresponds to this [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} offset is Zone \${decZonHslP}. The time in corresponding Dec and [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zones can differ by up to [0.5]{.color050} [dd]{.tool data-bs-toggle="tooltip" data-bs-title="decidays"}. The difference between your Dec and [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time is \${utcOffsetMdiffHsl} &div; 144 = \${utcOffDiffHsl} [dd]{.tool data-bs-toggle="tooltip" data-bs-title="decidays"}.

To obtain the time in Zone [0]{.color0}, we can subtract the offset of any time zone from its time. Inversely, we can get the time in any time zone by adding its offset to the Zone [0]{.color0} time. The dates and times in Zone [0]{.color0} and [[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[+00:00]{.color0}](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time) match exactly. Zone [5]{.color5} and [[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[+12:00]{.color5}](https://en.wikipedia.org/wiki/UTC%2B12:00) also have matching dates and times, both are precisely one day ahead of [[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[-12:00]{.color5}](https://en.wikipedia.org/wiki/UTC%E2%88%9212:00).

This stance is at odds with the International Earth Rotation and Reference Systems Service, which has inserted [27]{.color1by320} leap seconds into [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}.

since [1972]. Dec does not automatically shift time away necessary, Dec handles any shift away from leap seconds in time zone offsets.

Leap seconds

To indicate the

In Dec, the components of an [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet are called the "hour of day" ([hod]{.tool data-bs-toggle="tooltip" data-bs-title="hour of day"}), "minute of hour" ([moh]{.tool data-bs-toggle="tooltip" data-bs-title="minute of hour"}), and "second of minute" ([som]{.tool data-bs-toggle="tooltip" data-bs-title="second of minute"}).

Dec handles differences from Zone [0]{.color0} with time zone offsets. There is no time difference between Zone [0]{.color0} and UNIX time. Dec applies a time zone offset [5]{.color5} [decidays](https://en.wikipedia.org/wiki/Decimal_time#:~:text=dividing%20the%20day%20into%2010%20decidays){.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} to Julian dates because the Dec epoch occurred at midnight ([0]{.color0} [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}) and the [Julian period](https://en.wikipedia.org/wiki/Julian_day#:~:text=a%20chronological%20interval%20of%207980%C2%A0years%2C%20derived%20from%20three%20multi%2Dyear%20cycles:%20the%20Indiction%2C%20Solar%2C%20and%20Lunar%20cycles) started at noon ([5]{.color5} [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}).


To convert days to [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}, we multiply the [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} by ten.

In Dec, days start at midnight, instead of noon, but have the same duration as Julian days: 86400 [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units#:~:text=the%20world%27s%20most%20widely%20used%20system%20of%20measurement) ([SI]{.tool data-bs-toggle="tooltip" data-bs-title="International System of Units"}) seconds or 100000 Dec [beats]{.tool data-bs-toggle="tooltip" data-bs-title="centimillidays"}.

 The duration of days in Dec and Julian dates The difference between the Dec epoch and the beginning of the Julian period is the only thing that distinguishes Julian date and a [doe]{.tool data-bs-toggle="tooltip" data-bs-title="times-of-day"} is its epoch.

In [Coordinated Universal Time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time#:~:text=the%20primary%20time%20standard%20globally%20used%20to%20regulate%20clocks%20and%20time) ([UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}), days start at midnight, but the length of a day can vary due to [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment). In Dec, a day always has the same duration as a

When matching [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} is required, Dec avoids day length changes by adding leap seconds to a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone [offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place). According to Dec, the [[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[+00:00]{.color0}](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time) time zone does not have any leap seconds because its offset is [0]{.color0}. To indicate that a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone includes the [27 leap seconds](https://en.wikipedia.org/wiki/Leap_second#Procedure:~:text=16-,27,-Current%20TAI%20%E2%88%92%20UTC) that have been inserted into [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} so far, Dec appends [:27]{.color1by320} to its offset.

The Dec equivalent of the [[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[+00:00:27]{.color1by320}](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time) time zone is Zone [1/320]{.color1by320}.



In [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}, the length of Day [121]{.colorD121 data-bs-toggle="tooltip" data-bs-title="June 30"} or Day [305]{.colorD305 data-bs-toggle="tooltip" data-bs-title="December 31"} can vary due to [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment).
T
this offset as
T
To represent the 27 leap seconds that have been added to [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} so far, Dec uses an offset of [1/320]{.color1by320} [dd]{.tool data-bs-toggle="tooltip" data-bs-title="decidays"}. Dec refers to the [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone that has this offset as [[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[+00:00:32]{.color1by320}](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time).


either or secon
Since 1972+121, 27 positive leap seconds have been added to UTC, and 0 negative leap seconds have been whave been
in a Julian date or a [doe]{.tool data-bs-toggle="tooltip" data-bs-title="times-of-day"} i
Dec does not allow The time in the ten Dec time zones never include

o depending on whether the leap second is p.  Dec uses to represent [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment) without changing the length of a day in the same way as leap days changes the length of a year. Instead of allowing the length of a day included, some [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} days will be 86401 or 86399 seconds long. So far, 27 positive leap seconds have been added, some [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} days will differ in length.  includes  of seconds, Dec uses beats. 100000 The programming languages that the [Quarto FAQ](https://quarto.org/docs/faq) refers to as [principal languages supported by Quarto](https://quarto.org/docs/faq/#:~:text=The%20principal%20languages%20supported%20by%20Quarto%20are%20Python%2C%20R%2C%20Julia%2C%20and%20Observable%20JavaScript), [Python](https://en.wikipedia.org/wiki/Python_(programming_language)#:~:text=a%20high%2Dlevel%2C%20general%2Dpurpose%20programming%20language) (Quarto principal languages), [R](https://en.wikipedia.org/wiki/R_(programming_language)#:~:text=a%20programming%20language%20for%20statistical%20computing%20and%20data%20visualization), [Julia](https://en.wikipedia.org/wiki/Julia_(programming_language)#:~:text=a%20high%2Dlevel%2C%20general%2Dpurpose%5B17%5D%20dynamic%20programming%20language), and [Observable](http://observablehq.com) [JavaScript](https://en.wikipedia.org/wiki/JavaScript#:~:text=a%20programming%20language%20and%20core%20technology%20of%20the%20World%20Wide%20Web), do not include [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment) in [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time. Therefore, a day in
Even though the Dec, UNIX, and [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} epochs all occurred at midnight, [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time may be shifted in relation to Dec or UNIX time because of [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment).
Since 1972+121, 27


We can make the time in any Dec time zone match UNIX by subtracting its time zone [offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place). The time in the Zone [0]{.color0} Dec time zone always matches UNIX time. because neither includes [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment). Dec considers [Coordinated Universal Time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time#:~:text=the%20primary%20time%20standard%20globally%20used%20to%20regulate%20clocks%20and%20time) ([UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}) [[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} [time zone](https://en.wikipedia.org/wiki/Time_zone#:~:text=an%20area%20which%20observes%20a%20uniform%20standard%20time) to also match UNIX time. If there is a [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment) are not included. Dec handles leap seconds like an additional time zone [offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place). [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[+00:00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} with 27 leap seconds is referred to as Zone 1/320 in Dec and . which

[[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[+00:00]{.color0}](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)

To produce a Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} from an [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet, we get the difference between the [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet and its [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone [offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place), convert its components to either days or [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}, and sum the converted components.

and

$$\text{deciday} = \frac{\text{hour}}{2.4} + \frac{\text{minute}}{144} + \frac{\text{second}}{8640}$$

$$\text{day} = \frac{\text{hour}}{24} + \frac{\text{minute}}{1440} + \frac{\text{second}}{86400}$$

does not include [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment) or a [Coordinated Universal Time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time#:~:text=the%20primary%20time%20standard%20globally%20used%20to%20regulate%20clocks%20and%20time) ([UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}) [time zone](https://en.wikipedia.org/wiki/Time_zone#:~:text=an%20area%20which%20observes%20a%20uniform%20standard%20time) [offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place) and

than [[+00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} and [[+12](https://en.wikipedia.org/wiki/UTC%2B12:00)]{.color5} will not match the time in any of the ten Dec time zones. We can create a [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} by summing the components of an [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet after

that were added a [Coordinated Universal Time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time#:~:text=the%20primary%20time%20standard%20globally%20used%20to%20regulate%20clocks%20and%20time) ([UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}) [[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} time zone. An [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet that includes [leap seconds](https://en.wikipedia.org/wiki/Leap_second#:~:text=one%2Dsecond%20adjustment) or a

To be compatible with Dec, a time zone offset must be equivalent to one of the ten positive single-digit integer [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} Dec offsets. The Zone [5]{.color5} Dec time zone and [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[+12:00](https://en.wikipedia.org/wiki/UTC%2B12:00)]{.color5} time zone have equivalent offsets: [5]{.color5} [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} = [12]{.color5} hours. Likewise, the Zone [0]{.color0} Dec time zone, UNIX time, and the [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} time zone all have an offset of [0]{.color0}.

Apart from [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} and [[+12:00](https://en.wikipedia.org/wiki/UTC%2B12:00)]{.color5}, all of the other [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zones are incompatible with Dec. To find the [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} time difference $\Delta$ between a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone and its closest Dec time zone, convert the offset of the [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone to [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} and then calculate how much the converted offset changes after rounding it to the nearest [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"}.

$$\Delta = \text{offset} - \lfloor\text{offset} + 0.5\rfloor$$

## Repeating decimal numbers {#rdn .hiddenheading}

Dec expresses incompatible offsets as positive or negative fractions or multi-digit integers. [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} offsets are either [repeating](https://en.wikipedia.org/wiki/Repeating_decimal) or terminating decimal numbers. Dec displays repeating decimal offsets as fractions and terminating decimal offsets as integers. [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[+08:00](https://en.wikipedia.org/wiki/UTC%2B08:00)]{.color333}, the most populous [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone, has an offset of [.]{.color333}[3]{.vinculum} days and is called Zone [1/3]{.color333} in Dec. In contrast, [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[+03:00](https://en.wikipedia.org/wiki/UTC%2B03:00)]{.color125} has an offset of [.125]{.color125} days and is called Zone [125]{.color125} in Dec.

Terminating decimal number offsets can be displayed by Dec provided there is enough space for the additional digits. Dec displays repeating decimal number offsets as fractions. The second most populous [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone, [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[+05:30](https://en.wikipedia.org/wiki/UTC%2B05:30)]{.color333}, translates to Zone [55/24]{.color55by24} or Zone [2.291]{.color55by24}[6]{.vinculum} in Dec. The top six most populous [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zones all have positive offsets.

When it is midnight (tod=[0]{.color0}) in Zone [0]{.color0}, it is noon (tod=[5]{.color5}) in Zone [5]{.color5} and the time in every other time zone is equal to it it is \~[5.33]{.color533} in Zone [10/3]{.color333}, \~[4.29]{.color429} in Zone [55/24]{.color55by24}, and

To obtain the Zone [0]{.color0} time, we evaluate any Dec time as a math expression, add 10, and then get the remainder after dividing by 10 to make sure the result is less than 10 [decidays]{.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}.

The use of incompatible offsets makes mental calculations involving time zones much harder. Also, incompatible offsets are more difficult to display and read in the format of Dec times. Despite these clear disadvantages, Dec will attempt to parse, process, and display any time zone offset that is provided. Incompatible offset that are repeating decimal numbers can be displayed as fractions, truncated numbers

noon in [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[+08:00](https://en.wikipedia.org/wiki/UTC%2B08:00)]{.color333} could be written as [5.00]{.color5}[-]{.mono}[10/3]{.color333} or [5.00]{.color5}[-]{.mono}[3.]{.color333}[3]{.vinculum}.

Dec does not set a hard limit on the number of time zones, but negative time zones offsets to improve its compability with [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}.

::: callout-warning
# Bad Pun Alert

Sorry if reading this takes a long ***time***; I hope you don’t ***zone*** out!
:::

If a Dec time zone offset is not specified, we can detected a time zone using Whether or not negative time zones offsets are worth the trouble is a matter of that the offer little to no benefit. The [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[-12:00](https://en.wikipedia.org/wiki/UTC%E2%88%9212:00#:~:text=a%20nautical%20time%20zone%20comprising%20the%20high%20seas%20between%20180%C2%B0%20and%20172%C2%B030%E2%80%B2W%20longitude)]{.color5} and [[+12:00](https://en.wikipedia.org/wiki/UTC%2B12:00)]{.color5} time zones and the Zone [5]{.color5} and [-5]{.color5} Dec time zones all have the same time, but their dates do not match, because [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[-12:00](https://en.wikipedia.org/wiki/UTC%E2%88%9212:00#:~:text=a%20nautical%20time%20zone%20comprising%20the%20high%20seas%20between%20180%C2%B0%20and%20172%C2%B030%E2%80%B2W%20longitude)]{.color5} and Zone [-5]{.color5} are one day behind [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [[+12:00](https://en.wikipedia.org/wiki/UTC%2B12:00)]{.color5} and Zone [5]{.color5}. Dec discourages the use of time zones with negative offsets.

The remaining UTC time zones with negative offsets

If we disregard leap seconds, the [[+00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone is synchronized with UNIX time and the Zone [0]{.color0} Dec time zone. The [[+12](https://en.wikipedia.org/wiki/UTC%2B12:00)]{.color5} and [[-12](https://en.wikipedia.org/wiki/UTC%E2%88%9212:00)]{.color5} [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} offsets have the same time but their dates are one day apart.

We can honor this difference by translating [[+12](https://en.wikipedia.org/wiki/UTC%2B12:00)]{.color5} compatible [37 [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} offsets](https://en.wikipedia.org/wiki/List_of_UTC_offsets), only 3 are integers after they are converted to time zones. Conversion between Dec time zones and UTC offsets is inexact, because UTC offsets depend on geographic and political boundaries, whereas Dec time zones are determined solely by longitude.

because UNIX time, [[UTC](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0}, and Zone [0]{.color0} are all synchronized.

Similarly, a [[UTC](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet yields a Zone [5]{.color5} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}.

[UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}

Instead of passing an [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet and its [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone [offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place) to the [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} equation separately, we can subtract the offset from the triplet to produce a [[UTC](https://en.wikipedia.org/wiki/List_of_UTC_offsets#UTC+00:00,_Z)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[+00:00](https://en.wikipedia.org/wiki/List_of_UTC_offsets#UTC+00:00,_Z)]{.color0} [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet. In other words, we can avoid converting time zone offsets if we always first shift the input [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet to [[UTC](https://en.wikipedia.org/wiki/List_of_UTC_offsets#UTC+00:00,_Z)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[+00:00](https://en.wikipedia.org/wiki/List_of_UTC_offsets#UTC+00:00,_Z)]{.color0}.

To obtain the Zone 0 time, we evaluate a Dec time as a math expression, add 10, and get the remainder after dividing by 10 to make sure the result is less than 10 [decidays](https://en.wikipedia.org/wiki/Decimal_time#:~:text=dividing%20the%20day%20into%2010%20decidays){.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}: ([\${browserTime.toFixed(4)}]{.cyan} \${browserSign} [\${Math.abs(browserZone)}]{.lime} + 10) [mod](https://en.wikipedia.org/wiki/Modulo#:~:text=returns%20the%20remainder) 10 = [\${zone0time.toFixed(4)}]{.cyan}.

Instead of passing both a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplets and its [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone [offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place) to the [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"} equation.

Instead of performing this calculation on both a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet and its [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone [offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place), we should subtract the offset from the triplet.

equation should be a [[UTC](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet so that we do not have to convert a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zone [offset](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place) to [decidays](https://en.wikipedia.org/wiki/Decimal_time#:~:text=dividing%20the%20day%20into%2010%20decidays){.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"}.

When we add a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} offset to a [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet, with the resulting [[UTC](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} time.

The time in Zone [0]{.color0} matches UTC time with the [[UTC](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} offset. UNIX time and three [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} offsets are called [[UTC](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0}, [[UTC](https://en.wikipedia.org/wiki/UTC%2B12:00)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[+12:00](https://en.wikipedia.org/wiki/UTC%2B12:00)]{.color5}, and [[UTC](https://en.wikipedia.org/wiki/UTC%E2%88%9212:00)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[-12:00](https://en.wikipedia.org/wiki/UTC%E2%88%9212:00)]{.color5}. Starting with a [[UTC](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"}[[+00:00](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time)]{.color0} [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet results in Zone [0]{.color0} [tod]{.tool data-bs-toggle="tooltip" data-bs-title="time of day"}.

only three out of the [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zones are synchronized with a Dec time zone it will most likely be easier to shift the [hms]{.tool data-bs-toggle="tooltip" data-bs-title="hour minute second"} triplet to will result in days instead of decidays if we divide by the most Dec and [UTC]{.tool data-bs-toggle="tooltip" data-bs-title="Coordinated Universal Time"} time zones are not aligned. Whereas UNIX time is always synchronized with Zone [0]{.color0} and [UTC[+00:00]{.color0}](https://en.wikipedia.org/wiki/UTC%2B00:00#:~:text=the%20basis%20of%20Coordinated%20Universal%20Time), This method ensure that the result matches

[UTC time zone offsets](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place)

Drag the red⭕️circle across the [meridians](https://en.wikipedia.org/wiki/Meridian_%28geography%29#:~:text=words%2C%20it%20is-,a%20line%20of%20longitude,-.%20The%20position%20of) (vertical↕gray lines) on the map🗺️to see how changing time zones affects the time. Only the first digit of the Dec times shown above, the [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"}, varies across time zones, because the 10 Dec time zones, numbered 0 through 9 on the map🗺️, are each 1 [deci[turn](https://en.wikipedia.org/wiki/Turn_%28angle%29#:~:text=a%20unit%20of%20plane%20angle%20measurement%20equal%20to%202%CF%80%C2%A0radians%2C%20360%C2%A0degrees)]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a turn"} ([dt](https://en.wikipedia.org/wiki/Turn_%28angle%29#:~:text=the%20Greek%20letter,to%20one%20turn)) wide. Simply put, a [deciturn]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a turn"} of longitude translates into a [deciday]{.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} of time.

The leftmost vertical↕line on the map🗺️is [Meridian 0](https://en.wikipedia.org/wiki/18th_meridian_west#:~:text=a%20line%20of%20longitude%20that%20extends%20from%20the%20North%20Pole%20across%20the%20Arctic%20Ocean%2C%20Greenland%2C%20Iceland%2C%20the%20Atlantic%20Ocean%2C%20the%20Canary%20Islands%2C%20the%20Southern%20Ocean%2C%20and%20Antarctica%20to%20the%20South%20Pole), the Dec [International Date Line](https://en.wikipedia.org/wiki/International_Date_Line#:~:text=the%20line%20between%20the%20South%20and%20North%20Poles%20that%20is%20the%20boundary%20between%20one%20calendar%20day%20and%20the%20next) and [prime meridian](https://en.wikipedia.org/wiki/Prime_meridian#:~:text=an%20arbitrarily%2Dchosen%20meridian%20%28a%20line%20of%20longitude%29%20in%20a%20geographic%20coordinate%20system%20at%20which%20longitude%20is%20defined%20to%20be%200%C2%B0), which cuts across the Atlantic Ocean through Iceland🇮🇸just West of Africa🌍and is the boundary between Zone 9 and Zone 0, the rightmost and leftmost Dec time zones on the map🗺️, respectively. Arranging Dec time zones from 0 to 9 yields a [Pacific-centric](https://en.wikipedia.org/wiki/World_map#:~:text=south%2Dup%20map-,Pacific%2Dcentric%20map,-(more%20commonly%20used)) map🗺️.

While only positive Dec time zones are shown on the map🗺️, every Dec time zone can also be expressed as a negative number. Each pair of time zone numbers produces the same Dec time, but result in [Dec dates](/dec/date)🗓️that are 1 day apart. Negative time zone numbers can be useful for getting [Dec dates](/dec/date)🗓️to match [Gregorian calendar](https://en.wikipedia.org/wiki/Gregorian_calendar#:~:text=the%20calendar%20used%20in%20most%20parts%20of%20the%20world) dates🗓️with negative [UTC offsets](https://en.wikipedia.org/wiki/UTC_offset#:~:text=the%20difference%20in%20hours%20and%20minutes%20between%20Coordinated%20Universal%20Time%20(UTC)%20and%20the%20standard%20time%20at%20a%20particular%20place).

If you know your longitude in degrees (°) or [centi[turns](https://en.wikipedia.org/wiki/Turn_%28angle%29#:~:text=a%20unit%20of%20plane%20angle%20measurement%20equal%20to%202%CF%80%C2%A0radians%2C%20360%C2%A0degrees)]{.tool data-bs-toggle="tooltip" data-bs-title="hundredths of a turn"} ([ct](https://en.wikipedia.org/wiki/Turn_%28angle%29#:~:text=the%20Greek%20letter,to%20one%20turn)), you can look up your Dec time zone (TZ) in the table below.

| TZ<br>+ | TZ<br>- | Start<br>° | Mid<br>° | End<br>° | Start<br>$ct$ | Mid<br>$ct$ | End<br>$ct$ |
|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
| 9 | -1 | -54 | -36 | -18 | 90 | 95 | 100 |
| 8 | -2 | -90 | -72 | -54 | 80 | 85 | 90 |
| 7 | -3 | -126 | -108 | -90 | 70 | 75 | 80 |
| 6 | -4 | -162 | -144 | -126 | 60 | 65 | 70 |
| 5 | -5 | 162 | 180 | -162 | 50 | 55 | 60 |
| 4 | -6 | 126 | 144 | 162 | 40 | 45 | 50 |
| 3 | -7 | 90 | 108 | 126 | 30 | 35 | 40 |
| 2 | -8 | 54 | 72 | 90 | 20 | 25 | 30 |
| 1 | -9 | 18 | 36 | 54 | 10 | 15 | 20 |
| 0 | -10 | -18 | 0 | 18 | 0 | 5 | 10 |

Dec times in Zone 0 and 5 can be directly converted to and from UTC times with an offset of 0 and 12 [hours]{.teal}, respectively. The other Dec time zones

# Unit

Dec uses [metric prefixes](https://en.wikipedia.org/wiki/Metric_prefix#:~:text=a%20unit%20prefix%20that%20precedes%20a%20basic%20unit%20of%20measure%20to%20indicate%20a%20multiple%20or%20submultiple%20of%20the%20unit) to create [submultiples](https://en.wikipedia.org/wiki/Multiple_%28mathematics%29#Submultiple:~:text=of%20%22a%20being-,a%20unit%20fraction,-of%20b%22%20) of a day that can naturally be combined together into a single [decimal](https://en.wikipedia.org/wiki/Decimal#:~:text=system%20for%20denoting%20integer%20and%20non%2Dinteger%20numbers) number. Conversion between decimal units is as simple as moving↔︎️or removing❌the [decimal separator](https://en.wikipedia.org/wiki/Decimal_separator#:~:text=a%20symbol%20that%20separates%20the%20integer%20part%20from%20the%20fractional%20part%20of%20a%20number). In contrast, an [hh]{.teal}:[mm]{.olive}:[ss]{.purple} time is a [mixed-radix](https://en.wikipedia.org/wiki/Mixed_radix#:~:text=non%2Dstandard%20positional%20numeral%20systems%20in%20which%20the%20numerical%20base%20varies%20from%20position%20to%20position) number, where [hh]{.teal} is the [base-12](https://en.wikipedia.org/wiki/List_of_numeral_systems#:~:text=12-,Duodecimal,-%2C%20dozenal) or [base-24](https://en.wikipedia.org/wiki/List_of_numeral_systems#:~:text=24-,Quadravigesimal,-%5B48%5D) [hour]{.teal}, [mm]{.olive} is the [base-60](https://en.wikipedia.org/wiki/List_of_numeral_systems#:~:text=60-,Sexagesimal,-Babylonian%20numerals%20and) [minute]{.olive}, and [ss]{.purple} is the base-60 [second]{.purple}.

| Prefix | Power | Day | [hh]{.teal}:[mm]{.olive}:[ss]{.purple}.[sss]{.purple} |
|-------------------|---------------|---------------|-----------------------|
|  | 0 | 1 | 24:00:00.000 |
| deci | -1 | .1 | 02:24:00.000 |
| centi | -2 | .01 | 00:14:24.000 |
| milli | -3 | .001 | 00:01:26.400 |
| decimilli | -4 | .0001 | 00:00:08.640 |
| centimilli | -5 | .00001 | 00:00:00.864 |

To convert the [hour]{.teal} [h]{.teal}, [minute]{.olive} [m]{.olive}, and [second]{.purple} [s]{.purple} into the [deciday](https://en.wikipedia.org/wiki/Decimal_time#:~:text=dividing%20the%20day%20into%2010%20decidays){.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} [d]{.cyan}, Dec uses the following equation: [d]{.cyan} = [h]{.teal} ÷ 2.4 + [m]{.olive} ÷ 144 + [s]{.purple} ÷ 8640. The current equation values in Zone [\${browserZone}]{.lime} are: [\${browserTime.toFixed(4)}]{.cyan} = [\${Math.floor(hours).toString().padStart(2, "0")}]{.teal} ÷ 2.4 + [\${Math.floor(minutes).toString().padStart(2, "0")}]{.olive} ÷ 144 + [\${Math.floor(seconds).toString().padStart(2, "0")}]{.purple} ÷ 8640. Inversely, we can convert [decidays](https://en.wikipedia.org/wiki/Decimal_time#:~:text=dividing%20the%20day%20into%2010%20decidays){.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} into [hours]{.teal}: [h]{.teal} = [d]{.cyan} × 2.4, [minutes]{.olive}: [m]{.olive} = [h]{.teal} [mod](https://en.wikipedia.org/wiki/Modulo#:~:text=returns%20the%20remainder) 1 × 60, and [seconds]{.purple}: [s]{.purple} = [m]{.olive} [mod](https://en.wikipedia.org/wiki/Modulo#:~:text=returns%20the%20remainder) 1 × 60.

Instead of dealing with [hours]{.teal}, [minutes]{.olive}, and [seconds]{.purple}, we can convert the [UNIX timestamp](https://en.wikipedia.org/wiki/Unix_time#:~:text=the%20number%20of%20non%2Dleap%20seconds%20that%20have%20elapsed%20since%2000%3A00%3A00%20UTC%20on%201%C2%A0January%201970) [u]{.purple} into the Dec time [d]{.cyan}+[0]{.lime}. First, we divide [u]{.purple} by 86400 to convert seconds to days, then isolate the [fractional part](https://en.wikipedia.org/wiki/Fractional_part#:~:text=the%20excess%20beyond%20that%20number%27s%20integer%20part) of the [quotient](https://en.wikipedia.org/wiki/Quotient#:~:text=a%20quantity%20produced%20by%20the%20division%20of%20two%20numbers), and finally multiply by 10: [d]{.cyan} + [0]{.lime} = [u]{.purple} ÷ 86400 [mod](https://en.wikipedia.org/wiki/Modulo#:~:text=returns%20the%20remainder) 1 × 10. The current values in this equation are [\${browserTime.toFixed(4)}]{.cyan} + [0]{.lime} = [\${Math.floor(now / 1000)}]{.purple} ÷ 86400 [mod](https://en.wikipedia.org/wiki/Modulo#:~:text=returns%20the%20remainder) 1 × 10.

The concept of measuring time in decimal days is not novel. In the late 1700s, the [French Republican calendar](https://en.wikipedia.org/wiki/French_Republican_calendar#:~:text=a%20calendar%20created%20and%20implemented%20during%20the%20French%20Revolution) time system referred to [decidays](https://en.wikipedia.org/wiki/Decimal_time#:~:text=dividing%20the%20day%20into%2010%20decidays){.tool data-bs-toggle="tooltip" data-bs-title="tenths of a day"} as decimal [hours]{.teal}, [centidays]{.tool data-bs-toggle="tooltip" data-bs-title="hundredths of a day"} as [décimes](https://en.wikipedia.org/wiki/Decimal_time#:~:text=into%20tenths%2C%20or-,d%C3%A9cimes,-%2C%20instead%20of%20minutes), [millidays]{.tool data-bs-toggle="tooltip" data-bs-title="thousandths of a day"} as decimal [minutes]{.olive}, and [centimillidays]{.tool data-bs-toggle="tooltip" data-bs-title="hundred thousandths of a day"} as decimal [seconds]{.purple}. Similarly, [Swatch Internet Time](https://en.wikipedia.org/wiki/Swatch_Internet_Time#:~:text=a%20decimal%20time%20system%20introduced%20in%201998%20by%20the%20Swatch%20corporation), a [decimal time](https://en.wikipedia.org/wiki/Decimal_time#:~:text=the%20representation%20of%20the%20time%20of%20day%20using%20units%20which%20are%20decimally%20related) system introduced in 1998, uses the term ".beats" for [millidays]{.tool data-bs-toggle="tooltip" data-bs-title="thousandths of a day"}.

Swatch Internet Time differs from Dec in that it [has no time zones](https://en.wikipedia.org/wiki/Swatch_Internet_Time#Calculation_from_UTC+1:~:text=There%20are%20no%20time%20zones%20in%20Swatch%20Internet%20Time) and is obtained from the [[hours](https://en.wikipedia.org/wiki/Swatch_Internet_Time#Calculation_from_UTC+1:~:text=The%20formula%20for%20calculating%20the%20time%20in%20.beats%20from%20UTC%2B1)]{.teal}[, [minutes]{.olive}, and [seconds]{.purple}](https://en.wikipedia.org/wiki/Swatch_Internet_Time#Calculation_from_UTC+1:~:text=The%20formula%20for%20calculating%20the%20time%20in%20.beats%20from%20UTC%2B1) of [UTC+01:00](https://en.wikipedia.org/wiki/UTC%2B01:00#:~:text=a%20time%20offset%20from%20UTC%20of%20%2B01%3A00). In contrast, the major innovations described in this article are the Dec time zone system and the simple equation for obtaining the Dec time in Zone 0 from a UNIX timestamp, but Dec has much more to offer than [deciday](https://en.wikipedia.org/wiki/Decimal_time#:~:text=dividing%20the%20day%20into%2010%20decidays){.tool data-bs-toggle="tooltip" data-bs-title="a tenth of a day"} times and zones.

# Next

The next article in the [Dec section](/dec) of my site compares Dec to the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#:~:text=an%20international%20standard%20covering%20the%20worldwide%20exchange%20and%20communication%20of%20date%20and%20time%2Drelated%20data) international standard for dates and times. Like ISO 8601, Dec allows for [combined date and time representations](https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations) that can be paired up to express [time intervals](https://en.wikipedia.org/wiki/ISO_8601#Time_intervals:~:text=the%20intervening%20time%20between%20two%20time%20points). In Dec, the combination of a date and time is called a snap🫰and a time interval expressed as a pair of snaps is called a span🌈.

My [ISO 8601 article](/dec/iso) is unique because it avoids the use of Observable in favor of leveraging [Jupyter](https://jupyter.org) support in Quarto to make the code underlying Dec available in multiple programming languages. Observable is a great visualization tool but does not translate well into Jupyter notebooks. After the next article, I return to the use of Observable in my Dec [snap](/dec/span)🫰and [span](/dec/span)🌈articles.

::: {#timenav}
{{< include /asset/_decnav.qmd >}}
:::

# Cite

Please spread the good word about Dec using the citation information at the bottom of this article. You may also want to cite the Observable notebooks that I adapted into the clock🕓, bar📊chart, map🗺️, and daylight☀️plot visualizations in this article or the 2014 blog post which proposed a system of 20 decimal time zones, each 5 [centidays]{.tool data-bs-toggle="tooltip" data-bs-title="hundredths of a day"} wide, based on the [Greenwich Meridian](https://en.wikipedia.org/wiki/Prime_meridian_(Greenwich)#:~:text=a%20geographical%20reference%20line%20that%20passes%20through%20the%20Royal%20Observatory%2C%20Greenwich%2C%20in%20London%2C%20England):

-   [Pearson, Tom](https://www.2x2.graphics). [[2013]{.underline}]{.yellow}[+[124]{.cyan}]{.underline}. “Simple D3 clock.” [\${decYear}]{.yellow}+[\${decDate}]{.cyan}. [https://observablehq.com/\@d3/simple-clock](https://observablehq.com/@d3/simple-clock){.uri}.
-   [Heyen, Frank](https://fheyen.github.io). [[2021]{.underline}]{.yellow}[+[246]{.cyan}]{.underline}. “BarChart Clock.” [\${decYear}]{.yellow}+[\${decDate}]{.cyan}. [https://observablehq.com/\@fheyen/barchart-clock](https://observablehq.com/@fheyen/barchart-clock){.uri}.
-   [Johnson, Ian](https://enjalot.github.io). [[2021]{.underline}]{.yellow}[+[090]{.cyan}]{.underline}. “Draggable World Map Coordinates Input.” [\${decYear}]{.yellow}+[\${decDate}]{.cyan}. [https://observablehq.com/\@enjalot/draggable-world-map-coordinates-input](https://observablehq.com/@enjalot/draggable-world-map-coordinates-input){.uri}.
-   [Bridges, Dan](https://www.danbridges.org). [[2021]{.underline}]{.yellow}[+[311]{.cyan}]{.underline}. “Visualizing Seasonal Daylight.” [\${decYear}]{.yellow}+[\${decDate}]{.cyan}. [https://observablehq.com/\@dbridges/visualizing-seasonal-daylight](https://observablehq.com/@dbridges/visualizing-seasonal-daylight){.uri}.
-   [Clements, John](https://www.brinckerhoff.org). [[2014]{.underline}]{.yellow}[+[091]{.cyan}]{.underline}, “Decimal Time Zones.” [\${decYear}]{.yellow}+[\${decDate}]{.cyan}. <https://www.brinckerhoff.org/blog/2014/05/31/decimal-time-zones>.

```{ojs}
//| echo: false
//| output: false
function unix2dote(unix, zone, offset = 719468) {
  return [(unix ?? Date.now()) / 86400000 + (
    zone = zone ?? -Math.round(
      (new Date).getTimezoneOffset() / 144)
    ) / 10 + offset, zone]
}
function unix2dote1(unix, zone, offset = 719468) {
  return [
    (unix ?? Date.now()) / 86400000
    + (zone = zone ?? (10 - Math.round(
        (new Date).getTimezoneOffset() / 144)) % 10
      ) / 10 + offset, zone]
}
function dote2date(dote, zone = 0) {
  const cote = Math.floor((
      dote >= 0 ? dote
      : dote - 146096
    ) / 146097),
  dotc = dote - cote * 146097,
  yotc = Math.floor((dotc
    - Math.floor(dotc / 1460)
    + Math.floor(dotc / 36524)
    - Math.floor(dotc / 146096)
  ) / 365);
  return [
    yotc + cote * 400,
    dotc - (yotc * 365
      + Math.floor(yotc / 4)
      - Math.floor(yotc / 100)
  ), zone]}
function getEot(day) {
  const gamma = 2 * Math.PI * day / 365
    return (
      1.49504245e-5 +
      -4.1898733e-2 * Math.cos(gamma) +
      -2.9237036e-2 * Math.sin(gamma) +
      -4.5694380e-2 * Math.cos(2 * gamma) +
      5.17560175e-2 * Math.sin(2 * gamma)
    )
}
dz = unix2dote(now)
decYear = ydz[0].toString().padStart(4, "0")
zeroDote = unix2dote(now, 0)[0]
zeroTime = zeroDote % 1
zeroDate = dote2date(zeroDote)
zeroYear = zeroDate[0]
zeroYda = zeroDate[1]
zeroDoy = Math.floor(zeroYda)
zeroIsLeap = isLeapYear(zeroYear)
zeroYdaHsl = textcolor(zeroYda.toFixed(5), d3.color(piecewiseColor(zeroYda / (365 + zeroIsLeap))).formatHex())
zeroTimeHsl0 = textcolor(zeroTime.toFixed(5).slice(1), d3.color(piecewiseColor(zeroTime)).formatHex())
zeroTimeHsl1 = textcolor(zeroTime.toFixed(5).slice(1), d3.color(piecewiseColor(zeroTime)).formatHex())
zeroTimeHsl2 = textcolor((zeroTime * 10).toFixed(4), d3.color(piecewiseColor(zeroTime)).formatHex())
zeroTimeHsl3 = textcolor((zeroTime * 10).toFixed(4), d3.color(piecewiseColor(zeroTime)).formatHex())
zeroTimeHsl4 = textcolor((zeroTime * 10).toFixed(4), d3.color(piecewiseColor(zeroTime)).formatHex())
zeroTimeHsl5 = textcolor((zeroTime * 10).toFixed(5), d3.color(piecewiseColor(zeroTime)).formatHex())
zeroDotyHsl = textcolor(zeroDoy.toString().padStart(3, "0"), d3.color(piecewiseColor(zeroDoy / (365 + zeroIsLeap))).formatHex())
zeroDoteHsl = textcolor(zeroDote.toFixed(5), d3.color(piecewiseColor(zeroDote % 1)).formatHex())
zeroYearHsl = textcolor(zeroYear, d3.color(piecewiseColor(zeroYear % 1000 / 1000)).formatHex())
browserDote = unix2dote(now)
browserTime = browserDote[0] % 1 * 10
browserZone = browserDote[1]
browserSign = browserZone > 0 ? "-" : "+"
zone0time = (browserTime - browserZone + 10) % 10
hours = browserTime * 2.4
minutes = hours % 1 * 60
seconds = minutes % 1 * 60
selectedDote = unix2dote(now, long2zone(location[0]))
selectedExact = selectedDote[0] % 1
selectedExactN = (1 - selectedExact) % 1
selectedZone = selectedDote[1]
ydz = dote2date(...selectedDote)
decDate = Math.floor(ydz[1])
decTime = (selectedExact * 10).toFixed(4)
decTimeN = (selectedExactN * 10).toFixed(4)
barDD = decTime[0]
barDDN = decTimeN[0]
barMils = decTime.slice(2, 4)
barMilsN = decTimeN.slice(2, 4)
barBeats = decTime.slice(4, 6)
barBeatsN = decTimeN.slice(4, 6)
function lati2turn(degrees = -180, e = 3) {
  // turns: e=0, deciturns: e=1, etc.
  return (degrees %= 360) / (360 / 10**e) % 10**e;
}
graticule = d3.geoGraticule().stepMinor([36,36]).stepMajor([36,36])()
graticule.coordinates = graticule.coordinates.map(
  i => i.map(j => j.map((k, index, arr) => i.length === 3 && index === 0 ? k - 18 : k))
)
function long2turn(degrees = -180, e = 3) {
  // turns: e=0, deciturns: e=1, etc.
  return (((degrees %= 360) < 0 ? degrees + 360 : degrees) + 18) / (360 / 10**e) % 10**e;
}
// https://github.com/topojson/world-atlas
world = d3.json("https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json")
countries = topojson.feature(world, world.objects.countries)
topojson = require("topojson-client@3")
function long2zone(degrees = -180) {
  return Math.floor(long2turn(degrees, 1));
}
function year2leap(year = 1970) {
    return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}
// https://observablehq.com/@dbridges/visualizing-seasonal-daylight
solarSystem = (root, vizwidth, location, date, hour, darkmode) => {
  const earthRadius = 0.065 * vizwidth;
  // const sunRadius = 0.015 * vizwidth;
  const solarSystemRadius = vizwidth / 2 - (vizwidth < 500 ? 4 : 20);
  const stretch = 0.06;
  const solarAngle = getSolarAngle(date);
  const solarAngleDeg = (solarAngle * 180) / Math.PI;
  const x = solarSystemRadius * Math.sin(solarAngle);
  const y = stretch * solarSystemRadius * Math.cos(solarAngle);
  const spin = 180 + -location[0] + solarAngleDeg + 360 * ((hour + 12) / 24);
  const earthGeo = { type: "Sphere" };
  const projection = d3
    .geoOrthographic()
    .fitWidth(earthRadius * 2, earthGeo)
    .rotate([spin, 0, 23.5])
    .translate([0, 0]);
  const staticProjection = d3
    .geoOrthographic()
    .fitWidth(earthRadius * 2, earthGeo)
    .rotate([solarAngleDeg - 90, 0])
    .translate([0, 0]);
  const path = d3.geoPath(projection).pointRadius(1.5);
  const staticPath = d3.geoPath(staticProjection);
  const oceanColor = darkmode ? "#007FFF" : mapcolors.ocean;
  const landColor = darkmode ? "#0808" : mapcolors.land;
  const borderColor = darkmode ? "#eee" : "#333";
  const solarSystem = root
    .append("g")
    .attr("transform", `translate(${vizwidth / 2})`);
  // solarSystem.append("circle").attr("r", sunRadius).attr("fill", colors.sun);
  /* Draw orbit */
    solarSystem
      .append("ellipse")
      .attr("rx", solarSystemRadius)
      .attr("ry", stretch * solarSystemRadius)
      .attr("fill", "none")
      .attr("stroke-width", "1.25")
      .attr("stroke", "black");
    /* Draw month ticks */
    d3.range(12).map((m) => {
      const d = new Date(date.getFullYear(), m, 1);
      const angle = getSolarAngle(d);
      solarSystem
        .append("line")
        .attr("x1", (solarSystemRadius + 9) * Math.sin(angle))
        .attr("y1", (solarSystemRadius + 9) * stretch * Math.cos(angle))
        .attr("x2", (solarSystemRadius - 9) * Math.sin(angle))
        .attr("y2", (solarSystemRadius - 9) * stretch * Math.cos(angle))
        .attr("stroke-width", "1.75")
        .attr("stroke", "black");
      const startMonthAngle = getSolarAngle(new Date(date.getFullYear(), m, 1));
      solarSystem
        .append("text")
        .text(date2doty(d))
        .attr("x", (solarSystemRadius + 18 - width / 50) * Math.sin(startMonthAngle) * 1.1)
        .attr(
          "y",
          (solarSystemRadius + 2 - width / 3) * 6.2 * stretch * Math.cos(startMonthAngle) + Math.sign(Math.cos(startMonthAngle)) * 12
        )
        .attr("text-anchor", "middle")
        .attr("dominant-baseline", "middle")
        .attr("font-size", fontSize * (width < 300 ? .9 : width < 400 ? .95 : width < 500 ? 1 : width < 600 ? 1.05 : width < 700 ? 1.1 : 1.2) + width / 100)
        .attr("font-family", "sans-serif")
        .attr("fill", "black");
    });
    const earth = solarSystem
      .append("g")
      .attr("transform", `translate(${x}, ${y})`);
    function drawEarth() {
      earth.append("line").attr("y1", -1.5 * earthRadius).attr("y2", 1.5 * earthRadius).attr("stroke", "blue").attr("transform", `rotate(-23.5)`);
      earth.append("path").attr("d", path(earthGeo)).attr("fill", darkmode ? "#007FFF" : mapcolors.ocean).attr("id", "globeOcean");
      earth.append("path").attr("d", path(land)).attr("fill", darkmode ? "#0808" : mapcolors.land).attr("id", "globeLand");
      earth.append("path").attr("d", path(countries)).attr("stroke-width", ".08").attr("fill", "none").attr("stroke", darkmode ? "#eee" : "#333").attr("id", "globeBorders");
      path.pointRadius(5.5);
      earth.append("path").attr("d", path({ type: "Point", coordinates: location })).attr("fill", "none").attr("stroke-width", .6).attr("stroke", "black");
      path.pointRadius(4.5);
      earth.append("path").attr("d", path({ type: "Point", coordinates: location })).attr("fill", "none").attr("stroke-width", 2.25).attr("stroke", "red");
  }
  drawEarth();
}
function greg2doty(month = 1, day = 1) {
    return Math.floor(
        (153 * (month > 2 ? month - 3 : month + 9) + 2) / 5 + day - 1
)}
function date2doty(date) {
  return greg2doty(date.getMonth() + 1, date.getDate())
}
function date2doty1(date) {
  return greg2doty(date.getMonth() + 1, date.getDate())
}
// https://observablehq.com/@dbridges/visualizing-seasonal-daylight
// globe = (root, { vizwidth, location, date, hour }) => {
//   const solarAngle = getSolarAngle(date);
//   const solarAngleDeg = toDegrees(solarAngle);
//   const hourSpin = 360 * ((hour + 12) / 24);
//   const spin = (180 + -location[0] + solarAngleDeg + hourSpin);
//   const tilt = -15;
//   const projection = d3.geoOrthographic()
//                        .fitWidth(vizwidth, graticule)
//                        .rotate([spin, tilt, 23.5]);
//   const path = d3.geoPath(projection);
//   const unClippedProjection = d3.geoOrthographic()
//                                 .clipAngle(null)
//                                 .fitWidth(vizwidth, graticule)
//                                 .rotate([spin, tilt, 23.5]);
//   const unClippedPath = d3.geoPath(unClippedProjection);
//   const staticProjection = d3.geoOrthographic()
//                              .fitWidth(vizwidth, graticule)
//                              .rotate([solarAngleDeg - 90, tilt]);
//   const staticPath = d3.geoPath(staticProjection);
//   const background = root.append("g");
//   const earth = root.append("g").style("opacity", 0.75);
//   const foreground = root.append("g");
//   earth.append("path")
//     .attr("d", path({type: "Sphere"}))
//     .attr("fill", mapcolors.ocean)
//     .attr("stroke", "#9ecbda");
//   earth.append("path")
//     .attr("d", path(land))
//     .attr("fill", mapcolors.land);
//   earth.append("path")
//     .attr("d", path(countries))
//     .attr("stroke-width", "1")
//     .attr("fill", "none")
//     .attr("stroke", "#000");
//   background.append("path")
//     .attr("d", unClippedPath({type: "Point", coordinates: location}))
//     .attr("fill", "red");
//   const latitudeCoords = (latitude, start, end) => {
//     const longitudes = d3.range(start, end, 2).concat(end);
//     return longitudes.map(d => [d, latitude]);
//   }
//   const correctSpin = d3.geoRotation([-hourSpin, 0]);
//   const correctTilt = d3.geoRotation([6, 0, 0]);
//   /* total angular extent of day/night */
//   const dayExtent = 360 * dayLength(date, location[1]) / 24;
//   const nightExtent = 360 - dayExtent;
//   const dayLine = {
//     type: "LineString",
//     coordinates: latitudeCoords(location[1],
//                                 location[0] - dayExtent / 2,
//                                 location[0] + dayExtent / 2).map(d => correctSpin(d))
//   };
//   const nightLine = {
//     type: "LineString",
//     coordinates: latitudeCoords(location[1],
//                                 location[0] - dayExtent / 2 - nightExtent,
//                                 location[0] - dayExtent / 2).map(d => correctSpin(d))
//   };
//   background.append("path")
//     .attr("d", unClippedPath(dayLine))
//     .attr("fill", "none")
//     .attr("stroke", mapcolors.day)
//     .attr("stroke-width", 3);
//   background.append("path")
//     .attr("d", unClippedPath(nightLine))
//     .attr("fill", "none")
//     .attr("stroke", mapcolors.night)
//     .attr("stroke-width", 3);
//   foreground.append("path")
//     .attr("d", path(dayLine))
//     .attr("fill", "none")
//     .attr("stroke", mapcolors.day)
//     .attr("stroke-width", 3);
//   foreground.append("path")
//     .attr("d", path(nightLine))
//     .attr("fill", "none")
//     .attr("stroke", mapcolors.night)
//     .attr("stroke-width", 3);
//   foreground.append("path")
//     .attr("d", path({type: "Point", coordinates: location}))
//     .attr("stroke-width", .5)
//     .attr("stroke", "black")
//     .attr("fill", "red");
//   const shadowPolygon = [[0, -90], [0, 0], [0, 90], [180, 0], [0, -90]].map(d => correctTilt(d));
//   foreground.append("path")
//     .attr("d", staticPath({type: "Polygon", coordinates: [shadowPolygon]}))
//     .attr("fill", "rgba(0, 0, 0, 0.25)");
// }
dayOfYear = (date) => {
  const yearStart = new Date(date.getFullYear(), 0, 1+60);
  return Math.floor((date.getTime() - yearStart.getTime())/86400000) + 1
}
// https://observablehq.com/@dbridges/visualizing-seasonal-daylight
daylightPlot = (
  root,
  { vizwidth, height, year, latitude, defaultDate, defaultHour }
) => {
  const margin = { top: 32, bottom: 32, left: 32, right: 0 };
  const chartWidth = vizwidth - margin.left - margin.right;
  const chartHeight = height - margin.top - margin.bottom;
  const yTickValues =
    width > 380 ? [3, 6, 9, 12, 15, 18, 21] : width > 90 ? [6, 12, 18] : [12];
  const yScale = d3
    .scaleLinear()
    .domain([0, 24])
    .range([margin.left, margin.left + chartWidth])
    .clamp(true);
  // y-axis scale
  const xScale = d3
    .scaleTime()
    .domain([new Date(year, 0, 61), new Date(year, 11, 91)])
    .range([margin.top, margin.top + chartHeight])
    .clamp(true);
  // y-axis labels
  const xAxis = d3
    .axisBottom(xScale)
    .tickValues(d3.timeMonth.range(new Date(year, 0, 60), new Date(year, 12, 57)))
    .tickSize(chartWidth)
    .tickFormat(date2doty1);
  const yAxis = d3
    .axisLeft(yScale)
    .tickValues(yTickValues)
    .tickSize(chartHeight)
    .tickFormat((d) => { return `${d / .024}` });
  let date = defaultDate || new Date();
  let hour = defaultHour != null ? defaultHour : date.getHours();
  const handleMouseMove = (e) => {};
  root
    .append("rect")
    .attr("y", margin.left)
    .attr("x", margin.top)
    .attr("height", chartWidth)
    .attr("width", chartHeight)
    .attr("ry", 0.05 * vizwidth)
    .attr("fill", mapcolors.night);
  root
    .append("g")
    .attr("transform", `translate(0, ${margin.top})`)
    .call(xAxis)
    .call((g) => g.select(".domain").remove())
    .call((g) => g.selectAll(".tick").attr("color", mapcolors.grid))
    .call((g) => g.selectAll(".tick text").attr("font-size", (width < 300 ? .7 : width < 325 ? .725 : width < 350 ? .75 : width < 375 ? .8 : width < 400 ? .9 : width < 450 ? .95 : width < 500 ? 1 : width < 600 ? 1.2 : width < 700 ? 1.3 : 1.4) * fontSize))
    .call((g) => g.selectAll(".tick text").attr("color", "black"))
    .call((g) => g.selectAll(".tick line").attr("stroke-dasharray", "5 3"));
  root
    .append("g")
    .attr("transform", `translate(${margin.left + chartHeight}, 0)`)
    .call(yAxis)
    .call((g) => g.select(".domain").remove())
    .call((g) => g.selectAll(".tick").attr("color", mapcolors.grid))
    .call((g) => g.selectAll(".tick text").attr("font-size", (width < 400 ? .9 : width < 500 ? 1 : width < 600 ? 1.1 : width < 700 ? 1.2 : 1.3) * fontSize))
    .call((g) => g.selectAll(".tick text").attr("color", "black"))
    .call((g) => g.selectAll(".tick line").attr("stroke-dasharray", "5 3"));
  root
    .append("text")
    .text("Time of day")
    .attr("x", margin.bottom + (width < 275 ? -102 : width < 300 ? -106 : width < 325 ? -108 : width < 350 ? -115 : width < 375 ? -120 : width < 400 ? -128 : width < 425 ? -130 : width < 450 ? -132 : width < 475 ? -136 : width < 500 ? -141 : width < 525 ? -142 : width < 550 ? -148 : width < 575 ? -149 : width < 600 ? -154 : width < 650 ? -157 : width < 675 ? -157 : width < 700 ? -161 : width < 725 ? -160 : width < 750 ? -165 : width < 775 ? -169 : -173))
    .attr("y", margin.top - (width < 400 ? 33 : width < 500 ? 35 : width < 600 ? 37 : width < 700 ? 40 : 42))
    .attr("text-anchor", "middle")
    .attr("font-size", fontSize * (width < 300 ? .8 : width < 400 ? .9 : width < 500 ? 1 : width < 600 ? 1.1 : width < 700 ? 1.2 : 1.25) + width / 100)
    .attr("font-family", "sans-serif")
    .attr("transform", "rotate(-90)")
    .attr("fill", "black");
  root
    .append("text")
    .text("Day of year")
    .attr("x", margin.left + width / 2 - (width < 500 ? 30 : width < 600 ? 28 : width < 700 ? 24 : 22))
    .attr("y", margin.top + chartHeight / 4 + margin.bottom + (width < 275 ? 10 : width < 300 ? 18 : width < 325 ? 19 : width < 350 ? 22 : width < 375 ? 30 : width < 400 ? 37 : width < 450 ? 39 : width < 475 ? 40 : width < 500 ? 44 : width < 550 ? 50 : width < 600 ? 51 : width < 650 ? 50 : width < 700 ? 44 : width < 750 ? 40 : 43))
    .attr("text-anchor", "middle")
    .attr("font-size", fontSize * (width < 300 ? .95 : width < 400 ? 1 : width < 500 ? 1.05 : width < 600 ? 1.15 : width < 700 ? 1.2 : 1.25) + width / 100)
    .attr("font-family", "sans-serif")
    .attr("fill", "black");
  const data = yearDates(year)
    .map((d) => [d, dayLength(d, latitude)])
    .filter(([_, d]) => d > 0);
  /* Render separate polygons for each continuous sequence of
   * days with more than 0 hours of day light
   */
  const polys = [];
  let currentPoly = [];
  for (let i = 0; i < data.length; i++) {
    const currentDate = data[i][0];
    const prevDate = (data[i - 1] || [])[0];
    if (
      i === 0 ||
      currentDate.getTime() - prevDate.getTime() < 3600 * 24 * 1000 * 1.5
    ) {
      currentPoly.push(data[i]);
    } else {
      polys.push(currentPoly);
      currentPoly = [data[i]];
    }
  }
  polys.push(currentPoly);
  polys.forEach((p) => {
    const points = [
      ...p.map(([d, l]) => `${xScale(d)},${yScale(12 - l / 2)}`),
      ...p.reverse().map(([d, l]) => `${xScale(d)},${yScale(12 + l / 2)}`)
    ].join(" ");
    root.append("polygon").attr("points", points).attr("fill", mapcolors.day);
  });
  /* Legend */
  const legend = root
    .append("g")
    .attr("transform", `translate(${margin.left + chartWidth / 2 - 64})`);
  legend
    .append("rect")
    .attr("x", width < 300 ? 63 : width < 500 ? 62 : width < 600 ? 61 : 60)
    .attr("y", width < 450 ? 8 : 1)
    .attr("rx", 5)
    .attr("width", fontSize * (width < 300 ? .95 : width < 400 ? 1 : width < 500 ? 1.05 : width < 600 ? 1.15 : width < 700 ? 1.2 : 1.25) + width / 100)
    .attr("height", fontSize * (width < 300 ? .95 : width < 400 ? 1 : width < 500 ? 1.05 : width < 600 ? 1.15 : width < 700 ? 1.2 : 1.25) + width / 100)
    .attr("fill", mapcolors.day);
  legend
    .append("text")
    .attr("x", width < 400 ? 82 : width < 500 ? 85 : width < 600 ? 87 : 90)
    .attr("y", width < 300 ? 22 : width < 400 ? 23 : width < 450 ? 24 : width < 500 ? 18 : width < 600 ? 20 : width < 700 ? 21 : 23)
    .attr("font-size", fontSize * (width < 300 ? .95 : width < 400 ? 1 : width < 500 ? 1.05 : width < 600 ? 1.15 : width < 700 ? 1.2 : 1.25) + width / 100)
    .attr("font-family", "sans-serif")
    .text("Day");
  legend
    .append("rect")
    .attr("x", width < 400 ? -10 : width < 500 ? -20 : width < 600 ? -40 : -39)
    .attr("y", width < 450 ? 8 : 1)
    .attr("rx", 5)
    .attr("width", fontSize * (width < 300 ? .95 : width < 400 ? 1 : width < 500 ? 1.05 : width < 600 ? 1.15 : width < 700 ? 1.2 : 1.25) + width / 100)
    .attr("height", fontSize * (width < 300 ? .95 : width < 400 ? 1 : width < 500 ? 1.05 : width < 600 ? 1.15 : width < 700 ? 1.2 : 1.25) + width / 100)
    .attr("fill", mapcolors.night);
  legend
    .append("text")
    .attr("x", width < 400 ? 11 : width < 500 ? 4 : width < 600 ? -12 : -9)
    .attr("y", width < 300 ? 22 : width < 400 ? 23 : width < 450 ? 24 : width < 500 ? 18 : width < 600 ? 19 : width < 700 ? 21 : 23)
    .attr("font-size", fontSize * (width < 300 ? .95 : width < 400 ? 1 : width < 500 ? 1.05 : width < 600 ? 1.15 : width < 700 ? 1.2 : 1.25) + width / 100)
    .attr("font-family", "sans-serif")
    .text("Night");
  /* Time and date controls */
  const dateLine = root.append("g");
  const updateControlPositions = () => {
    dateLine
      .select("line")
      .attr("y1", yScale(0))
      .attr("x1", xScale(date))
      .attr("y2", yScale(24))
      .attr("x2", xScale(date));
    dateLine
      .select("rect")
      .attr("y", yScale(0))
      .attr("x", xScale(date) - 4);
    root
      .select("#time-control")
      .attr("cy", yScale(hour))
      .attr("cx", xScale(date));
  };
  const dispatchDateHourChange = () => {
    const detail = { date, hour };
    const changeEvent = new CustomEvent(EventType.DateHourChange, {
      detail,
      bubbles: true
    });
    root.node().dispatchEvent(changeEvent);
  };
  const handleDateLineDrag = ({ x }) => {
    date = xScale.invert(x);
    updateControlPositions();
    dispatchDateHourChange();
  };
  const handleTimeCircleDrag = ({ y }) => {
    hour = yScale.invert(y);
    updateControlPositions();
    dispatchDateHourChange();
  };
  dateLine.append("line").attr("stroke-width", 4).attr("stroke", "red");
  dateLine
    .append("rect")
    .attr("height", chartWidth)
    .attr("width", 8)
    .attr("fill", "rgba(0, 0, 0, 0)")
    .style("cursor", "row-resize")
    .call(d3.drag().on("drag", handleDateLineDrag));
  root
    .append("circle")
    .attr("id", "time-control")
    .attr("r", 12)
    .attr("fill", "red")
    .attr("stroke-width", .6)
    .attr("stroke", "black")
    .style("cursor", "pointer")
    .call(d3.drag().on("drag", handleTimeCircleDrag));
  updateControlPositions();
}
fontSize = 14;
getSolarAngle = (date) => (dayOfYear(date) + 10) / 365 * Math.PI * 2 - Math.PI / 2;
/*
 * Formulas uses the CBM model as reviewed here:
 * https://www.ikhebeenvraag.be/mediastorage/FSDocument/171/Forsythe+-+A+model+comparison+for+daylength+as+a+function+of+latitude+and+day+of+year+-+1995.pdf
 */
dayLength = (date, latitude) => {
  const yearStart = new Date(date.getFullYear(), 0, 1);
  const dayOfYear = Math.floor((date.getTime() - yearStart.getTime())/86400000) + 1;
  const revAngle = 0.2163108 + 2 * Math.atan(0.9671396 * Math.tan(0.00860 * (dayOfYear - 186)));
  const decAngle = Math.asin(0.39795 * Math.cos(revAngle));
  /* daylight coefficient selected for apparent sunrise/sunset */
  const p = 0.8333
  const intResult =
    (Math.sin((p * Math.PI) / 180) +
      Math.sin((latitude * Math.PI) / 180) * Math.sin(decAngle)) /
    (Math.cos((latitude * Math.PI) / 180) * Math.cos(decAngle));
  if (intResult >= 1) return 24;
  if (intResult <= -1) return 0;
  return 24 - 24 * Math.acos(intResult) / Math.PI;
}
yearDates = (year) => {
  const startDate = new Date(year, 0, 1+60);
  const endDate = new Date(year + 1, 0, 1+60);
  return d3.timeDay.range(startDate, endDate);
}
height = 0.65 * width;
EventType = ({
  LocationChange: "LOCATION_CHANGE",
  DateHourChange: "DATE_HOUR_CHANGE"
})
mapcolors = ({
  night: "#719fb6",
  day: "#ffe438",
  grid: "#4b6a79",
  ocean: "#adeeff",
  land: "#90ff7888",
  sun: "#ffb438"
})
toRadians = (val) => val * Math.PI / 180
toDegrees = (val) => val * 180 / Math.PI;
land = topojson.feature(world, world.objects.land);
d3 = require("d3@7", "d3-geo-projection@3")
function input(config) {
  let {
    form,
    type = "text",
    attributes = {},
    action,
    getValue,
    title,
    description,
    format,
    display,
    submit,
    options
  } = config;
  const wrapper = html`<div></div>`;
  if (!form)
    form = html`<form>
  <input name=input type=${type} />
  </form>`;
  Object.keys(attributes).forEach(key => {
    const val = attributes[key];
    if (val != null) form.input.setAttribute(key, val);
  });
  if (submit)
    form.append(
      html`<input name=submit type=submit style="margin: 0 0.75em" value="${
        typeof submit == "string" ? submit : "Submit"
      }" />`
    );
  form.append(
    html`<output name=output style="font: 14px Menlo, Consolas, monospace; margin-left: 0.1em; text-align:center;"></output>`
  );
  if (title)
    form.prepend(
      html`<div style="font: 700 0.9rem sans-serif; margin-bottom: 3px;">${title}</div>`
    );
  if (description)
    form.append(
      html`<div style="font-size: 0.85rem; font-style: italic; margin-top: 3px;">${description}</div>`
    );
  if (format)
    format = typeof format === "function" ? format : d3format.format(format);
  if (action) {
    action(form);
  } else {
    const verb = submit
      ? "onsubmit"
      : type == "button"
      ? "onclick"
      : type == "checkbox" || type == "radio"
      ? "onchange"
      : "oninput";
    form[verb] = e => {
      e && e.preventDefault();
      const value = getValue ? getValue(form.input) : form.input.value;
      if (form.output) {
        const out = display ? display(value) : format ? format(value) : value;
        if (out instanceof window.Element) {
          while (form.output.hasChildNodes()) {
            form.output.removeChild(form.output.lastChild);
          }
          form.output.append(out);
        } else {
          form.output.value = out;
        }
      }
      form.value = value;
      if (verb !== "oninput")
        form.dispatchEvent(new CustomEvent("input", { bubbles: true }));
    };
    if (verb !== "oninput")
      wrapper.oninput = e => e && e.stopPropagation() && e.preventDefault();
    if (verb !== "onsubmit") form.onsubmit = e => e && e.preventDefault();
    form[verb]();
  }
  while (form.childNodes.length) {
    wrapper.appendChild(form.childNodes[0]);
  }
  form.append(wrapper);
  return form;
}
d3format = require("d3-format@1")
// https://observablehq.com/@enjalot/draggable-world-map-coordinates-input
function worldMapCoordinates(config = {}, dimensions) {
  const {
    value = [], title, description, width = dimensions[0]
  } = Array.isArray(config) ? {value: config} : config;
  const height = dimensions[1];
  let [lon, lat] = value;
  lon = lon != null ? lon : null;
  lat = lat != null ? lat : null;
  const formEl = html`<form id="formEl" style="width: ${width}px;"></form>`;
  const context = DOM.context2d(width, height-width/14);
  const canvas = context.canvas;
  canvas.style.margin = `0px 0px -26px 0px`;
  const projection = d3
    .geoEquirectangular()
    .precision(0.1)
    .fitSize([width, height], { type: "Sphere" }).rotate([-153, 0]);
  const path = d3.geoPath(projection, context).pointRadius(2.5);
  formEl.append(canvas);
  function draw() {
    context.fillStyle = window.darkmode ? "black" : "white";
    context.fillRect(0, 0, width, height);
    context.beginPath(); path({type: "Sphere"});
    context.fillStyle = window.darkmode ? "#007FFF" : mapcolors.ocean;
    context.fill();
    context.beginPath();
    path(graticule);
    context.lineWidth = 0.95;
    context.strokeStyle = `#aaa`;
    context.stroke();
    context.beginPath();
    path(land);
    context.fillStyle = window.darkmode ? "#0808" : mapcolors.land;
    context.fill();
    context.beginPath();
    path(countries);
    context.lineWidth = .95;
    context.strokeStyle = window.darkmode ? "#aaa" : "#333";
    context.stroke();
    context.fillStyle = window.darkmode ? "#fff" : "#000";
    context.font = width < 760 ? "14px serif" : width < 990 ? "17px serif" : "23px serif";
    d3.range(-1.5, 342 + 1, 36).map(x =>  context.fillText(long2zone(x), ...projection([x, 82 - (width < 500) * 8.8])));
    d3.range(-1.5, 342 + 1, 36).map(x =>  context.fillText(long2zone(x), ...projection([x, -66 + (width < 500) * 1.1])));
    context.beginPath(), path(night), context.fillStyle = "rgba(0,0,255,0.1)", context.fill();
    context.beginPath(); path.pointRadius(17); path({type: "Point", coordinates: sun}); context.strokeStyle = "#0008"; context.fillStyle = "#ff08"; context.lineWidth = 1; context.stroke(); context.fill();
    if (lon != null && lat != null) {
      path.pointRadius(17); context.strokeStyle = "black";
      context.beginPath(); path({type: "Point", coordinates: [lon, lat]}); context.lineWidth = 1; context.stroke();
      context.lineWidth = 6;
      path.pointRadius(14); context.strokeStyle = "red";
      context.beginPath(); path({type: "Point", coordinates: [lon, lat]}); context.stroke();
    }
  }
  let drag = d3.drag()
    .on("drag", (event) => {
      let coords = projection.invert([event.x, event.y]);
      lon = +coords[0].toFixed(2);
      lat = +coords[1].toFixed(2);
      draw();
      canvas.dispatchEvent(new CustomEvent("input", { bubbles: true }));
    })
  d3.select(canvas).call(drag)
  canvas.onclick = function(ev) {
    const { offsetX, offsetY } = ev;
    let coords = projection.invert([offsetX, offsetY]);
    lon = +coords[0].toFixed(2);
    lat = +coords[1].toFixed(2);
    draw();
    canvas.dispatchEvent(new CustomEvent("input", { bubbles: true }));
  };
  draw();
  const form = input({
    type: "worldMapCoordinates",
    title,
    description,
    display: v => (width > 300) ? html`<div style="width: ${width}px; white-space: nowrap; color: window.darkmode ? #fff : #000; text-align: center; font: ${width / 40}px monospace; position: relative; top: ${-16 - width / 50}px;  margin-bottom: -.4em;">
            <span style="color: window.darkmode ? #fff : #000;">Zone:</span> ${lon != null ? long2zone(lon) : ""}
            &nbsp; &nbsp;
            <span style="color: window.darkmode ? #fff : #000;">Longitude:</span> ${lon != null ? (long2turn(lon)).toFixed(0) : ""}
            &nbsp; &nbsp;
            <span style="color: window.darkmode ? #fff : #000;">Latitude:</span> ${lat != null ? (lati2turn(lat)).toFixed(0) : ""}
          </div>` : '',
    getValue: () => [lon != null ? lon : null, lat != null ? lat : null],
    form: formEl
  });
  return form;
}
window.darkmode = document.getElementsByTagName("body")[0].className.match(/quarto-dark/) ? true : false;
document.getElementsByClassName("quarto-color-scheme-toggle")[0].onclick = function (e) {
  window.quartoToggleColorScheme();
  window.darkmode = document.getElementsByTagName("body")[0].className.match(/quarto-dark/) ? true : false;
  worldMapCoordinates.draw();
  app.drawEarth();
  return false;
};
sun = {
  const now = new Date;
  const day = new Date(+now).setUTCHours(0, 0, 0, 0);
  const t = solar.century(now);
  const longitude = (day - now) / 864e5 * 360 - 180;
  return [longitude - solar.equationOfTime(t) / 4, solar.declination(t)];
}
night = d3.geoCircle()
    .radius(90)
    .center(antipode(sun))
  ()
antipode = ([longitude, latitude]) => [longitude + 180, -latitude]
solar = require("solar-calculator@0.3/dist/solar-calculator.min.js")
viewof fancySecondsOFF = Inputs.toggle({
  label: "Ticking clock",
  value: true,
})
function setStyle(content, style = {}) {
  function yiq(color) {
    const {r, g, b} = d3.rgb(color);
    return (r * 299 + g * 587 + b * 114) / 1000 / 255; // returns values between 0 and 1
  }
  const {
    background,
    color = yiq(background) >= 0.6 ? "#111" : "white",
    padding = "0 1px",
    borderRadius = "4px",
    fontWeight = 900,
    fontSize = "1em",
    ...rest
  } = typeof style === "string" ? {background: style} : style;
  return htl.html`<span style=${{
    background,
    color,
    padding,
    borderRadius,
    fontWeight,
    ...rest
  }}>${content}</span>`;
}
function yiq(color) {
  const {r, g, b} = d3.rgb(color);
  return (r * 299 + g * 587 + b * 114) / 1000 / 255; // returns values between 0 and 1
}
function textcolor(content, style = {}) {
  const {
    background,
    color = yiq(background) > 0.51 ? "#000" : "white",
    padding = "0 5px",
    borderRadius = "4px",
    fontWeight = 400,
    fontFamily = "monospace",
    ...rest
  } = typeof style === "string" ? {background: style} : style;
  return htl.html`<span style=${{
    background,
    color,
    padding,
    borderRadius,
    fontWeight,
    fontFamily,
    ...rest
  }}>${content}</span>`;
}
function isLeapYear(y) {
  y += 1;
  return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
}
elapsed = {
  let i = 0;
  while (true) {
    yield Promises.tick(864, ++i);
  }
}
piecewiseColor = d3.piecewise(d3.interpolateRgb, [
  "#f00",    //  0   0 red
  "#f50",    //  0.25  20 yr
  "#f60",    //  0.5   24 yr orangered
  "#f70",    //  0.75  28 yr
  "#f90",    //  1     36 yr orange
  "#fb0",    //  1.25  44 yr
  "#fc0",    //  1.5   48 yr yelloworange
  "#fd0",    //  1.75  52 yr
  "#ff0",    //  2     60 yellow
  "#ef0",    //  2.25  64 gy
  "#df0",    //  2.5   68 gy limeyellow
  "#cf0",    //  2.75  72 gy
  "#af0",    //  3     80 gy lime
  "#8f0",    //  3.25  88 gy
  "#7f0",    //  3.5   92 gy greenlime
  "#6f0",    //  3.75  96 gy
  "#0f0",    //  4    120 green
  "#0f7",    //  4.25 148 cg
  "#0f9",    //  4.5  156 cg cyangreen
  "#0fb",    //  4.75 164 cg
  "#0ff",    //  5    180 cyan
  "#0cf",    //  5.25 192 bc
  "#0bf",    //  5.5  196 bc azurecyan
  "#0af",    //  5.75 200 bc
  "#08f",    //  6    208 bc azure
  "#06f",    //  6.25 216 bc
  "#05f",    //  6.5  220 bc blueazure
  "#04f",    //  6.75 224 bc
  "#00f",    //  7    240 blue
  "#50f",    //  7.25 260 mb
  "#60f",    //  7.5  264 mb purpleblue
  "#70f",    //  7.75 268 mb
  "#90f",    //  8    276 mb purple
  "#b0f",    //  8.25 284 mb
  "#c0f",    //  8.5  288 mb violetpurple
  "#d0f",    //  8.75 292 mb
  "#f0f",    //  9    300 magenta
  "#f0a",    //  9.25 320 rm
  "#f08",    //  9.5  328 rm
  "#f06",    //  9.75 336 rm
  "#f00",    //  0        0 red
])
slStr = `, 100%, 50%)`
elaTime = elapsed % 1e5
elaTimeHsl = textcolor(elaTime, `hsl(${d3.hsl(piecewiseColor(elaTime % 1000 / 1000)).h}` + slStr)
decMoty = Math.floor((5 * decDate + 2) / 153)
isoYear = decYear + (decMoty > 9)
month = decMoty < 10 ? decMoty + 3 : decMoty - 9
decHour = decTime * 24
decMinute = (decHour % 1) * 60
decSecond = (decMinute % 1) * 60
isoHour = Math.floor(decHour)
isoMinute = Math.floor(decMinute)
isoSecond = Math.floor(decSecond)
decDek = Math.floor(decDate / 10)
decDod = decDate % 10
decDotm = Math.floor(decDate - (153 * decMoty + 2) / 5 + 1)
selDote = unix2dote(selectedDate.getTime() - 86400000, 0)
selDate = Math.floor(dote2date(...selDote)[1])
selTime = selectedHour / 24
selTimeOne = selTime % 1
selTimeTen = selTime * 10 % 10
selSnap = selDate + selTime
selLati = lati2turn(location[1])
decDodHsl = textcolor(decDod, d3.color(piecewiseColor(decDod / 10)).formatHex())
decDateHsl = textcolor(decDate.toString().padStart(3, "0"), d3.color(piecewiseColor(decDate / (365 + isLeapYear(decYear)))).formatHex())
decTimeHsl = textcolor(decTime, d3.color(piecewiseColor(decTime / 10)).formatHex())
selDateHsl = textcolor(selDate.toString().padStart(3, "0"), d3.color(piecewiseColor(selDate / 365)).formatHex())
selLatiHsl = textcolor(selLati.toFixed(0), d3.color(piecewiseColor((selLati + 250) % 250 / 250)).formatHex())
selTimeDay = textcolor(selTimeOne.toFixed(3).slice(2), d3.color(piecewiseColor(selTime)).formatHex())
selTimeHsl0 = textcolor(selTimeTen.toFixed(4), d3.color(piecewiseColor(selTime)).formatHex())
selTimeHsl1 = textcolor(selTimeTen.toFixed(4), d3.color(piecewiseColor(selTime)).formatHex())
selZoneHsl = textcolor(selectedZone, d3.color(piecewiseColor(selectedZone / 10)).formatHex())
selSnapDay = textcolor(selSnap.toFixed(3).padStart(6, "0"), d3.color(piecewiseColor(selSnap / 365)).formatHex())
selSnapDec = textcolor((selSnap * 10).toFixed(4).padStart(9, "0"), d3.color(piecewiseColor(selSnap / 365)).formatHex())
decZoneHsl = textcolor(selectedZone, d3.color(piecewiseColor(selectedZone / 10)).formatHex())
viewof selectedDate = Inputs.input(date2022)
viewof selectedHour = Inputs.input(date2022.getHours())
date2022 = new Date(2022, new Date().getMonth(), new Date().getDate(), new Date().getHours())
function set(input, value) {
  input.value = value;
  input.dispatchEvent(new Event("input", {bubbles: true}));
}
hD121 = d3.hsl(piecewiseColor(121 / 365)).h
hD268 = d3.hsl(piecewiseColor(268 / 365)).h
hD305 = d3.hsl(piecewiseColor(305 / 365)).h
hD306 = d3.hsl(piecewiseColor(306 / 365)).h
h1by320 = d3.hsl(piecewiseColor(1 / 320)).h
h1by8640 = d3.hsl(piecewiseColor(1 / 8640)).h
hues = Object.fromEntries([
  .0083,
  .0166,
  .0229,
  .025,
  .287,
  .0333,
  .0416,
  .05,
  .125,
  .333,
  .375,
  .429,
  .533,
  .969,
  .999,
  ].map(i => [i, d3.hsl(piecewiseColor(i)).h])
);
// https://observablehq.com/@mattdzugan/population-by-time-zone-creating-a-dataset
populationByTimeZone = FileAttachment("../../asset/populationByTimeZone.json").json();
sortedPop = populationByTimeZone.sort(
  (a, b) => sortParams[1] ? sortFunc(a.number, b.number) : sortFunc(a.pop, b.pop)
)
sortFunc = sortParams[0] ? d3.ascending : d3.descending
popBySign = d3.rollup(sortedPop, v => d3.sum(v, d => d.pop / 1e9), d => d.Sign)
totalPop = d3.sum(sortedPop, d => d.pop / 1e9)
dzOff = unix2dote(now, offset)
ydzOff = dote2date(...dzOff)
decTimeOff = ydzOff[1] % 1
decSignOff = offset < 0 ? "+" : "–"
decOffsetPosi = (offset + 10) % 10
decOffsetNega = decOffsetPosi - 10
decOffsetHsl0 = textcolor(Math.abs(offset), `hsl(${d3.hsl(piecewiseColor(decOffsetPosi / 10)).h}` + slStr)
decOffsetHsl1 = textcolor(Math.abs(offset), `hsl(${d3.hsl(piecewiseColor(decOffsetPosi / 10)).h}` + slStr)
decOffsetHsl2 = textcolor(offset, `hsl(${d3.hsl(piecewiseColor(decOffsetPosi / 10)).h}` + slStr)
decOffsetHslP = textcolor(decOffsetPosi, `hsl(${d3.hsl(piecewiseColor(decOffsetPosi / 10)).h}` + slStr)
decOffsetHslN = textcolor(decOffsetNega, `hsl(${d3.hsl(piecewiseColor(decOffsetPosi / 10)).h}` + slStr)
decTimeOffHsl0 = textcolor((decTimeOff * 10).toFixed(4), `hsl(${d3.hsl(piecewiseColor(decTimeOff)).h}` + slStr)
decTimeOffHsl1 = textcolor((decTimeOff * 10).toFixed(4), `hsl(${d3.hsl(piecewiseColor(decTimeOff)).h}` + slStr)
decTimeOffHsl2 = textcolor((decTimeOff * 10).toFixed(4), `hsl(${d3.hsl(piecewiseColor(decTimeOff)).h}` + slStr)
decTimeOffHsl3 = textcolor((decTimeOff * 10).toFixed(4), `hsl(${d3.hsl(piecewiseColor(decTimeOff)).h}` + slStr)
decTimeOffLeapNum = offset * 320 + 1
decTimeOffLeapTodHsl = textcolor((decTimeOff * 10 + 1 / 320).toFixed(4), `hsl(${d3.hsl(piecewiseColor(decTimeOff)).h}` + slStr)
decTimeOffLeapTzoHsl = textcolor(`${decTimeOffLeapNum}/320`, `hsl(${d3.hsl(piecewiseColor((decTimeOffLeapNum / 320 + 10) % 10 / 10)).h}` + slStr)
utcOffsetM = -(new Date).getTimezoneOffset()
utcOffsetD = utcOffsetM / 144
utcOffsetP = (utcOffsetD + 10) % 10
decZone = ydz[2]
decZonePos = (decZone + 10) % 10
utcOffDiff = parseFloat((Math.round(utcOffsetD) - utcOffsetD).toFixed(2))
utcOffHslM = textcolor(utcOffsetM, `hsl(${d3.hsl(piecewiseColor(utcOffsetP / 10)).h}` + slStr)
utcOffHslD = textcolor(parseFloat(utcOffsetD.toFixed(2)), `hsl(${d3.hsl(piecewiseColor(utcOffsetP / 10)).h}` + slStr)
decZonHslP = textcolor(decZonePos, `hsl(${d3.hsl(piecewiseColor(decZonePos / 10)).h}` + slStr)
utcOffsetMdiffHsl = textcolor(parseFloat((utcOffDiff * 144).toFixed(2)), `hsl(${d3.hsl(piecewiseColor(utcOffDiff / 10)).h}` + slStr)
utcOffDiffHsl = textcolor(utcOffDiff, `hsl(${d3.hsl(piecewiseColor(utcOffDiff / 10)).h}` + slStr)
function date2dote(year = 1969, doty = 306, zone = 0) {
    const cote = Math.floor((year >= 0 ? year : year - 399) / 400), yote = year - cote * 400;
    return [cote * 146097 + yote * 365 + Math.floor(yote / 4) - Math.floor(yote / 100) + doty, zone]
}
leapSecondDotes = [
  [1972, 121],
  [1972, 305],
  [1973, 305],
  [1974, 305],
  [1975, 305],
  [1976, 305],
  [1977, 305],
  [1978, 305],
  [1979, 305],
  [1981, 121],
  [1982, 121],
  [1983, 121],
  [1985, 121],
  [1987, 305],
  [1989, 305],
  [1990, 305],
  [1992, 121],
  [1993, 121],
  [1994, 121],
  [1995, 305],
  [1997, 121],
  [1998, 305],
  [2005, 305],
  [2008, 305],
  [2012, 121],
  [2015, 121],
  [2016, 305],
].map(x => date2dote(...x)[0])
leapSecondDote = date2dote(leapSecondYear, leapSecondDate)[0]
leapCount = leapSecondDotes.filter(dote => leapSecondDote > dote).length;
leapColor = d3.color(piecewiseColor(leapCount / 86400)).formatHex()
leapCountHsl = textcolor(leapCount, leapColor)
frac = require("fraction.js")
leapFrac = frac(leapCount).div(8640).toFraction()
leapTzoHsl0 = textcolor(leapFrac, leapColor)
leapTzoHsl1 = textcolor(leapFrac, leapColor)
leapTzoHsl2 = textcolor(leapFrac, leapColor)
hmsTzo = frac(hmsinput[0]).div(24).add(hmsinput[1], 1440).add(hmsinput[2], 86400).mod(1)
hmsTzox10 = hmsTzo.mul(10)
pluralx10 = hmsTzox10.equals(1) ? "" : "s"
hmsRounded = hmsTzox10.round(digits - 1)
hmsRef = hmsRounded.sub(hmsTzox10)
hmsRefHsl = textcolor(hmsRef.abs().toFraction(), d3.color(piecewiseColor(Number(hmsRef.div(10)))).formatHex())
hmsRefSign = hmsRef.lt(0) ? "-" : "+"
hmsTzoHsl = textcolor(hmsTzox10.toFraction(), d3.color(piecewiseColor(Number(hmsTzo))).formatHex())
hmsRodHsl = textcolor(hmsRounded, d3.color(piecewiseColor(Number(hmsRounded.div(10)))).formatHex())
hmsTod = (zeroTime + hmsTzo) % 1
hmsTodHsl = textcolor((hmsTod * 10).toFixed(4), d3.color(piecewiseColor(hmsTod)).formatHex())
leapTod = (zeroTime + leapCount / 86400) % 1
leapDecidayTod = (leapTod * 10).toFixed(4)
leapTodHsl0 = textcolor(leapDecidayTod, d3.color(piecewiseColor(leapTod)).formatHex())
leapTodHsl1 = textcolor(leapDecidayTod, d3.color(piecewiseColor(leapTod)).formatHex())
longInputHsl = textcolor(longInput, d3.color(piecewiseColor(longInput / 10)).formatHex())
eot = getEot(leapSecondDate)
astTzo = eot + longInput
astTzoHsl = textcolor(astTzo.toFixed(4), d3.color(piecewiseColor(astTzo / 10)).formatHex())
solarNoon = (5 - astTzo + 10) % 10
solarNoonHsl = textcolor(solarNoon.toFixed(4), d3.color(piecewiseColor(solarNoon / 10)).formatHex())
solarDiff = zeroTime - solarNoon
solarSign = solarDiff < 0 ? "-" : "+"
solarDiffHsl = textcolor(Math.abs(solarDiff).toFixed(4), d3.color(piecewiseColor((solarDiff + 10) % 10 / 10)).formatHex())
eotHsl = textcolor(eot.toFixed(4), d3.color(piecewiseColor(eot / 10)).formatHex())
eotSum = (zeroTime + astTzo + 10) % 10
eotSumHsl = textcolor(eotSum.toFixed(4), d3.color(piecewiseColor(eotSum / 10)).formatHex())
// https://observablehq.com/@mcmcclur/adaptive-plotter
function build_samples(f, a, b, opts = {}) {
  let { N = 9, max_depth = 6 } = opts;
  let dx = (b - a) / N;
  let root_intervals = Array.from({ length: N }).map(
    (_, i) => new Interval(a + i * dx, a + (i + 1) * dx, 0)
  );
  root_intervals.forEach((I) => {
    I.fa = f(I.a);
    I.fb = f(I.b);
  });
  root_intervals.reverse();
  let stack = root_intervals;
  let cnt = 0;
  let pts = [];
  let nodeRight, nodeLeft;
  while (stack.length > 0 && cnt++ < 100000) {
    let node = stack.pop();
    if (test(f, node, opts)) {
      let midpoint = node.midpoint;
      let new_depth = node.depth + 1;
      if (new_depth <= max_depth) {
        let a_left = node.a;
        let b_left = midpoint;
        nodeLeft = new Interval(a_left, b_left, new_depth);
        nodeLeft.fa = f(a_left);
        nodeLeft.fb = f(b_left);
        node.left = nodeLeft;

        let a_right = midpoint;
        let b_right = node.b;
        nodeRight = new Interval(a_right, b_right, new_depth);
        nodeRight.fa = f(a_left);
        nodeRight.fb = f(b_left);
        node.right = nodeRight;

        stack.push(nodeRight);
        stack.push(nodeLeft);
      } else {
        pts.push(node.a);
      }
    } else {
      pts.push(node.a);
    }
  }
  pts.push(b);
  //  pts = pts.map(x => ({ x: x, y: f(x) }));
  pts = pts.map((x) => [x, f(x)]);
  if (opts.show_roots) {
    let function_roots = [];
    pts.forEach(function (o, i) {
      if (i < pts.length - 1 && Math.sign(o.y) != Math.sign(pts[i + 1].y)) {
        function_roots.push((o.x + pts[i + 1].x) / 2);
      }
    });
    pts.function_roots = function_roots;
  }
  return pts;
}
function test(f, I, opts = {}) {
  let { angle_tolerance = 0.01, check_roots = false } = opts;
  let a = I.a;
  let b = I.b;
  let dx2 = (b - a) / 2;
  let m = (a + b) / 2;
  let fm = f(m);
  I.midpoint = m;
  I.f_mid = fm;
  if (check_roots && Math.sign(I.fa) != Math.sign(I.fb)) {
    return true;
  }
  let alpha = Math.atan((I.f_mid - I.fa) / dx2);
  let beta = Math.atan((I.fb - I.f_mid) / dx2);
  return Math.abs(alpha - beta) > angle_tolerance;
}
class Interval {
  constructor(a, b, depth) {
    this.a = a;
    this.b = b;
    this.depth = depth;
  }
}
```

```{ojs}
//| echo: false
//| output: false
html`
<style>
.colorNight {
  background: #416f86;
  color: white;
  padding: 0px 2px 0px 4px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.colorDay {
  background: #ffe438;
  color: black;
  padding: 0px 3px 0px 4px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.colorBkg {
  background: ${window.darkmode ? "black" : "white"};
  color: ${window.darkmode ? "white" : "black"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color0 {
  background: hsl(0 100% 50%);
  color: ${yiq(`hsl(0, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color1by8640 {
  background: hsl(${h1by8640} 100% 50%);
  color: ${yiq(`hsl(${h1by8640}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color1 {
  background: hsl(300 100% 50%);
  color: ${yiq(`hsl(300, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color2 {
  background: hsl(280 100% 50%);
  color: ${yiq(`hsl(280, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color3 {
  background: hsl(240 100% 50%);
  color: ${yiq(`hsl(240, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color4 {
  background: hsl(200 100% 50%);
  color: ${yiq(`hsl(200, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color5 {
  background: hsl(180 100% 50%);
  color: ${yiq(`hsl(180, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color583 {
  background: hsl(129.88235294117646 100% 50%);
  color: ${yiq(`hsl(129.88235294117646, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color6 {
  background: hsl(120 100% 50%);
  color: ${yiq(`hsl(120, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color7 {
  background: hsl(80 100% 50%);
  color: ${yiq(`hsl(80, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color8 {
  background: hsl(60 100% 50%);
  color: ${yiq(`hsl(60, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color9 {
  background: hsl(40 100% 50%);
  color: ${yiq(`hsl(40, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color375 {
  background: hsl(${hues[0.375]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.375]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color0083 {
  background: hsl(${hues[0.0083]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.0083]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color0166 {
  background: hsl(${hues[0.0166]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.0166]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color55by24 {
  background: hsl(${hues[.0229]} 100% 50%);
  color: ${yiq(`hsl(${hues[.0229]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color125 {
  background: hsl(${hues[.125]} 100% 50%);
  color: ${yiq(`hsl(${hues[.125]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color025 {
  background: hsl(${hues[0.025]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.025]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color287 {
  background: hsl(${hues[0.287]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.287]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color333 {
  background: hsl(${hues[0.333]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.333]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color0333 {
  background: hsl(${hues[0.0333]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.0333]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color0416 {
  background: hsl(${hues[0.0416]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.0416]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color429 {
  background: hsl(${hues[0.429]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.429]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color05 {
  background: hsl(${hues[0.05]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.05]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color533 {
  background: hsl(${hues[0.533]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.533]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color969 {
  background: hsl(${hues[0.969]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.969]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color999 {
  background: hsl(${hues[0.999]} 100% 50%);
  color: ${yiq(`hsl(${hues[0.999]}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.color1by320 {
  background: hsl(${h1by320} 100% 50%);
  color: ${yiq(`hsl(${h1by320}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.colorD121 {
  background: hsl(${hD121} 100% 50%);
  color: ${yiq(`hsl(${hD121}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.colorD268 {
  background: hsl(${hD268} 100% 50%);
  color: ${yiq(`hsl(${hD268}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.colorD305 {
  background: hsl(${hD305} 100% 50%);
  color: ${yiq(`hsl(${hD305}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
.colorD306 {
  background: hsl(${hD306} 100% 50%);
  color: ${yiq(`hsl(${hD306}, 100%, 50%)`) > 0.51 ? "black" : "white"};
  padding: 0px 5px;
  border-radius: 4px;
  font-weight: 400;
  font-family: monospace;
}
</style>
`
```

```{=html}
<style>
svg.barclock {
  width: 100%;
  overflow: visible;
}
.tickLabel, .tickLabel1, .tickLabel2, .timeLabel {
  font-family: monospace;
  text-anchor: middle;
}
.timeLabel {
  text-anchor: start;
}
.timeBar, .timeBarFull, .timeBarFullN {
  x: 1px;
  height: 25px;
  rx: 5px;
  stroke: #aaa;
}
.tickDek, .tickDotd, .tickDotd1, .tickC, .tickC1, .tickM, .tickM1, .tickB, .tickB1 {
  stroke: none;
  fill: #666;
  width: 1px;
}
.analogclock {
  stroke: #000;
  font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
  overflow: visible;
}
.analogclock #rim {
  fill: none;
  stroke: #999;
  stroke-width: 3px;
}
.analogclock .second-hand {
  stroke-width: 3;
}
.analogclock .minute-hand {
  stroke-width: 8;
  stroke-linecap: round;
}
.analogclock .hour-hand {
  stroke-width: 12;
  stroke-linecap: round;
}
.analogclock .hands-cover {
  stroke-width: 3;
  fill: #fff;
}
.analogclock .second-tick {
  stroke-width: 3;
  fill: #000;
}
.analogclock .hour-tick {
  stroke-width: 8; // same as the minute hand
}
.analogclock .second-label {
  font-size: 18px;
}
.analogclock .hour-label {
  font-size: 32px
}
.clocks * {
  margin: -10px 0px 10px 0px;
  padding: 0px;
}
#title-block-header > div:nth-child(2) {
  display: none;
}
h4.hiddenheading, h5.hiddenheading {
  display: none;
}
div.cell-output:has(#daylightapp) {
  overflow: visible;
}
div.cell-output:has(#formEl) {
  overflow: visible;
}
#daylightapp {
  overflow: visible;
}
#daylightapp * {
  overflow: visible;
}
#solar-system * {
  overflow: visible;
}
#timezonepopstackedbar {
  overflow: visible;
}
#timezonepoptoggles div {
  display: flex;
}
#timezonepoptoggles div form {
  max-width: 180px;
}
#timezonepoptoggles div form label {
  max-width: 120px;
}
#timezonepoptoggles div form:nth-child(1) {
  margin-right: 8px;
}
#timezonepoptoggles div form:nth-child(2) label {
  max-width: 110px;
}
#timezonepoptoggles input[type=checkbox] {
  margin-top: 8px;
}
</style>
```
