Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

consistent intervals with interval.every #66

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ jobs:
cache: 'yarn'
- run: yarn --frozen-lockfile
- run: yarn test
- run: yarn lint
- run: yarn build
- run: npm publish
env:
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@ jobs:
cache: yarn
- run: yarn --frozen-lockfile
- run: yarn test
- run: yarn lint
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
},
"scripts": {
"test": "TZ=America/Los_Angeles mocha 'test/**/*-test.js' && eslint src test",
"lint": "eslint src test",
"build": "rm -rf dist && rollup -c"
},
"engines": {
Expand Down
31 changes: 8 additions & 23 deletions src/day.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,20 @@
import {timeInterval} from "./interval.js";
import {durationDay, durationMinute} from "./duration.js";
import {timeEpoch} from "./epoch.js";

export const timeDay = timeInterval(
date => date.setHours(0, 0, 0, 0),
(date) => date.setHours(0, 0, 0, 0),
(date, step) => date.setDate(date.getDate() + step),
(start, end) => (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay,
date => date.getDate() - 1
timeEpoch
);

export const timeDays = timeDay.range;

export const utcDay = timeInterval((date) => {
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCDate(date.getUTCDate() + step);
}, (start, end) => {
return (end - start) / durationDay;
}, (date) => {
return date.getUTCDate() - 1;
});
export const utcDay = timeInterval(
(date) => date.setUTCHours(0, 0, 0, 0),
(date, step) => date.setUTCDate(date.getUTCDate() + step),
(start, end) => (end - start) / durationDay
);

export const utcDays = utcDay.range;

export const unixDay = timeInterval((date) => {
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCDate(date.getUTCDate() + step);
}, (start, end) => {
return (end - start) / durationDay;
}, (date) => {
return Math.floor(date / durationDay);
});

export const unixDays = unixDay.range;
1 change: 1 addition & 0 deletions src/epoch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const timeEpoch = new Date(1970, 0, 1);
30 changes: 12 additions & 18 deletions src/hour.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
import {timeInterval} from "./interval.js";
import {durationHour, durationMinute, durationSecond} from "./duration.js";
import {timeEpoch} from "./epoch.js";

export const timeHour = timeInterval((date) => {
date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond - date.getMinutes() * durationMinute);
}, (date, step) => {
date.setTime(+date + step * durationHour);
}, (start, end) => {
return (end - start) / durationHour;
}, (date) => {
return date.getHours();
});
export const timeHour = timeInterval(
(date) => date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond - date.getMinutes() * durationMinute),
(date, step) => date.setTime(+date + step * durationHour),
(start, end) => (end - start) / durationHour,
timeEpoch
);

export const timeHours = timeHour.range;

export const utcHour = timeInterval((date) => {
date.setUTCMinutes(0, 0, 0);
}, (date, step) => {
date.setTime(+date + step * durationHour);
}, (start, end) => {
return (end - start) / durationHour;
}, (date) => {
return date.getUTCHours();
});
export const utcHour = timeInterval(
(date) => date.setUTCMinutes(0, 0, 0),
(date, step) => date.setTime(+date + step * durationHour),
(start, end) => (end - start) / durationHour
);

export const utcHours = utcHour.range;
4 changes: 2 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export {
timeDays,
utcDay,
utcDays,
unixDay,
unixDays
utcDay as unixDay, // deprecated! use utcDay
utcDays as unixDays // deprecated! use utcDays
} from "./day.js";

