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/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..1da1572 100644
--- a/src/index.js
+++ b/src/index.js
@@ -33,10 +33,14 @@ export {
export {
timeDay,
timeDays,
+ timeMonthDay,
+ timeMonthDays,
+ utcDay as unixDay, // deprecated; use utcDay
+ utcDays as unixDays, // deprecated; use utcDays
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),