From c11a84383e63044946fa082fb1201fc5939ffa6b Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sun, 25 Jun 2023 14:00:02 -0700 Subject: [PATCH 1/2] add utcMonthDay, timeMonthDay --- src/day.js | 50 ++++----- src/index.js | 6 +- src/ticks.js | 4 +- test/day-test.js | 215 --------------------------------------- test/monthDay-test.js | 215 +++++++++++++++++++++++++++++++++++++++ test/ticks-test.js | 10 ++ test/unixDay-test.js | 117 --------------------- test/utcDay-test.js | 6 +- test/utcMonthDay-test.js | 117 +++++++++++++++++++++ test/utcTicks-test.js | 10 ++ 10 files changed, 387 insertions(+), 363 deletions(-) delete mode 100644 test/day-test.js create mode 100644 test/monthDay-test.js delete mode 100644 test/unixDay-test.js create mode 100644 test/utcMonthDay-test.js diff --git a/src/day.js b/src/day.js index 2b5d4b6..d2b0db9 100644 --- a/src/day.js +++ b/src/day.js @@ -1,35 +1,37 @@ import {timeInterval} from "./interval.js"; import {durationDay, durationMinute} from "./duration.js"; -export const timeDay = timeInterval( - date => date.setHours(0, 0, 0, 0), +export const timeMonthDay = timeInterval( + (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 + (date) => date.getDate() - 1 +); + +export const timeMonthDays = timeMonthDay.range; + +export const utcMonthDay = timeInterval( + (date) => date.setUTCHours(0, 0, 0, 0), + (date, step) => date.setUTCDate(date.getUTCDate() + step), + (start, end) => (end - start) / durationDay, + (date) => date.getUTCDate() - 1 + ); + +export const utcMonthDays = utcMonthDay.range; + +export const timeDay = timeInterval( + (date) => date.setHours(0, 0, 0, 0), + (date, step) => date.setDate(date.getDate() + step), + (start, end) => (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay ); 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, + (date) => Math.floor(date / 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; diff --git a/src/index.js b/src/index.js index d6dfd90..f11d7c5 100644 --- a/src/index.js +++ b/src/index.js @@ -33,10 +33,12 @@ export { export { timeDay, timeDays, + timeMonthDay, + timeMonthDays, utcDay, utcDays, - unixDay, - unixDays + utcMonthDay, + utcMonthDays } from "./day.js"; export { diff --git a/src/ticks.js b/src/ticks.js index c314789..b18261f 100644 --- a/src/ticks.js +++ b/src/ticks.js @@ -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"; @@ -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}; diff --git a/test/day-test.js b/test/day-test.js deleted file mode 100644 index 771616b..0000000 --- a/test/day-test.js +++ /dev/null @@ -1,215 +0,0 @@ -import assert from "assert"; -import {timeDay, timeDays, timeYear} from "../src/index.js"; -import {local, utc} from "./date.js"; - -it("timeDays in an alias for timeDay.range", () => { - assert.strictEqual(timeDays, timeDay.range); -}); - -it("timeDay() is equivalent to timeDay.floor(new Date)", () => { - const t = new Date; - assert.deepStrictEqual(timeDay(), timeDay.floor(t)); -}); - -it("timeDay(date) is equivalent to timeDay.floor(date)", () => { - const t = new Date; - assert.deepStrictEqual(timeDay(t), timeDay.floor(t)); -}); - -it("timeDay.floor(date) returns days", () => { - assert.deepStrictEqual(timeDay.floor(local(2010, 11, 31, 23)), local(2010, 11, 31)); - assert.deepStrictEqual(timeDay.floor(local(2011, 0, 1, 0)), local(2011, 0, 1)); - assert.deepStrictEqual(timeDay.floor(local(2011, 0, 1, 1)), local(2011, 0, 1)); -}); - -it("timeDay.floor(date) observes daylight saving", () => { - assert.deepStrictEqual(timeDay.floor(utc(2011, 2, 13, 7)), local(2011, 2, 12)); - assert.deepStrictEqual(timeDay.floor(utc(2011, 2, 13, 8)), local(2011, 2, 13)); - assert.deepStrictEqual(timeDay.floor(utc(2011, 2, 13, 9)), local(2011, 2, 13)); - assert.deepStrictEqual(timeDay.floor(utc(2011, 2, 13, 10)), local(2011, 2, 13)); - assert.deepStrictEqual(timeDay.floor(utc(2011, 10, 6, 7)), local(2011, 10, 6)); - assert.deepStrictEqual(timeDay.floor(utc(2011, 10, 6, 8)), local(2011, 10, 6)); - assert.deepStrictEqual(timeDay.floor(utc(2011, 10, 6, 9)), local(2011, 10, 6)); - assert.deepStrictEqual(timeDay.floor(utc(2011, 10, 6, 10)), local(2011, 10, 6)); -}); - -it("timeDay.floor(date) handles years in the first century", () => { - assert.deepStrictEqual(timeDay.floor(local(9, 10, 6, 7)), local(9, 10, 6)); -}); - -it("timeDay.round(date) returns days", () => { - assert.deepStrictEqual(timeDay.round(local(2010, 11, 30, 13)), local(2010, 11, 31)); - assert.deepStrictEqual(timeDay.round(local(2010, 11, 30, 11)), local(2010, 11, 30)); -}); - -it("timeDay.round(date) observes daylight saving", () => { - assert.deepStrictEqual(timeDay.round(utc(2011, 2, 13, 7)), local(2011, 2, 13)); - assert.deepStrictEqual(timeDay.round(utc(2011, 2, 13, 8)), local(2011, 2, 13)); - assert.deepStrictEqual(timeDay.round(utc(2011, 2, 13, 9)), local(2011, 2, 13)); - assert.deepStrictEqual(timeDay.round(utc(2011, 2, 13, 20)), local(2011, 2, 14)); - assert.deepStrictEqual(timeDay.round(utc(2011, 10, 6, 7)), local(2011, 10, 6)); - assert.deepStrictEqual(timeDay.round(utc(2011, 10, 6, 8)), local(2011, 10, 6)); - assert.deepStrictEqual(timeDay.round(utc(2011, 10, 6, 9)), local(2011, 10, 6)); - assert.deepStrictEqual(timeDay.round(utc(2011, 10, 6, 20)), local(2011, 10, 7)); -}); - -it("timeDay.round(date) handles midnight in leap years", () => { - assert.deepStrictEqual(timeDay.round(utc(2012, 2, 1, 0)), local(2012, 2, 1)); - assert.deepStrictEqual(timeDay.round(utc(2012, 2, 1, 0)), local(2012, 2, 1)); -}); - -it("timeDay.ceil(date) returns days", () => { - assert.deepStrictEqual(timeDay.ceil(local(2010, 11, 30, 23)), local(2010, 11, 31)); - assert.deepStrictEqual(timeDay.ceil(local(2010, 11, 31, 0)), local(2010, 11, 31)); - assert.deepStrictEqual(timeDay.ceil(local(2010, 11, 31, 1)), local(2011, 0, 1)); -}); - -it("timeDay.ceil(date) observes start of daylight saving", () => { - assert.deepStrictEqual(timeDay.ceil(utc(2011, 2, 13, 7)), local(2011, 2, 13)); - assert.deepStrictEqual(timeDay.ceil(utc(2011, 2, 13, 8)), local(2011, 2, 13)); - assert.deepStrictEqual(timeDay.ceil(utc(2011, 2, 13, 9)), local(2011, 2, 14)); - assert.deepStrictEqual(timeDay.ceil(utc(2011, 2, 13, 10)), local(2011, 2, 14)); -}); - -it("timeDay.ceil(date) observes end of daylight saving", () => { - assert.deepStrictEqual(timeDay.ceil(utc(2011, 10, 6, 7)), local(2011, 10, 6)); - assert.deepStrictEqual(timeDay.ceil(utc(2011, 10, 6, 8)), local(2011, 10, 7)); - assert.deepStrictEqual(timeDay.ceil(utc(2011, 10, 6, 9)), local(2011, 10, 7)); - assert.deepStrictEqual(timeDay.ceil(utc(2011, 10, 6, 10)), local(2011, 10, 7)); -}); - -it("timeDay.ceil(date) handles midnight for leap years", () => { - assert.deepStrictEqual(timeDay.ceil(utc(2012, 2, 1, 0)), local(2012, 2, 1)); - assert.deepStrictEqual(timeDay.ceil(utc(2012, 2, 1, 0)), local(2012, 2, 1)); -}); - -it("timeDay.offset(date) is an alias for timeDay.offset(date, 1)", () => { - assert.deepStrictEqual(timeDay.offset(local(2010, 11, 31, 23, 59, 59, 999)), local(2011, 0, 1, 23, 59, 59, 999)); -}); - -it("timeDay.offset(date, step) does not modify the passed-in date", () => { - const d = local(2010, 11, 31, 23, 59, 59, 999); - timeDay.offset(d, +1); - assert.deepStrictEqual(d, local(2010, 11, 31, 23, 59, 59, 999)); -}); - -it("timeDay.offset(date, step) does not round the passed-in date", () => { - assert.deepStrictEqual(timeDay.offset(local(2010, 11, 31, 23, 59, 59, 999), +1), local(2011, 0, 1, 23, 59, 59, 999)); - assert.deepStrictEqual(timeDay.offset(local(2010, 11, 31, 23, 59, 59, 456), -2), local(2010, 11, 29, 23, 59, 59, 456)); -}); - -it("timeDay.offset(date, step) allows step to be negative", () => { - assert.deepStrictEqual(timeDay.offset(local(2010, 11, 31), -1), local(2010, 11, 30)); - assert.deepStrictEqual(timeDay.offset(local(2011, 0, 1), -2), local(2010, 11, 30)); - assert.deepStrictEqual(timeDay.offset(local(2011, 0, 1), -1), local(2010, 11, 31)); -}); - -it("timeDay.offset(date, step) allows step to be positive", () => { - assert.deepStrictEqual(timeDay.offset(local(2010, 11, 31), +1), local(2011, 0, 1)); - assert.deepStrictEqual(timeDay.offset(local(2010, 11, 30), +2), local(2011, 0, 1)); - assert.deepStrictEqual(timeDay.offset(local(2010, 11, 30), +1), local(2010, 11, 31)); -}); - -it("timeDay.offset(date, step) allows step to be zero", () => { - assert.deepStrictEqual(timeDay.offset(local(2010, 11, 31, 23, 59, 59, 999), 0), local(2010, 11, 31, 23, 59, 59, 999)); - assert.deepStrictEqual(timeDay.offset(local(2010, 11, 31, 23, 59, 58, 0), 0), local(2010, 11, 31, 23, 59, 58, 0)); -}); - -it("timeDay.range(start, stop) returns days between start (inclusive) and stop (exclusive)", () => { - assert.deepStrictEqual(timeDay.range(local(2011, 10, 4), local(2011, 10, 10)), [ - local(2011, 10, 4), - local(2011, 10, 5), - local(2011, 10, 6), - local(2011, 10, 7), - local(2011, 10, 8), - local(2011, 10, 9) - ]); -}); - -it("timeDay.range(start, stop) returns days", () => { - assert.deepStrictEqual(timeDay.range(local(2011, 10, 4, 2), local(2011, 10, 10, 13)), [ - local(2011, 10, 5), - local(2011, 10, 6), - local(2011, 10, 7), - local(2011, 10, 8), - local(2011, 10, 9), - local(2011, 10, 10) - ]); -}); - -it("timeDay.range(start, stop) coerces start and stop to dates", () => { - assert.deepStrictEqual(timeDay.range(+local(2011, 10, 4), +local(2011, 10, 7)), [ - local(2011, 10, 4), - local(2011, 10, 5), - local(2011, 10, 6) - ]); -}); - -it("timeDay.range(start, stop) returns the empty array for invalid dates", () => { - assert.deepStrictEqual(timeDay.range(new Date(NaN), Infinity), []); -}); - -it("timeDay.range(start, stop) returns the empty array if start >= stop", () => { - assert.deepStrictEqual(timeDay.range(local(2011, 10, 10), local(2011, 10, 4)), []); - assert.deepStrictEqual(timeDay.range(local(2011, 10, 10), local(2011, 10, 10)), []); -}); - -it("timeDay.range(start, stop, step) returns every step day", () => { - assert.deepStrictEqual(timeDay.range(local(2011, 10, 4, 2), local(2011, 10, 14, 13), 3), [ - local(2011, 10, 5), - local(2011, 10, 8), - local(2011, 10, 11), - local(2011, 10, 14) - ]); -}); - -it("timeDay.range(start, stop, step) returns the empty array if step is zero, negative or NaN", () => { - assert.deepStrictEqual(timeDay.range(local(2011, 0, 1, 0), local(2011, 4, 9, 0), 0), []); - assert.deepStrictEqual(timeDay.range(local(2011, 0, 1, 0), local(2011, 4, 9, 0), -1), []); - assert.deepStrictEqual(timeDay.range(local(2011, 0, 1, 0), local(2011, 4, 9, 0), 0.5), []); - assert.deepStrictEqual(timeDay.range(local(2011, 0, 1, 0), local(2011, 4, 9, 0), NaN), []); -}); - -it("timeDay.count(start, end) counts days after start (exclusive) and before end (inclusive)", () => { - assert.strictEqual(timeDay.count(local(2011, 0, 1, 0), local(2011, 4, 9, 0)), 128); - assert.strictEqual(timeDay.count(local(2011, 0, 1, 1), local(2011, 4, 9, 0)), 128); - assert.strictEqual(timeDay.count(local(2010, 11, 31, 23), local(2011, 4, 9, 0)), 129); - assert.strictEqual(timeDay.count(local(2011, 0, 1, 0), local(2011, 4, 8, 23)), 127); - assert.strictEqual(timeDay.count(local(2011, 0, 1, 0), local(2011, 4, 9, 1)), 128); -}); - -it("timeDay.count(start, end) observes daylight saving", () => { - assert.strictEqual(timeDay.count(local(2011, 0, 1), local(2011, 2, 13, 1)), 71); - assert.strictEqual(timeDay.count(local(2011, 0, 1), local(2011, 2, 13, 3)), 71); - assert.strictEqual(timeDay.count(local(2011, 0, 1), local(2011, 2, 13, 4)), 71); - assert.strictEqual(timeDay.count(local(2011, 0, 1), local(2011, 10, 6, 0)), 309); - assert.strictEqual(timeDay.count(local(2011, 0, 1), local(2011, 10, 6, 1)), 309); - assert.strictEqual(timeDay.count(local(2011, 0, 1), local(2011, 10, 6, 2)), 309); -}); - -it("timeDay.count(start, stop) does not exhibit floating-point rounding error", () => { - const date = new Date(2011, 4, 9); - assert.strictEqual(timeDay.count(timeYear(date), date), 128); -}); - -it("timeDay.count(start, end) returns 364 or 365 for a full year", () => { - assert.strictEqual(timeDay.count(local(1999, 0, 1), local(1999, 11, 31)), 364); - assert.strictEqual(timeDay.count(local(2000, 0, 1), local(2000, 11, 31)), 365); // leap year - assert.strictEqual(timeDay.count(local(2001, 0, 1), local(2001, 11, 31)), 364); - assert.strictEqual(timeDay.count(local(2002, 0, 1), local(2002, 11, 31)), 364); - assert.strictEqual(timeDay.count(local(2003, 0, 1), local(2003, 11, 31)), 364); - assert.strictEqual(timeDay.count(local(2004, 0, 1), local(2004, 11, 31)), 365); // leap year - assert.strictEqual(timeDay.count(local(2005, 0, 1), local(2005, 11, 31)), 364); - assert.strictEqual(timeDay.count(local(2006, 0, 1), local(2006, 11, 31)), 364); - assert.strictEqual(timeDay.count(local(2007, 0, 1), local(2007, 11, 31)), 364); - assert.strictEqual(timeDay.count(local(2008, 0, 1), local(2008, 11, 31)), 365); // leap year - assert.strictEqual(timeDay.count(local(2009, 0, 1), local(2009, 11, 31)), 364); - assert.strictEqual(timeDay.count(local(2010, 0, 1), local(2010, 11, 31)), 364); - 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)]); -}); diff --git a/test/monthDay-test.js b/test/monthDay-test.js new file mode 100644 index 0000000..1d98f64 --- /dev/null +++ b/test/monthDay-test.js @@ -0,0 +1,215 @@ +import assert from "assert"; +import {timeMonthDay, timeMonthDays, timeYear} from "../src/index.js"; +import {local, utc} from "./date.js"; + +it("timeMonthDays in an alias for timeMonthDay.range", () => { + assert.strictEqual(timeMonthDays, timeMonthDay.range); +}); + +it("timeMonthDay() is equivalent to timeMonthDay.floor(new Date)", () => { + const t = new Date; + assert.deepStrictEqual(timeMonthDay(), timeMonthDay.floor(t)); +}); + +it("timeMonthDay(date) is equivalent to timeMonthDay.floor(date)", () => { + const t = new Date; + assert.deepStrictEqual(timeMonthDay(t), timeMonthDay.floor(t)); +}); + +it("timeMonthDay.floor(date) returns days", () => { + assert.deepStrictEqual(timeMonthDay.floor(local(2010, 11, 31, 23)), local(2010, 11, 31)); + assert.deepStrictEqual(timeMonthDay.floor(local(2011, 0, 1, 0)), local(2011, 0, 1)); + assert.deepStrictEqual(timeMonthDay.floor(local(2011, 0, 1, 1)), local(2011, 0, 1)); +}); + +it("timeMonthDay.floor(date) observes daylight saving", () => { + assert.deepStrictEqual(timeMonthDay.floor(utc(2011, 2, 13, 7)), local(2011, 2, 12)); + assert.deepStrictEqual(timeMonthDay.floor(utc(2011, 2, 13, 8)), local(2011, 2, 13)); + assert.deepStrictEqual(timeMonthDay.floor(utc(2011, 2, 13, 9)), local(2011, 2, 13)); + assert.deepStrictEqual(timeMonthDay.floor(utc(2011, 2, 13, 10)), local(2011, 2, 13)); + assert.deepStrictEqual(timeMonthDay.floor(utc(2011, 10, 6, 7)), local(2011, 10, 6)); + assert.deepStrictEqual(timeMonthDay.floor(utc(2011, 10, 6, 8)), local(2011, 10, 6)); + assert.deepStrictEqual(timeMonthDay.floor(utc(2011, 10, 6, 9)), local(2011, 10, 6)); + assert.deepStrictEqual(timeMonthDay.floor(utc(2011, 10, 6, 10)), local(2011, 10, 6)); +}); + +it("timeMonthDay.floor(date) handles years in the first century", () => { + assert.deepStrictEqual(timeMonthDay.floor(local(9, 10, 6, 7)), local(9, 10, 6)); +}); + +it("timeMonthDay.round(date) returns days", () => { + assert.deepStrictEqual(timeMonthDay.round(local(2010, 11, 30, 13)), local(2010, 11, 31)); + assert.deepStrictEqual(timeMonthDay.round(local(2010, 11, 30, 11)), local(2010, 11, 30)); +}); + +it("timeMonthDay.round(date) observes daylight saving", () => { + assert.deepStrictEqual(timeMonthDay.round(utc(2011, 2, 13, 7)), local(2011, 2, 13)); + assert.deepStrictEqual(timeMonthDay.round(utc(2011, 2, 13, 8)), local(2011, 2, 13)); + assert.deepStrictEqual(timeMonthDay.round(utc(2011, 2, 13, 9)), local(2011, 2, 13)); + assert.deepStrictEqual(timeMonthDay.round(utc(2011, 2, 13, 20)), local(2011, 2, 14)); + assert.deepStrictEqual(timeMonthDay.round(utc(2011, 10, 6, 7)), local(2011, 10, 6)); + assert.deepStrictEqual(timeMonthDay.round(utc(2011, 10, 6, 8)), local(2011, 10, 6)); + assert.deepStrictEqual(timeMonthDay.round(utc(2011, 10, 6, 9)), local(2011, 10, 6)); + assert.deepStrictEqual(timeMonthDay.round(utc(2011, 10, 6, 20)), local(2011, 10, 7)); +}); + +it("timeMonthDay.round(date) handles midnight in leap years", () => { + assert.deepStrictEqual(timeMonthDay.round(utc(2012, 2, 1, 0)), local(2012, 2, 1)); + assert.deepStrictEqual(timeMonthDay.round(utc(2012, 2, 1, 0)), local(2012, 2, 1)); +}); + +it("timeMonthDay.ceil(date) returns days", () => { + assert.deepStrictEqual(timeMonthDay.ceil(local(2010, 11, 30, 23)), local(2010, 11, 31)); + assert.deepStrictEqual(timeMonthDay.ceil(local(2010, 11, 31, 0)), local(2010, 11, 31)); + assert.deepStrictEqual(timeMonthDay.ceil(local(2010, 11, 31, 1)), local(2011, 0, 1)); +}); + +it("timeMonthDay.ceil(date) observes start of daylight saving", () => { + assert.deepStrictEqual(timeMonthDay.ceil(utc(2011, 2, 13, 7)), local(2011, 2, 13)); + assert.deepStrictEqual(timeMonthDay.ceil(utc(2011, 2, 13, 8)), local(2011, 2, 13)); + assert.deepStrictEqual(timeMonthDay.ceil(utc(2011, 2, 13, 9)), local(2011, 2, 14)); + assert.deepStrictEqual(timeMonthDay.ceil(utc(2011, 2, 13, 10)), local(2011, 2, 14)); +}); + +it("timeMonthDay.ceil(date) observes end of daylight saving", () => { + assert.deepStrictEqual(timeMonthDay.ceil(utc(2011, 10, 6, 7)), local(2011, 10, 6)); + assert.deepStrictEqual(timeMonthDay.ceil(utc(2011, 10, 6, 8)), local(2011, 10, 7)); + assert.deepStrictEqual(timeMonthDay.ceil(utc(2011, 10, 6, 9)), local(2011, 10, 7)); + assert.deepStrictEqual(timeMonthDay.ceil(utc(2011, 10, 6, 10)), local(2011, 10, 7)); +}); + +it("timeMonthDay.ceil(date) handles midnight for leap years", () => { + assert.deepStrictEqual(timeMonthDay.ceil(utc(2012, 2, 1, 0)), local(2012, 2, 1)); + assert.deepStrictEqual(timeMonthDay.ceil(utc(2012, 2, 1, 0)), local(2012, 2, 1)); +}); + +it("timeMonthDay.offset(date) is an alias for timeMonthDay.offset(date, 1)", () => { + assert.deepStrictEqual(timeMonthDay.offset(local(2010, 11, 31, 23, 59, 59, 999)), local(2011, 0, 1, 23, 59, 59, 999)); +}); + +it("timeMonthDay.offset(date, step) does not modify the passed-in date", () => { + const d = local(2010, 11, 31, 23, 59, 59, 999); + timeMonthDay.offset(d, +1); + assert.deepStrictEqual(d, local(2010, 11, 31, 23, 59, 59, 999)); +}); + +it("timeMonthDay.offset(date, step) does not round the passed-in date", () => { + assert.deepStrictEqual(timeMonthDay.offset(local(2010, 11, 31, 23, 59, 59, 999), +1), local(2011, 0, 1, 23, 59, 59, 999)); + assert.deepStrictEqual(timeMonthDay.offset(local(2010, 11, 31, 23, 59, 59, 456), -2), local(2010, 11, 29, 23, 59, 59, 456)); +}); + +it("timeMonthDay.offset(date, step) allows step to be negative", () => { + assert.deepStrictEqual(timeMonthDay.offset(local(2010, 11, 31), -1), local(2010, 11, 30)); + assert.deepStrictEqual(timeMonthDay.offset(local(2011, 0, 1), -2), local(2010, 11, 30)); + assert.deepStrictEqual(timeMonthDay.offset(local(2011, 0, 1), -1), local(2010, 11, 31)); +}); + +it("timeMonthDay.offset(date, step) allows step to be positive", () => { + assert.deepStrictEqual(timeMonthDay.offset(local(2010, 11, 31), +1), local(2011, 0, 1)); + assert.deepStrictEqual(timeMonthDay.offset(local(2010, 11, 30), +2), local(2011, 0, 1)); + assert.deepStrictEqual(timeMonthDay.offset(local(2010, 11, 30), +1), local(2010, 11, 31)); +}); + +it("timeMonthDay.offset(date, step) allows step to be zero", () => { + assert.deepStrictEqual(timeMonthDay.offset(local(2010, 11, 31, 23, 59, 59, 999), 0), local(2010, 11, 31, 23, 59, 59, 999)); + assert.deepStrictEqual(timeMonthDay.offset(local(2010, 11, 31, 23, 59, 58, 0), 0), local(2010, 11, 31, 23, 59, 58, 0)); +}); + +it("timeMonthDay.range(start, stop) returns days between start (inclusive) and stop (exclusive)", () => { + assert.deepStrictEqual(timeMonthDay.range(local(2011, 10, 4), local(2011, 10, 10)), [ + local(2011, 10, 4), + local(2011, 10, 5), + local(2011, 10, 6), + local(2011, 10, 7), + local(2011, 10, 8), + local(2011, 10, 9) + ]); +}); + +it("timeMonthDay.range(start, stop) returns days", () => { + assert.deepStrictEqual(timeMonthDay.range(local(2011, 10, 4, 2), local(2011, 10, 10, 13)), [ + local(2011, 10, 5), + local(2011, 10, 6), + local(2011, 10, 7), + local(2011, 10, 8), + local(2011, 10, 9), + local(2011, 10, 10) + ]); +}); + +it("timeMonthDay.range(start, stop) coerces start and stop to dates", () => { + assert.deepStrictEqual(timeMonthDay.range(+local(2011, 10, 4), +local(2011, 10, 7)), [ + local(2011, 10, 4), + local(2011, 10, 5), + local(2011, 10, 6) + ]); +}); + +it("timeMonthDay.range(start, stop) returns the empty array for invalid dates", () => { + assert.deepStrictEqual(timeMonthDay.range(new Date(NaN), Infinity), []); +}); + +it("timeMonthDay.range(start, stop) returns the empty array if start >= stop", () => { + assert.deepStrictEqual(timeMonthDay.range(local(2011, 10, 10), local(2011, 10, 4)), []); + assert.deepStrictEqual(timeMonthDay.range(local(2011, 10, 10), local(2011, 10, 10)), []); +}); + +it("timeMonthDay.range(start, stop, step) returns every step day", () => { + assert.deepStrictEqual(timeMonthDay.range(local(2011, 10, 4, 2), local(2011, 10, 14, 13), 3), [ + local(2011, 10, 5), + local(2011, 10, 8), + local(2011, 10, 11), + local(2011, 10, 14) + ]); +}); + +it("timeMonthDay.range(start, stop, step) returns the empty array if step is zero, negative or NaN", () => { + assert.deepStrictEqual(timeMonthDay.range(local(2011, 0, 1, 0), local(2011, 4, 9, 0), 0), []); + assert.deepStrictEqual(timeMonthDay.range(local(2011, 0, 1, 0), local(2011, 4, 9, 0), -1), []); + assert.deepStrictEqual(timeMonthDay.range(local(2011, 0, 1, 0), local(2011, 4, 9, 0), 0.5), []); + assert.deepStrictEqual(timeMonthDay.range(local(2011, 0, 1, 0), local(2011, 4, 9, 0), NaN), []); +}); + +it("timeMonthDay.count(start, end) counts days after start (exclusive) and before end (inclusive)", () => { + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1, 0), local(2011, 4, 9, 0)), 128); + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1, 1), local(2011, 4, 9, 0)), 128); + assert.strictEqual(timeMonthDay.count(local(2010, 11, 31, 23), local(2011, 4, 9, 0)), 129); + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1, 0), local(2011, 4, 8, 23)), 127); + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1, 0), local(2011, 4, 9, 1)), 128); +}); + +it("timeMonthDay.count(start, end) observes daylight saving", () => { + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1), local(2011, 2, 13, 1)), 71); + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1), local(2011, 2, 13, 3)), 71); + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1), local(2011, 2, 13, 4)), 71); + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1), local(2011, 10, 6, 0)), 309); + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1), local(2011, 10, 6, 1)), 309); + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1), local(2011, 10, 6, 2)), 309); +}); + +it("timeMonthDay.count(start, stop) does not exhibit floating-point rounding error", () => { + const date = new Date(2011, 4, 9); + assert.strictEqual(timeMonthDay.count(timeYear(date), date), 128); +}); + +it("timeMonthDay.count(start, end) returns 364 or 365 for a full year", () => { + assert.strictEqual(timeMonthDay.count(local(1999, 0, 1), local(1999, 11, 31)), 364); + assert.strictEqual(timeMonthDay.count(local(2000, 0, 1), local(2000, 11, 31)), 365); // leap year + assert.strictEqual(timeMonthDay.count(local(2001, 0, 1), local(2001, 11, 31)), 364); + assert.strictEqual(timeMonthDay.count(local(2002, 0, 1), local(2002, 11, 31)), 364); + assert.strictEqual(timeMonthDay.count(local(2003, 0, 1), local(2003, 11, 31)), 364); + assert.strictEqual(timeMonthDay.count(local(2004, 0, 1), local(2004, 11, 31)), 365); // leap year + assert.strictEqual(timeMonthDay.count(local(2005, 0, 1), local(2005, 11, 31)), 364); + assert.strictEqual(timeMonthDay.count(local(2006, 0, 1), local(2006, 11, 31)), 364); + assert.strictEqual(timeMonthDay.count(local(2007, 0, 1), local(2007, 11, 31)), 364); + assert.strictEqual(timeMonthDay.count(local(2008, 0, 1), local(2008, 11, 31)), 365); // leap year + assert.strictEqual(timeMonthDay.count(local(2009, 0, 1), local(2009, 11, 31)), 364); + assert.strictEqual(timeMonthDay.count(local(2010, 0, 1), local(2010, 11, 31)), 364); + assert.strictEqual(timeMonthDay.count(local(2011, 0, 1), local(2011, 11, 31)), 364); +}); + +it("timeMonthDay.every(step) returns every stepth day, starting with the first day of the month", () => { + assert.deepStrictEqual(timeMonthDay.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(timeMonthDay.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(timeMonthDay.every(7).range(local(2008, 11, 30, 0, 12), local(2009, 0, 8, 23, 48)), [local(2009, 0, 1), local(2009, 0, 8)]); +}); diff --git a/test/ticks-test.js b/test/ticks-test.js index 36c0318..8ee1e56 100644 --- a/test/ticks-test.js +++ b/test/ticks-test.js @@ -163,6 +163,16 @@ it("timeTicks(start, stop, count) can generate 2-day ticks", () => { ]); }); +it("timeTicks(start, stop, count) can generate regular 2-day ticks across month boundaries", () => { + assert.deepStrictEqual(timeTicks(local(2011, 0, 25, 16, 28, 27), local(2011, 1, 5, 21, 34, 12), 4), [ + local(2011, 0, 27, 0, 0), + local(2011, 0, 29, 0, 0), + local(2011, 0, 31, 0, 0), + local(2011, 1, 2, 0, 0), + local(2011, 1, 4, 0, 0) + ]); +}); + it("timeTicks(start, stop, count) can generate 1-week ticks", () => { assert.deepStrictEqual(timeTicks(local(2011, 0, 1, 16, 28, 27), local(2011, 0, 23, 21, 34, 12), 4), [ local(2011, 0, 2, 0, 0), diff --git a/test/unixDay-test.js b/test/unixDay-test.js deleted file mode 100644 index 60a916b..0000000 --- a/test/unixDay-test.js +++ /dev/null @@ -1,117 +0,0 @@ -import assert from "assert"; -import {unixDay, unixDays} from "../src/index.js"; -import {utc} from "./date.js"; - -it("unixDays in an alias for unixDay.range", () => { - assert.strictEqual(unixDays, unixDay.range); -}); - -it("unixDay.floor(date) returns days", () => { - assert.deepStrictEqual(unixDay.floor(utc(2010, 11, 31, 23)), utc(2010, 11, 31)); - assert.deepStrictEqual(unixDay.floor(utc(2011, 0, 1, 0)), utc(2011, 0, 1)); - assert.deepStrictEqual(unixDay.floor(utc(2011, 0, 1, 1)), utc(2011, 0, 1)); -}); - -it("unixDay.floor(date) does not observe daylight saving", () => { - assert.deepStrictEqual(unixDay.floor(utc(2011, 2, 13, 7)), utc(2011, 2, 13)); - assert.deepStrictEqual(unixDay.floor(utc(2011, 2, 13, 8)), utc(2011, 2, 13)); - assert.deepStrictEqual(unixDay.floor(utc(2011, 2, 13, 9)), utc(2011, 2, 13)); - assert.deepStrictEqual(unixDay.floor(utc(2011, 2, 13, 10)), utc(2011, 2, 13)); - assert.deepStrictEqual(unixDay.floor(utc(2011, 10, 6, 5)), utc(2011, 10, 6)); - assert.deepStrictEqual(unixDay.floor(utc(2011, 10, 6, 6)), utc(2011, 10, 6)); - assert.deepStrictEqual(unixDay.floor(utc(2011, 10, 6, 7)), utc(2011, 10, 6)); - assert.deepStrictEqual(unixDay.floor(utc(2011, 10, 6, 8)), utc(2011, 10, 6)); -}); - -it("unixDay.round(date) returns days", () => { - assert.deepStrictEqual(unixDay.round(utc(2010, 11, 30, 13)), utc(2010, 11, 31)); - assert.deepStrictEqual(unixDay.round(utc(2010, 11, 30, 11)), utc(2010, 11, 30)); -}); - -it("unixDay.ceil(date) returns days", () => { - assert.deepStrictEqual(unixDay.ceil(utc(2010, 11, 30, 23)), utc(2010, 11, 31)); - assert.deepStrictEqual(unixDay.ceil(utc(2010, 11, 31, 0)), utc(2010, 11, 31)); - assert.deepStrictEqual(unixDay.ceil(utc(2010, 11, 31, 1)), utc(2011, 0, 1)); -}); - -it("unixDay.ceil(date) does not observe daylight saving", () => { - assert.deepStrictEqual(unixDay.ceil(utc(2011, 2, 13, 7)), utc(2011, 2, 14)); - assert.deepStrictEqual(unixDay.ceil(utc(2011, 2, 13, 8)), utc(2011, 2, 14)); - assert.deepStrictEqual(unixDay.ceil(utc(2011, 2, 13, 9)), utc(2011, 2, 14)); - assert.deepStrictEqual(unixDay.ceil(utc(2011, 2, 13, 10)), utc(2011, 2, 14)); - assert.deepStrictEqual(unixDay.ceil(utc(2011, 10, 6, 5)), utc(2011, 10, 7)); - assert.deepStrictEqual(unixDay.ceil(utc(2011, 10, 6, 6)), utc(2011, 10, 7)); - assert.deepStrictEqual(unixDay.ceil(utc(2011, 10, 6, 7)), utc(2011, 10, 7)); - assert.deepStrictEqual(unixDay.ceil(utc(2011, 10, 6, 8)), utc(2011, 10, 7)); -}); - -it("unixDay.offset(date) is an alias for unixDay.offset(date, 1)", () => { - assert.deepStrictEqual(unixDay.offset(utc(2010, 11, 31, 23, 59, 59, 999)), utc(2011, 0, 1, 23, 59, 59, 999)); -}); - -it("unixDay.offset(date, step) does not modify the passed-in date", () => { - const d = utc(2010, 11, 31, 23, 59, 59, 999); - unixDay.offset(d, +1); - assert.deepStrictEqual(d, utc(2010, 11, 31, 23, 59, 59, 999)); -}); - -it("unixDay.offset(date, step) does not round the passed-in date", () => { - assert.deepStrictEqual(unixDay.offset(utc(2010, 11, 31, 23, 59, 59, 999), +1), utc(2011, 0, 1, 23, 59, 59, 999)); - assert.deepStrictEqual(unixDay.offset(utc(2010, 11, 31, 23, 59, 59, 456), -2), utc(2010, 11, 29, 23, 59, 59, 456)); -}); - -it("unixDay.offset(date, step) allows step to be negative", () => { - assert.deepStrictEqual(unixDay.offset(utc(2010, 11, 31), -1), utc(2010, 11, 30)); - assert.deepStrictEqual(unixDay.offset(utc(2011, 0, 1), -2), utc(2010, 11, 30)); - assert.deepStrictEqual(unixDay.offset(utc(2011, 0, 1), -1), utc(2010, 11, 31)); -}); - -it("unixDay.offset(date, step) allows step to be positive", () => { - assert.deepStrictEqual(unixDay.offset(utc(2010, 11, 31), +1), utc(2011, 0, 1)); - assert.deepStrictEqual(unixDay.offset(utc(2010, 11, 30), +2), utc(2011, 0, 1)); - assert.deepStrictEqual(unixDay.offset(utc(2010, 11, 30), +1), utc(2010, 11, 31)); -}); - -it("unixDay.offset(date, step) allows step to be zero", () => { - assert.deepStrictEqual(unixDay.offset(utc(2010, 11, 31, 23, 59, 59, 999), 0), utc(2010, 11, 31, 23, 59, 59, 999)); - assert.deepStrictEqual(unixDay.offset(utc(2010, 11, 31, 23, 59, 58, 0), 0), utc(2010, 11, 31, 23, 59, 58, 0)); -}); - -it("unixDay.count(start, end) counts days after start (exclusive) and before end (inclusive)", () => { - assert.strictEqual(unixDay.count(utc(2011, 0, 1, 0), utc(2011, 4, 9, 0)), 128); - assert.strictEqual(unixDay.count(utc(2011, 0, 1, 1), utc(2011, 4, 9, 0)), 128); - assert.strictEqual(unixDay.count(utc(2010, 11, 31, 23), utc(2011, 4, 9, 0)), 129); - assert.strictEqual(unixDay.count(utc(2011, 0, 1, 0), utc(2011, 4, 8, 23)), 127); - assert.strictEqual(unixDay.count(utc(2011, 0, 1, 0), utc(2011, 4, 9, 1)), 128); -}); - -it("unixDay.count(start, end) does not observe daylight saving", () => { - assert.strictEqual(unixDay.count(utc(2011, 0, 1), utc(2011, 2, 13, 1)), 71); - assert.strictEqual(unixDay.count(utc(2011, 0, 1), utc(2011, 2, 13, 3)), 71); - assert.strictEqual(unixDay.count(utc(2011, 0, 1), utc(2011, 2, 13, 4)), 71); - assert.strictEqual(unixDay.count(utc(2011, 0, 1), utc(2011, 10, 6, 0)), 309); - assert.strictEqual(unixDay.count(utc(2011, 0, 1), utc(2011, 10, 6, 1)), 309); - assert.strictEqual(unixDay.count(utc(2011, 0, 1), utc(2011, 10, 6, 2)), 309); -}); - -it("unixDay.count(start, end) returns 364 or 365 for a full year", () => { - assert.strictEqual(unixDay.count(utc(1999, 0, 1), utc(1999, 11, 31)), 364); - assert.strictEqual(unixDay.count(utc(2000, 0, 1), utc(2000, 11, 31)), 365); // leap year - assert.strictEqual(unixDay.count(utc(2001, 0, 1), utc(2001, 11, 31)), 364); - assert.strictEqual(unixDay.count(utc(2002, 0, 1), utc(2002, 11, 31)), 364); - assert.strictEqual(unixDay.count(utc(2003, 0, 1), utc(2003, 11, 31)), 364); - assert.strictEqual(unixDay.count(utc(2004, 0, 1), utc(2004, 11, 31)), 365); // leap year - assert.strictEqual(unixDay.count(utc(2005, 0, 1), utc(2005, 11, 31)), 364); - assert.strictEqual(unixDay.count(utc(2006, 0, 1), utc(2006, 11, 31)), 364); - assert.strictEqual(unixDay.count(utc(2007, 0, 1), utc(2007, 11, 31)), 364); - assert.strictEqual(unixDay.count(utc(2008, 0, 1), utc(2008, 11, 31)), 365); // leap year - assert.strictEqual(unixDay.count(utc(2009, 0, 1), utc(2009, 11, 31)), 364); - assert.strictEqual(unixDay.count(utc(2010, 0, 1), utc(2010, 11, 31)), 364); - assert.strictEqual(unixDay.count(utc(2011, 0, 1), utc(2011, 11, 31)), 364); -}); - -it("unixDay.every(step) returns every stepth day", () => { - assert.deepStrictEqual(unixDay.every(3).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 5, 23, 48)), [utc(2008, 11, 31), utc(2009, 0, 3)]); - assert.deepStrictEqual(unixDay.every(5).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 6, 23, 48)), [utc(2009, 0, 1), utc(2009, 0, 6)]); - assert.deepStrictEqual(unixDay.every(7).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 8, 23, 48)), [utc(2009, 0, 1), utc(2009, 0, 8)]); -}); diff --git a/test/utcDay-test.js b/test/utcDay-test.js index f521c91..80ab5b1 100644 --- a/test/utcDay-test.js +++ b/test/utcDay-test.js @@ -110,8 +110,8 @@ it("utcDay.count(start, end) returns 364 or 365 for a full year", () => { assert.strictEqual(utcDay.count(utc(2011, 0, 1), utc(2011, 11, 31)), 364); }); -it("utcDay.every(step) returns every stepth day, starting with the first day of the month", () => { - assert.deepStrictEqual(utcDay.every(3).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 5, 23, 48)), [utc(2008, 11, 31), utc(2009, 0, 1), utc(2009, 0, 4)]); - assert.deepStrictEqual(utcDay.every(5).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 6, 23, 48)), [utc(2008, 11, 31), utc(2009, 0, 1), utc(2009, 0, 6)]); +it("utcDay.every(step) returns every stepth day", () => { + assert.deepStrictEqual(utcDay.every(3).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 5, 23, 48)), [utc(2008, 11, 31), utc(2009, 0, 3)]); + assert.deepStrictEqual(utcDay.every(5).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 6, 23, 48)), [utc(2009, 0, 1), utc(2009, 0, 6)]); assert.deepStrictEqual(utcDay.every(7).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 8, 23, 48)), [utc(2009, 0, 1), utc(2009, 0, 8)]); }); diff --git a/test/utcMonthDay-test.js b/test/utcMonthDay-test.js new file mode 100644 index 0000000..e3ffcf1 --- /dev/null +++ b/test/utcMonthDay-test.js @@ -0,0 +1,117 @@ +import assert from "assert"; +import {utcMonthDay, utcMonthDays} from "../src/index.js"; +import {utc} from "./date.js"; + +it("utcMonthDays in an alias for utcMonthDay.range", () => { + assert.strictEqual(utcMonthDays, utcMonthDay.range); +}); + +it("utcMonthDay.floor(date) returns days", () => { + assert.deepStrictEqual(utcMonthDay.floor(utc(2010, 11, 31, 23)), utc(2010, 11, 31)); + assert.deepStrictEqual(utcMonthDay.floor(utc(2011, 0, 1, 0)), utc(2011, 0, 1)); + assert.deepStrictEqual(utcMonthDay.floor(utc(2011, 0, 1, 1)), utc(2011, 0, 1)); +}); + +it("utcMonthDay.floor(date) does not observe daylight saving", () => { + assert.deepStrictEqual(utcMonthDay.floor(utc(2011, 2, 13, 7)), utc(2011, 2, 13)); + assert.deepStrictEqual(utcMonthDay.floor(utc(2011, 2, 13, 8)), utc(2011, 2, 13)); + assert.deepStrictEqual(utcMonthDay.floor(utc(2011, 2, 13, 9)), utc(2011, 2, 13)); + assert.deepStrictEqual(utcMonthDay.floor(utc(2011, 2, 13, 10)), utc(2011, 2, 13)); + assert.deepStrictEqual(utcMonthDay.floor(utc(2011, 10, 6, 5)), utc(2011, 10, 6)); + assert.deepStrictEqual(utcMonthDay.floor(utc(2011, 10, 6, 6)), utc(2011, 10, 6)); + assert.deepStrictEqual(utcMonthDay.floor(utc(2011, 10, 6, 7)), utc(2011, 10, 6)); + assert.deepStrictEqual(utcMonthDay.floor(utc(2011, 10, 6, 8)), utc(2011, 10, 6)); +}); + +it("utcMonthDay.round(date) returns days", () => { + assert.deepStrictEqual(utcMonthDay.round(utc(2010, 11, 30, 13)), utc(2010, 11, 31)); + assert.deepStrictEqual(utcMonthDay.round(utc(2010, 11, 30, 11)), utc(2010, 11, 30)); +}); + +it("utcMonthDay.ceil(date) returns days", () => { + assert.deepStrictEqual(utcMonthDay.ceil(utc(2010, 11, 30, 23)), utc(2010, 11, 31)); + assert.deepStrictEqual(utcMonthDay.ceil(utc(2010, 11, 31, 0)), utc(2010, 11, 31)); + assert.deepStrictEqual(utcMonthDay.ceil(utc(2010, 11, 31, 1)), utc(2011, 0, 1)); +}); + +it("utcMonthDay.ceil(date) does not observe daylight saving", () => { + assert.deepStrictEqual(utcMonthDay.ceil(utc(2011, 2, 13, 7)), utc(2011, 2, 14)); + assert.deepStrictEqual(utcMonthDay.ceil(utc(2011, 2, 13, 8)), utc(2011, 2, 14)); + assert.deepStrictEqual(utcMonthDay.ceil(utc(2011, 2, 13, 9)), utc(2011, 2, 14)); + assert.deepStrictEqual(utcMonthDay.ceil(utc(2011, 2, 13, 10)), utc(2011, 2, 14)); + assert.deepStrictEqual(utcMonthDay.ceil(utc(2011, 10, 6, 5)), utc(2011, 10, 7)); + assert.deepStrictEqual(utcMonthDay.ceil(utc(2011, 10, 6, 6)), utc(2011, 10, 7)); + assert.deepStrictEqual(utcMonthDay.ceil(utc(2011, 10, 6, 7)), utc(2011, 10, 7)); + assert.deepStrictEqual(utcMonthDay.ceil(utc(2011, 10, 6, 8)), utc(2011, 10, 7)); +}); + +it("utcMonthDay.offset(date) is an alias for utcMonthDay.offset(date, 1)", () => { + assert.deepStrictEqual(utcMonthDay.offset(utc(2010, 11, 31, 23, 59, 59, 999)), utc(2011, 0, 1, 23, 59, 59, 999)); +}); + +it("utcMonthDay.offset(date, step) does not modify the passed-in date", () => { + const d = utc(2010, 11, 31, 23, 59, 59, 999); + utcMonthDay.offset(d, +1); + assert.deepStrictEqual(d, utc(2010, 11, 31, 23, 59, 59, 999)); +}); + +it("utcMonthDay.offset(date, step) does not round the passed-in date", () => { + assert.deepStrictEqual(utcMonthDay.offset(utc(2010, 11, 31, 23, 59, 59, 999), +1), utc(2011, 0, 1, 23, 59, 59, 999)); + assert.deepStrictEqual(utcMonthDay.offset(utc(2010, 11, 31, 23, 59, 59, 456), -2), utc(2010, 11, 29, 23, 59, 59, 456)); +}); + +it("utcMonthDay.offset(date, step) allows step to be negative", () => { + assert.deepStrictEqual(utcMonthDay.offset(utc(2010, 11, 31), -1), utc(2010, 11, 30)); + assert.deepStrictEqual(utcMonthDay.offset(utc(2011, 0, 1), -2), utc(2010, 11, 30)); + assert.deepStrictEqual(utcMonthDay.offset(utc(2011, 0, 1), -1), utc(2010, 11, 31)); +}); + +it("utcMonthDay.offset(date, step) allows step to be positive", () => { + assert.deepStrictEqual(utcMonthDay.offset(utc(2010, 11, 31), +1), utc(2011, 0, 1)); + assert.deepStrictEqual(utcMonthDay.offset(utc(2010, 11, 30), +2), utc(2011, 0, 1)); + assert.deepStrictEqual(utcMonthDay.offset(utc(2010, 11, 30), +1), utc(2010, 11, 31)); +}); + +it("utcMonthDay.offset(date, step) allows step to be zero", () => { + assert.deepStrictEqual(utcMonthDay.offset(utc(2010, 11, 31, 23, 59, 59, 999), 0), utc(2010, 11, 31, 23, 59, 59, 999)); + assert.deepStrictEqual(utcMonthDay.offset(utc(2010, 11, 31, 23, 59, 58, 0), 0), utc(2010, 11, 31, 23, 59, 58, 0)); +}); + +it("utcMonthDay.count(start, end) counts days after start (exclusive) and before end (inclusive)", () => { + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1, 0), utc(2011, 4, 9, 0)), 128); + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1, 1), utc(2011, 4, 9, 0)), 128); + assert.strictEqual(utcMonthDay.count(utc(2010, 11, 31, 23), utc(2011, 4, 9, 0)), 129); + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1, 0), utc(2011, 4, 8, 23)), 127); + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1, 0), utc(2011, 4, 9, 1)), 128); +}); + +it("utcMonthDay.count(start, end) does not observe daylight saving", () => { + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1), utc(2011, 2, 13, 1)), 71); + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1), utc(2011, 2, 13, 3)), 71); + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1), utc(2011, 2, 13, 4)), 71); + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1), utc(2011, 10, 6, 0)), 309); + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1), utc(2011, 10, 6, 1)), 309); + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1), utc(2011, 10, 6, 2)), 309); +}); + +it("utcMonthDay.count(start, end) returns 364 or 365 for a full year", () => { + assert.strictEqual(utcMonthDay.count(utc(1999, 0, 1), utc(1999, 11, 31)), 364); + assert.strictEqual(utcMonthDay.count(utc(2000, 0, 1), utc(2000, 11, 31)), 365); // leap year + assert.strictEqual(utcMonthDay.count(utc(2001, 0, 1), utc(2001, 11, 31)), 364); + assert.strictEqual(utcMonthDay.count(utc(2002, 0, 1), utc(2002, 11, 31)), 364); + assert.strictEqual(utcMonthDay.count(utc(2003, 0, 1), utc(2003, 11, 31)), 364); + assert.strictEqual(utcMonthDay.count(utc(2004, 0, 1), utc(2004, 11, 31)), 365); // leap year + assert.strictEqual(utcMonthDay.count(utc(2005, 0, 1), utc(2005, 11, 31)), 364); + assert.strictEqual(utcMonthDay.count(utc(2006, 0, 1), utc(2006, 11, 31)), 364); + assert.strictEqual(utcMonthDay.count(utc(2007, 0, 1), utc(2007, 11, 31)), 364); + assert.strictEqual(utcMonthDay.count(utc(2008, 0, 1), utc(2008, 11, 31)), 365); // leap year + assert.strictEqual(utcMonthDay.count(utc(2009, 0, 1), utc(2009, 11, 31)), 364); + assert.strictEqual(utcMonthDay.count(utc(2010, 0, 1), utc(2010, 11, 31)), 364); + assert.strictEqual(utcMonthDay.count(utc(2011, 0, 1), utc(2011, 11, 31)), 364); +}); + +it("utcMonthDay.every(step) returns every stepth day, starting with the first day of the month", () => { + assert.deepStrictEqual(utcMonthDay.every(3).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 5, 23, 48)), [utc(2008, 11, 31), utc(2009, 0, 1), utc(2009, 0, 4)]); + assert.deepStrictEqual(utcMonthDay.every(5).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 6, 23, 48)), [utc(2008, 11, 31), utc(2009, 0, 1), utc(2009, 0, 6)]); + assert.deepStrictEqual(utcMonthDay.every(7).range(utc(2008, 11, 30, 0, 12), utc(2009, 0, 8, 23, 48)), [utc(2009, 0, 1), utc(2009, 0, 8)]); +}); diff --git a/test/utcTicks-test.js b/test/utcTicks-test.js index fc243a3..35cbf1a 100644 --- a/test/utcTicks-test.js +++ b/test/utcTicks-test.js @@ -158,6 +158,16 @@ it("utcTicks(start, stop, count) can generate 2-day ticks", () => { ]); }); +it("utcTicks(start, stop, count) can generate regular 2-day ticks across month boundaries", () => { + assert.deepStrictEqual(utcTicks(utc(2011, 2, 25, 16, 28, 27), utc(2011, 3, 5, 21, 34, 12), 4), [ + utc(2011, 2, 27, 0, 0), + utc(2011, 2, 29, 0, 0), + utc(2011, 2, 31, 0, 0), + utc(2011, 3, 2, 0, 0), + utc(2011, 3, 4, 0, 0) + ]); +}); + it("utcTicks(start, stop, count) can generate 1-week ticks", () => { assert.deepStrictEqual(utcTicks(utc(2011, 0, 1, 16, 28, 27), utc(2011, 0, 23, 21, 34, 12), 4), [ utc(2011, 0, 2, 0, 0), From ce3a3806bb10524985aac727cf4c70f8dcf51e60 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sun, 25 Jun 2023 14:03:05 -0700 Subject: [PATCH 2/2] deprecate unixDay --- README.md | 6 ++---- src/index.js | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a7b4eaf..348f85d 100644 --- a/README.md +++ b/README.md @@ -197,9 +197,8 @@ Hours (e.g., 01:00 AM); 60 minutes. Note that advancing time by one hour in loca # d3.timeDay · [Source](https://github.com/d3/d3-time/blob/main/src/day.js "Source")
# d3.utcDay · [Source](https://github.com/d3/d3-time/blob/main/src/day.js) -
# d3.unixDay · [Source](https://github.com/d3/d3-time/blob/main/src/day.js) -Days (e.g., February 7, 2012 at 12:00 AM); typically 24 hours. Days in local time may range from 23 to 25 hours due to daylight saving. d3.unixDay is like [d3.utcDay](#timeDay), except it counts days since the UNIX epoch (January 1, 1970) such that *interval*.every returns uniformly-spaced dates rather than varying based on day-of-month. +Days (e.g., February 7, 2012 at 12:00 AM); typically 24 hours. Days in local time may range from 23 to 25 hours due to daylight saving. # d3.timeWeek · [Source](https://github.com/d3/d3-time/blob/main/src/week.js "Source")
# d3.utcWeek · [Source](https://github.com/d3/d3-time/blob/main/src/utcWeek.js "Source") @@ -277,9 +276,8 @@ Aliases for [d3.timeHour](#timeHour).[range](#interval_range) and [d3.utcHour](# # d3.timeDays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/day.js)
# d3.utcDays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/day.js) -
# d3.unixDays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/main/src/day.js) -Aliases for [d3.timeDay](#timeDay).[range](#interval_range), [d3.utcDay](#timeDay).[range](#interval_range), and [d3.unixDay](#timeDay).[range](#interval_range). +Aliases for [d3.timeDay](#timeDay).[range](#interval_range) and [d3.utcDay](#timeDay).[range](#interval_range). # d3.timeWeeks(start, stop[, step])
# d3.utcWeeks(start, stop[, step]) diff --git a/src/index.js b/src/index.js index f11d7c5..1da1572 100644 --- a/src/index.js +++ b/src/index.js @@ -35,6 +35,8 @@ export { timeDays, timeMonthDay, timeMonthDays, + utcDay as unixDay, // deprecated; use utcDay + utcDays as unixDays, // deprecated; use utcDays utcDay, utcDays, utcMonthDay,