export {
Expand Down
8 changes: 4 additions & 4 deletions src/interval.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const t0 = new Date, t1 = new Date;

export function timeInterval(floori, offseti, count, field) {
export function timeInterval(floori, offseti, count, epoch = 0) {

function interval(date) {
return floori(date = arguments.length === 0 ? new Date : new Date(+date)), date;
Expand Down Expand Up @@ -59,9 +59,9 @@ export function timeInterval(floori, offseti, count, field) {
step = Math.floor(step);
return !isFinite(step) || !(step > 0) ? null
: !(step > 1) ? interval
: interval.filter(field
? (d) => field(d) % step === 0
: (d) => interval.count(0, d) % step === 0);
: interval.filter(typeof epoch === "function" // deprecated field
? (d) => epoch(d) % step === 0
: (d) => interval.count(epoch, d) % step === 0);
};
}

Expand Down
30 changes: 12 additions & 18 deletions src/minute.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
import {timeInterval} from "./interval.js";
import {durationMinute, durationSecond} from "./duration.js";
import {timeEpoch} from "./epoch.js";

export const timeMinute = timeInterval((date) => {
date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond);
}, (date, step) => {
date.setTime(+date + step * durationMinute);
}, (start, end) => {
return (end - start) / durationMinute;
}, (date) => {
return date.getMinutes();
});
export const timeMinute = timeInterval(
(date) => date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond),
(date, step) => date.setTime(+date + step * durationMinute),
(start, end) => (end - start) / durationMinute,
timeEpoch
);

export const timeMinutes = timeMinute.range;

export const utcMinute = timeInterval((date) => {
date.setUTCSeconds(0, 0);
}, (date, step) => {
date.setTime(+date + step * durationMinute);
}, (start, end) => {
return (end - start) / durationMinute;
}, (date) => {
return date.getUTCMinutes();
});
export const utcMinute = timeInterval(
(date) => date.setUTCSeconds(0, 0),
(date, step) => date.setTime(+date + step * durationMinute),
(start, end) => (end - start) / durationMinute
);

export const utcMinutes = utcMinute.range;
32 changes: 12 additions & 20 deletions src/month.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
import {timeEpoch} from "./epoch.js";
import {timeInterval} from "./interval.js";

export const timeMonth = timeInterval((date) => {
date.setDate(1);
date.setHours(0, 0, 0, 0);
}, (date, step) => {
date.setMonth(date.getMonth() + step);
}, (start, end) => {
return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
}, (date) => {
return date.getMonth();
});
export const timeMonth = timeInterval(
(date) => (date.setDate(1), date.setHours(0, 0, 0, 0)),
(date, step) => date.setMonth(date.getMonth() + step),
(start, end) => end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12,
timeEpoch
);

export const timeMonths = timeMonth.range;

export const utcMonth = timeInterval((date) => {
date.setUTCDate(1);
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCMonth(date.getUTCMonth() + step);
}, (start, end) => {
return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
}, (date) => {
return date.getUTCMonth();
});
export const utcMonth = timeInterval(
(date) => (date.setUTCDate(1), date.setUTCHours(0, 0, 0, 0)),
(date, step) => date.setUTCMonth(date.getUTCMonth() + step),
(start, end) => end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12
);

export const utcMonths = utcMonth.range;
14 changes: 5 additions & 9 deletions src/second.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import {timeInterval} from "./interval.js";
import {durationSecond} from "./duration.js";

export const second = timeInterval((date) => {
date.setTime(date - date.getMilliseconds());
}, (date, step) => {
date.setTime(+date + step * durationSecond);
}, (start, end) => {
return (end - start) / durationSecond;
}, (date) => {
return date.getUTCSeconds();
});
export const second = timeInterval(
(date) => date.setTime(date - date.getMilliseconds()),
(date, step) => date.setTime(+date + step * durationSecond),
(start, end) => (end - start) / durationSecond
);

export const seconds = second.range;
4 changes: 2 additions & 2 deletions src/ticks.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {millisecond} from "./millisecond.js";
import {second} from "./second.js";
import {timeMinute, utcMinute} from "./minute.js";
import {timeHour, utcHour} from "./hour.js";
import {timeDay, unixDay} from "./day.js";
import {timeDay, utcDay} from "./day.js";
import {timeSunday, utcSunday} from "./week.js";
import {timeMonth, utcMonth} from "./month.js";
import {timeYear, utcYear} from "./year.js";
Expand Down Expand Up @@ -52,7 +52,7 @@ function ticker(year, month, week, day, hour, minute) {
return [ticks, tickInterval];
}

const [utcTicks, utcTickInterval] = ticker(utcYear, utcMonth, utcSunday, unixDay, utcHour, utcMinute);
const [utcTicks, utcTickInterval] = ticker(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute);
const [timeTicks, timeTickInterval] = ticker(timeYear, timeMonth, timeSunday, timeDay, timeHour, timeMinute);

export {utcTicks, utcTickInterval, timeTicks, timeTickInterval};
28 changes: 12 additions & 16 deletions src/week.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import {timeInterval} from "./interval.js";
import {durationMinute, durationWeek} from "./duration.js";
import {timeEpoch} from "./epoch.js";

function timeWeekday(i) {
return timeInterval((date) => {
date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
date.setHours(0, 0, 0, 0);
}, (date, step) => {
date.setDate(date.getDate() + step * 7);
}, (start, end) => {
return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek;
});
return timeInterval(
(date) => (date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7), date.setHours(0, 0, 0, 0)),
(date, step) => date.setDate(date.getDate() + step * 7),
(start, end) => (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek,
timeEpoch
);
}

export const timeSunday = timeWeekday(0);
Expand All @@ -29,14 +28,11 @@ export const timeFridays = timeFriday.range;
export const timeSaturdays = timeSaturday.range;

function utcWeekday(i) {
return timeInterval((date) => {
date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCDate(date.getUTCDate() + step * 7);
}, (start, end) => {
return (end - start) / durationWeek;
});
return timeInterval(
(date) => (date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7), date.setUTCHours(0, 0, 0, 0)),
(date, step) => date.setUTCDate(date.getUTCDate() + step * 7),
(start, end) => (end - start) / durationWeek
);
}

