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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more