Public
Edited
Sep 17, 2024
Insert cell
Insert cell
Insert cell
viewof selectedDate = html`<input type="date" value="2024-07-04"/>`
Insert cell
Insert cell
Insert cell
datenum(selectedDate)
Insert cell
datenum = (y, m = 1, d = 1, h = 0, mn = 0, s = 0) => {
if (y instanceof Date) {
s = y.getSeconds();
mn = y.getMinutes();
h = y.getHours();
m = y.getMonth() + 1;
d = y.getDate();
y = y.getFullYear();
}
return (
datedays(y, m, d) * by.day.step +
h * by.hour.step +
mn * by.minute.step +
s * by.second.step
);
}
Insert cell
numdate(datenum(selectedDate))
Insert cell
datenum(selectedDate)

Insert cell
divmul(datenum(selectedDate), by.year.step)
Insert cell
// Because of pre-gregorian dates, we have discrepancy between the step
[1000 * by.year.step / by.day.step, datedays(1000)]
Insert cell
[1 * by.year.step / by.day.step, datedays(1582+1)-datedays(1582)]
Insert cell
datedays(1582)-datedays(1582-1)
Insert cell
datedays(1582+1)-datedays(1582)
Insert cell
leapyear(1582)
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
datedays(2001)-datedays(2000)
Insert cell
datedays(1)-datedays(0)
Insert cell
datedays(2024, 2, 1) - datedays(2023,12,31)
Insert cell
numdate = (n) => [
div(n, by.year.step),
div(n, by.month.step, by.month.period),
0
]
/*const g = div(n, MS_PER_DAY);
let y = div(10000 * g + 14780, 3652425);
let ddd = g - (365 * y + div(y, 4) - div(y, 100) + div(y, 400));
if (ddd < 0) {
y = y - 1;
ddd = g - (365 * y + div(y, 4) - div(y, 100) + div(y, 400));
}
let mi = div(100 * ddd + 52, 3060);
let mm = ((mi + 2) % 12) + 1;
y = y + div(mi + 2, 12);
let dd = ddd - div(mi * 306 + 5, 10) + 1;
return [y, mm, dd];*/
Insert cell
datedays = (year, month, day) =>
// 365 days a year,
year * 365 +
// plus one days for every leap year since,
leaps(year - 1) +
(month && month > 1 ? (isleap(year) ? LEAP_YEAR_DAYS : YEAR_DAYS)[(month - 1) % 12] : 0) +
(day > 1 ? day - 1 : 0)
Insert cell
// Number of leap years between 0AD and the given year, inclusively.
leaps = (year) =>
!year || year < 0
? 0
: // Gregorian calendar
Math.floor(year / 4) -
Math.floor(year / 100) +
Math.floor(year / 400) -
// adjustment for missing leap years in 100, 200, 300, 500, 600, 700, 900, 1000, 1100, 1400
(year >= 1582 ? 10 : 0)
Insert cell
Insert cell
Insert cell
15638400000 / 31557600000
Insert cell
((datedays(2024, 3, 28) - datedays(2024)) * by.day.step) / by.month.step
Insert cell
datedays(2024, 1, 1) - datedays(2023, 12, 31)
Insert cell
div(datenum(2024, 1, 28), by.month.step, by.month.period, by.month.offset) + 1
Insert cell
div(
datenum(2024, 3, 28) - datenum(2024),
by.month.step,
by.month.period,
by.month.offset
)
Insert cell
{
const year = 2024;
const month = 0;
const day = 0;
return (
(year - 1) * 365 +
// plus one days for every leap year since,
leaps(year - 1)
);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const today = new Date().getTime() + Year.step * 1970;
const daysInYear = today % Year.step;

// NOTE: Current day is a bit more challenging
return md`
| Grain | Units |
| :------- | :----- |
| Seconds per minute | \`${Minute.step / Second.step}\` |
| Minutes per hour | \`${Hour.step / Minute.step}\` |
| Hours per day | \`${Day.step / Hour.step}\` |
| Days per month | \`${Month.step / Day.step}\` |
| Days per year | \`${Year.step / Day.step}\` |
| Months per year | \`${Year.step / Month.step}\` |
| Years since EPOCH | \`${new Date(0).getTime() / Year.step}\` |
| Year from today since EPOCH | \`${new Date().getTime() / Year.step}\`
| Current Year | \`${today / Year.step}\`
| Days in Year | \`${daysInYear / Day.step}\`
| Current Month | \`${((today / Month.step) % Month.period) + Month.offset}\` `
`;
}
Insert cell
viewof periodDate = html`<input type="date" value="2024-07-04"/>`
Insert cell
{
const origin = new Date(0);
const delta = periodDate.getTime() - origin.getTime();
return Object.keys(by).reduce((r, grain) => {
const g = by[grain];
let v = Math.floor(delta / g.step);
let w = (g.period ? v % g.period : v) + (g.offset || 0);
r[grain] = `${w}${g.suffix}`;
return r;
}, {});
}
Insert cell
Insert cell
Insert cell
snap = (nd, grain) => {
switch (grain) {
default:
return divmul(nd, grain.value);
}
}
Insert cell
_snapDate = datenum(2024, 7, 12, 17, 52, 38)
Insert cell
Insert cell
numdate(63865216800000)
Insert cell
snap(datenum(2024, 7, 15, 5, 21), by.day)
Insert cell
dt0 = datenum(2024, 7, 15, 5, 21) - datenum(2024, 7, 14)
Insert cell
63883036800000 / 86400000
Insert cell
Insert cell
dist = (d0, d1=undefined) => {
// Just one argument, we break down by granularity and return the result
if (d1 === undefined) {
const res={};
for (k of by) {
res[k] = d0/ by[k].period;
}
return res;
} else {
const dt = d1 - d0;
const ds = dt % by.second.period;
const dM =
}
}
Insert cell
Insert cell
Insert cell
isleap = (year) =>
year < 0 || year % 4 !== 0
? false
: year <= 1582
? year % 4 === 0
: (year % 4 === 0) && (year % 100 !== 0 || year % 400 === 0)
Insert cell
// Returns the number of days in the year, or since the beginning of the year if the days was given
yeardays = (year, month) =>
month === undefined
? isleap(year)
? 366
: 365
: isleap(year)
? YEAR_DAYS[month - 1]
: LEAP_YEAR_DAYS[month - 1]
Insert cell
monthdays = (year, month) =>
month === 2 ? (isleap(year) ? 29 : 28) : month % 2 === 0 ? 30 : 31
Insert cell
Insert cell
Insert cell
weekday = (year, month, day, firstDay = 0) => {
const s = div(year, 100);
let sday =
1720996.5 -
s +
div(s, 4) +
Math.floor(365.25 * year) +
Math.floor(30.6001 * (month + 1)) +
day;
sday -= div(sday, 7) * 7;
const wday = (Math.floor(sday) + 1) % 7;
// We adjust based on the first day. In US calendars, the first day
// is Sunday (==6), so we shift the result by one day, as there
// is now 1 more day to reach Monday (the canonical 0).
return (wday + (7 - firstDay)) % 7;
}
Insert cell
Insert cell
Insert cell

// The timezone offset is in milliseconds, the same unit as `datenum`
timezone = () => new Date().getTimezoneOffset() * MS_PER_MINUTE
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
div = (v, k, p, offset = 0) =>
p ? ((Math.floor(v / k) - offset) % p) + offset : Math.floor(v / k)
Insert cell
divmul = (v, k) => div(v, k) * k
Insert cell
$table = (...rows) => html`<table>
${rows
.map(
([header, ...cols]) =>
`<tr><th>${header}</th>${cols.map(v=>`<td><code>${JSON.stringify(v)}</code></td>`).join("")}</tr>`
)
.join("")}</table>`
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Enum = (...names) =>(
{values:Object.freeze(names.reduce((r,v,i)=>(
r[v] = i, r
), {})),names}
)
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more