diff --git a/README.md b/README.md
index f17811d..8433235 100644
--- a/README.md
+++ b/README.md
@@ -197,8 +197,9 @@ 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/master/src/day.js "Source")
# d3.utcDay · [Source](https://github.com/d3/d3-time/blob/master/src/utcDay.js "Source")
+
# d3.unixDay · [Source](https://github.com/d3/d3-time/blob/master/src/unixDay.js "Source")
-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.
+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.
# d3.timeWeek · [Source](https://github.com/d3/d3-time/blob/master/src/week.js "Source")
# d3.utcWeek · [Source](https://github.com/d3/d3-time/blob/master/src/utcWeek.js "Source")
@@ -276,8 +277,9 @@ Aliases for [d3.timeHour](#timeHour).[range](#interval_range) and [d3.utcHour](#
# d3.timeDays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/master/src/day.js)
# d3.utcDays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/master/src/utcDay.js)
+
# d3.unixDays(start, stop[, step]) · [Source](https://github.com/d3/d3-time/blob/master/src/unixDay.js)
-Aliases for [d3.timeDay](#timeDay).[range](#interval_range) and [d3.utcDay](#timeDay).[range](#interval_range).
+Aliases for [d3.timeDay](#timeDay).[range](#interval_range), [d3.utcDay](#timeDay).[range](#interval_range), and [d3.unixDay](#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 c163d63..9ceb157 100644
--- a/src/index.js
+++ b/src/index.js
@@ -62,46 +62,51 @@ export {
export {
default as utcMinute,
- utcMinutes as utcMinutes
+ utcMinutes
} from "./utcMinute.js";
export {
default as utcHour,
- utcHours as utcHours
+ utcHours
} from "./utcHour.js";
export {
default as utcDay,
- utcDays as utcDays
+ utcDays
} from "./utcDay.js";
+export {
+ default as unixDay,
+ unixDays
+} from "./unixDay.js";
+
export {
utcSunday as utcWeek,
utcSundays as utcWeeks,
- utcSunday as utcSunday,
- utcSundays as utcSundays,
- utcMonday as utcMonday,
- utcMondays as utcMondays,
- utcTuesday as utcTuesday,
- utcTuesdays as utcTuesdays,
- utcWednesday as utcWednesday,
- utcWednesdays as utcWednesdays,
- utcThursday as utcThursday,
- utcThursdays as utcThursdays,
- utcFriday as utcFriday,
- utcFridays as utcFridays,
- utcSaturday as utcSaturday,
- utcSaturdays as utcSaturdays
+ utcSunday,
+ utcSundays,
+ utcMonday,
+ utcMondays,
+ utcTuesday,
+ utcTuesdays,
+ utcWednesday,
+ utcWednesdays,
+ utcThursday,
+ utcThursdays,
+ utcFriday,
+ utcFridays,
+ utcSaturday,
+ utcSaturdays
} from "./utcWeek.js";
export {
default as utcMonth,
- utcMonths as utcMonths
+ utcMonths
} from "./utcMonth.js";
export {
default as utcYear,
- utcYears as utcYears
+ utcYears
} from "./utcYear.js";
export {
diff --git a/src/ticks.js b/src/ticks.js
index e221936..ff71c76 100644
--- a/src/ticks.js
+++ b/src/ticks.js
@@ -10,7 +10,7 @@ import month from "./month.js";
import year from "./year.js";
import utcMinute from "./utcMinute.js";
import utcHour from "./utcHour.js";
-import utcDay from "./utcDay.js";
+import unixDay from "./unixDay.js";
import {utcSunday as utcWeek} from "./utcWeek.js";
import utcMonth from "./utcMonth.js";
import utcYear from "./utcYear.js";
@@ -58,7 +58,7 @@ function ticker(year, month, week, day, hour, minute) {
return [ticks, tickInterval];
}
-const [utcTicks, utcTickInterval] = ticker(utcYear, utcMonth, utcWeek, utcDay, utcHour, utcMinute);
+const [utcTicks, utcTickInterval] = ticker(utcYear, utcMonth, utcWeek, unixDay, utcHour, utcMinute);
const [timeTicks, timeTickInterval] = ticker(year, month, week, day, hour, minute);
export {utcTicks, utcTickInterval, timeTicks, timeTickInterval};
diff --git a/src/unixDay.js b/src/unixDay.js
new file mode 100644
index 0000000..bbb1bea
--- /dev/null
+++ b/src/unixDay.js
@@ -0,0 +1,15 @@
+import interval from "./interval.js";
+import {durationDay} from "./duration.js";
+
+var unixDay = interval(function(date) {
+ date.setUTCHours(0, 0, 0, 0);
+}, function(date, step) {
+ date.setUTCDate(date.getUTCDate() + step);
+}, function(start, end) {
+ return (end - start) / durationDay;
+}, function(date) {
+ return Math.floor(date / durationDay);
+});
+
+export default unixDay;
+export var unixDays = unixDay.range;
diff --git a/test/unixDay-test.js b/test/unixDay-test.js
new file mode 100644
index 0000000..60a916b
--- /dev/null
+++ b/test/unixDay-test.js
@@ -0,0 +1,117 @@
+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/utcTicks-test.js b/test/utcTicks-test.js
index 0f05cb9..fc243a3 100644
--- a/test/utcTicks-test.js
+++ b/test/utcTicks-test.js
@@ -152,10 +152,9 @@ it("utcTicks(start, stop, count) can generate 1-day ticks", () => {
it("utcTicks(start, stop, count) can generate 2-day ticks", () => {
assert.deepStrictEqual(utcTicks(utc(2011, 0, 2, 16, 28, 27), utc(2011, 0, 9, 21, 34, 12), 4), [
- utc(2011, 0, 3, 0, 0),
- utc(2011, 0, 5, 0, 0),
- utc(2011, 0, 7, 0, 0),
- utc(2011, 0, 9, 0, 0)
+ utc(2011, 0, 4, 0, 0),
+ utc(2011, 0, 6, 0, 0),
+ utc(2011, 0, 8, 0, 0)
]);
});