export const utcSunday = utcWeekday(0);
Expand Down
54 changes: 20 additions & 34 deletions src/year.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,35 @@
import {timeEpoch} from "./epoch.js";
import {timeInterval} from "./interval.js";

export const timeYear = timeInterval((date) => {
date.setMonth(0, 1);
date.setHours(0, 0, 0, 0);
}, (date, step) => {
date.setFullYear(date.getFullYear() + step);
}, (start, end) => {
return end.getFullYear() - start.getFullYear();
}, (date) => {
return date.getFullYear();
});
export const timeYear = timeInterval(
(date) => (date.setMonth(0, 1), date.setHours(0, 0, 0, 0)),
(date, step) => date.setFullYear(date.getFullYear() + step),
(start, end) => end.getFullYear() - start.getFullYear(),
timeEpoch
);

// An optimized implementation for this simple case.
timeYear.every = (k) => {
return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {
date.setFullYear(Math.floor(date.getFullYear() / k) * k);
date.setMonth(0, 1);
date.setHours(0, 0, 0, 0);
}, (date, step) => {
date.setFullYear(date.getFullYear() + step * k);
});
return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval(
(date) => (date.setFullYear(Math.floor(date.getFullYear() / k) * k), date.setMonth(0, 1), date.setHours(0, 0, 0, 0)),
(date, step) => date.setFullYear(date.getFullYear() + step * k)
);
};

export const timeYears = timeYear.range;

export const utcYear = timeInterval((date) => {
date.setUTCMonth(0, 1);
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCFullYear(date.getUTCFullYear() + step);
}, (start, end) => {
return end.getUTCFullYear() - start.getUTCFullYear();
}, (date) => {
return date.getUTCFullYear();
});
export const utcYear = timeInterval(
(date) => (date.setUTCMonth(0, 1), date.setUTCHours(0, 0, 0, 0)),
(date, step) => date.setUTCFullYear(date.getUTCFullYear() + step),
(start, end) => end.getUTCFullYear() - start.getUTCFullYear()
);

// An optimized implementation for this simple case.
utcYear.every = (k) => {
return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {
date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
date.setUTCMonth(0, 1);
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCFullYear(date.getUTCFullYear() + step * k);
});
return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval(
(date) => (date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k), date.setUTCMonth(0, 1), date.setUTCHours(0, 0, 0, 0)),
(date, step) => date.setUTCFullYear(date.getUTCFullYear() + step * k)
);
};

export const utcYears = utcYear.range;
8 changes: 4 additions & 4 deletions test/day-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ it("timeDay.count(start, end) returns 364 or 365 for a full year", () => {
assert.strictEqual(timeDay.count(local(2011, 0, 1), local(2011, 11, 31)), 364);
});

it("timeDay.every(step) returns every stepth day, starting with the first day of the month", () => {
assert.deepStrictEqual(timeDay.every(3).range(local(2008, 11, 30, 0, 12), local(2009, 0, 5, 23, 48)), [local(2008, 11, 31), local(2009, 0, 1), local(2009, 0, 4)]);
assert.deepStrictEqual(timeDay.every(5).range(local(2008, 11, 30, 0, 12), local(2009, 0, 6, 23, 48)), [local(2008, 11, 31), local(2009, 0, 1), local(2009, 0, 6)]);
assert.deepStrictEqual(timeDay.every(7).range(local(2008, 11, 30, 0, 12), local(2009, 0, 8, 23, 48)), [local(2009, 0, 1), local(2009, 0, 8)]);
it("timeDay.every(step) returns every stepth day without resetting on the first of the month", () => {
assert.deepStrictEqual(timeDay.every(3).range(local(2008, 11, 30, 0, 12), local(2009, 0, 5, 23, 48)), [local(2008, 11, 31), local(2009, 0, 3)]);
assert.deepStrictEqual(timeDay.every(5).range(local(2008, 11, 25, 0, 12), local(2009, 0, 6, 23, 48)), [local(2008, 11, 27), local(2009, 0, 1), local(2009, 0, 6)]);
assert.deepStrictEqual(timeDay.every(7).range(local(2008, 11, 23, 0, 12), local(2009, 0, 8, 23, 48)), [local(2008, 11, 25), local(2009, 0, 1), local(2009, 0, 8)]);
});
Loading