d3-time
在可视化时间序列数据、分析时间模式或处理一般时间时,常规时间单位的不规则性很快就变得明显起来。在 Gregorian calendar(公历) 中,大多数月份有 31
天但是有些月份只有 28
或者 29
、30
天。大多数年份有 365
天但是 leap years(闰年) 有 366
天。在 daylight saving(夏令时) 中一天可能有 23
25
小时。更复杂的是世界各地的夏时制不同。
由于这些时间特性,执行看似微不足道的任务可能会很困难。例如,如果你想计算两个日期之间相隔的天数,你可能会简单的以 24
小时为一天去计算:
var start = new Date(2015, 02, 01), // Sun Mar 01 2015 00:00:00 GMT-0800 (PST)
end = new Date(2015, 03, 01); // Wed Apr 01 2015 00:00:00 GMT-0700 (PDT)
(end - start) / 864e5; // 30.958333333333332, oops!
但是使用 d3.timeDay.count 会更容易:
d3.timeDay.count(start, end); // 31
day interval 是 d3-time
提供的方法之一. 常用的时间单位比如 hours, weeks, months, etc. 都有对应的计算边界日期的方法。例如 d3.timeDay 通常会以当地时间的午夜作为一天的开始。为了 rounding 和 counting,间隔可以用来生成一组边界日期。比如计算当前月的每一个周日:
var now = new Date;
d3.timeWeek.range(d3.timeMonth.floor(now), d3.timeMonth.ceil(now));
// [Sun Jun 07 2015 00:00:00 GMT-0700 (PDT),
// Sun Jun 14 2015 00:00:00 GMT-0700 (PDT),
// Sun Jun 21 2015 00:00:00 GMT-0700 (PDT),
// Sun Jun 28 2015 00:00:00 GMT-0700 (PDT)]
d3-time
模块不会实现自己的日历系统。它仅仅是基于 ECMAScript
的 Date 实现了一些方便的数学计算 API
. 因此,它忽略了闰秒,只能与当地时区和 Coordinated Universal Time(世界协调时) (UTC)一起工作。
这个模块可以被 D3
的时间比例尺用来生成合理的刻度,通过 D3
的时间格式化可以直接被用来做类似于 calendar layouts 之类的事情。
Installing
NPM
安装: npm install d3-time
. 此外还可以下载 latest release. 可以直接从 d3js.org 以 standalone library 或作为 D3 4.0 的一部分引入. 支持 AMD
, CommonJS
, 以及基本的标签形式,如果使用标签引入会暴露全局 d3
变量:
<script src="https://d3js.org/d3-time.v1.min.js"></script>
<script>
var day = d3.timeDay(new Date);
</script>
API Reference
interval(date) <>
interval.floor 的别名. 例如 d3.timeYear(date) 和 d3.timeYear.floor(date) 是等价的.
interval.floor(date) <>
对日期的向下取整,返回一个新日期,返回的日期不超过当前 date。例如 d3.timeDay.floor(date) 通常返回给定 date 的当天 12:00 AM
.
这个方法是幂等的:如果指定的 date 在当前时间间隔内,则返回相同时间的新日期。此外返回的日期是当前区间内的最小值,比如 interval.floor(interval.floor(date) - 1) 会返回前一个间隔的最小时间值。
注意 ==
and ===
操作不能对比 Date 对象,因此不能使用这个操作来判读指定的 date 是否已经完成向下取整。作为替代,你可以将其转换为数值然后对比:
// Returns true if the specified date is a day boundary.
function isDay(date) {
return +d3.timeDay.floor(date) === +date;
}
这比测试时间是否为 12:00 AM
更可靠,因为在某些时区,由于夏令时可能不存在午夜。
interval.round(date) <>
日期取整,返回指定 date 的取整时刻。例如 d3.timeDay.round(date),如果当前 date 在 12:00 AM
之前会返回当天的 12:00 AM
,否则会返回下一天的 12:00 AM
.
这个方法也是幂等的:对于一定时间区间内的 date 都会返回相同的新时刻。
interval.ceil(date) <>
日期向上取整,返回不晚于指定 date 的最早的时刻。比如,d3.timeDay.ceil(date) 通常会返回指定 date 下一天的 12:00 AM
.
这个方法也是幂等的:对于一定时间区间内的 date 都会返回相同的新时刻。因此 interval.ceil(interval.ceil(date) + 1) 会返回当前日期的下下一天的 12:00 AM
.
interval.offset(date[, step]) <>
返回一个新的日期,新的日期等于 date 加 step 间隔。如果没有指定 step 则默认为 1
。如果 step 为负,则返回的新日期将比指定的 date 早。如果 step 为 0
则返回指定 date 的拷贝;如果 step 不是整数,则会使用 floored 进行取整。这个方法不会对指定的 date 进行四舍五入。例如如果 date 为 今天的 5:34 PM
则 d3.timeDay.offset(date, 1) 会返回明天的 5:34 PM
(即使夏令时改变了也能正确返回)。
interval.range(start, stop[, step]) <>
返回介于 start (包含) 和 stop (不包含) 之间的日期间隔数组。如果 step 没有指定则默认返回每个日期间隔边界值;例如 d3.timeDay 间隔步长设置为 2
时表示每隔一天返回取一个值。如果 step 不是整数,则会使用 floored 进行取整。
返回的数组的第一个元素的日期值表示所取的日期范围的最早值,不早于 start;随后的所有的值之间的间隔都为 step 表示的日期间隔。例如只取奇数天:
d3.timeDay.range(new Date(2015, 0, 1), new Date(2015, 0, 7), 2);
// [Thu Jan 01 2015 00:00:00 GMT-0800 (PST),
// Sat Jan 03 2015 00:00:00 GMT-0800 (PST),
// Mon Jan 05 2015 00:00:00 GMT-0800 (PST)]
只取偶数天:
d3.timeDay.range(new Date(2015, 0, 2), new Date(2015, 0, 8), 2);
// [Fri Jan 02 2015 00:00:00 GMT-0800 (PST),
// Sun Jan 04 2015 00:00:00 GMT-0800 (PST),
// Tue Jan 06 2015 00:00:00 GMT-0800 (PST)]
如果想要每个间隔的步长一致,可以使用 interval.every 代替。
interval.filter(test) <>
返回一个新的间隔,这个间隔是使用 test 函数对指定间隔进行过滤之后的子集。test 函数传递日期并且应该返回真或假以表示当前日期是否被被考虑在内。例如创建一个返回每个月 1st
, 11th
, 21th
and 31th
(如果存在) 的间隔:
var i = d3.timeDay.filter(function(d) { return (d.getDate() - 1) % 10 === 0; });
返回的新的间隔不支持 interval.count. 同时参考 interval.every.
interval.every(step) <>
返回当前间隔的经过过滤后的日期列表。step 依赖于当前间隔的类型,例如 d3.timeMinute.every(15) 会返回一个表示每隔 15
分钟取一个值的间隔。需要注意,对于一些间隔返回的日期可能不是均匀的。如果 step 不可用则返回 null
。如果 step 为 1
则返回当前间隔。
这个方法可以和 interval.range 结合使用以保障生成固定的日期列表:
d3.timeDay.every(2).range(new Date(2015, 0, 1), new Date(2015, 0, 7));
// [Thu Jan 01 2015 00:00:00 GMT-0800 (PST),
// Sat Jan 03 2015 00:00:00 GMT-0800 (PST),
// Mon Jan 05 2015 00:00:00 GMT-0800 (PST)]
同上:
d3.timeDay.every(2).range(new Date(2015, 0, 2), new Date(2015, 0, 8));
// [Sat Jan 03 2015 00:00:00 GMT-0800 (PST),
// Mon Jan 05 2015 00:00:00 GMT-0800 (PST),
// Wed Jan 07 2015 00:00:00 GMT-0800 (PST)]
返回的过滤间隔不支持 interval.count,同时参考 interval.filter.
interval.count(start, end) <>
返回以当前间隔为单位,在 start(不包含) 之后和 end(包含) 之前的个数。注意这个行为与 interval.range 有所不同,因为它的目标是返回 end 相对于 start 之间的统计数。例如计算当前日期在当年内的基于 0
的天数统计:
var now = new Date;
d3.timeDay.count(d3.timeYear(now), now); // 177
同样的,计算当前基于 0
的对周个数统计(过了多少周):
d3.timeSunday.count(d3.timeYear(now), now); // 25
d3.timeInterval(floor, offset[, count[, field]]) <>
构造给定指定的 floor 和 offset 函数以及可选的 count 函数自定义间隔。
floor 函数接受单个日期作为参数,并将其四舍五入到最近的区间边界。
floor 函数以日期和整数步长作为参数,将指定的日期向前推进指定的边界数; 步长可以是正的,负的或零。
可选的 count 函数接收一个起始日期和结束日期,向下取整到当前间隔,并返回开始(独占)和结束(包含)之间的边界数。如果没有指定 count 方法则返回的间隔不会暴露 Intervals
提供以下间隔类型:
d3.timeMillisecond <>
Ranges
为方便起见,interval.range 的别名也以相应区间的复数形式提供。
d3.timeMilliseconds(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/second.js" title="Source" target="_blank" rel="noopener noreferrer"><>
"https://github.com/xswei/d3-time/blob/master/src/minute.js" title="Source" target="_blank" rel="noopener noreferrer"><>
"https://github.com/xswei/d3-time/blob/master/src/utcMinute.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeMinute.range 和 d3.utcMinute.range.
d3.timeHours(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/utcHour.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeHour.range 和 d3.utcHour.range.
d3.timeDays(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/utcDay.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeDay.range 和 d3.utcDay.range.
d3.timeWeeks(start, stop[, step])
"https://github.com/xswei/d3-time/blob/master/src/week.js" title="Source" target="_blank" rel="noopener noreferrer"><>
"https://github.com/xswei/d3-time/blob/master/src/utcWeek.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeSunday.range 和 d3.utcSunday.range.
d3.timeMondays(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/utcWeek.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeMonday.range 和 d3.utcMonday.range.
d3.timeTuesdays(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/utcWeek.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeTuesday.range 和 d3.utcTuesday.range.
d3.timeWednesdays(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/utcWeek.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeWednesday.range 和 d3.utcWednesday.range.
d3.timeThursdays(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/utcWeek.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeThursday.range 和 d3.utcThursday.range.
d3.timeFridays(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/utcWeek.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeFriday.range 和 d3.utcFriday.range.
d3.timeSaturdays(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/utcWeek.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeSaturday.range 和 d3.utcSaturday.range.
d3.timeMonths(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/utcMonth.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeMonth.range 和 d3.utcMonth.range.
d3.timeYears(start, stop[, step]) <>
"https://github.com/xswei/d3-time/blob/master/src/utcYear.js" title="Source" target="_blank" rel="noopener noreferrer"><>
别名 d3.timeYear.range 和 d3.utcYear.range.