Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
系列文章可以查看《数据可视化》专栏
时间修约
时间边距计算器 interval
是一个方法,可以直接调用 interval([date])
以计算出给定时间 date
所属的时间间距的下界,即一个 Date 对象。
// 基于字符串创建一个 Date 对象
// 最后添加 Z 后缀采用 UTC 协调世界时
const utcDateObj = new Date("2022-02-02T06:40:10.123Z");
console.log(utcDateObj); // "2022-02-04T20:40:10.123Z"
// 创建不同间距的 interval,然后直接调用,并指定入参为 utcDateObj
// 由于入参时间是 UTC 格式,所以采用相应的方法创建时距器 interval
const year = d3.utcYear(utcDateObj);
const month = d3.utcMonth(utcDateObj);
const hour = d3.utcHour(utcDateObj);
const minute = d3.utcMinute(utcDateObj);
const second = d3.utcSecond(utcDateObj);
const millisecond = d3.utcMillisecond(utcDateObj);
// 打印不同 interval 调用的结果
// 返回给定时间所属的时间间距的下界,它是一个以该时间创建的 Date 对象,打印出时会自动转变为字符串形式
console.log("utcYear Lower Boundary: ", year);
console.log("utcMonth Lower Boundary: ", month);
console.log("utcHour Lower Boundary: ", hour);
console.log("utcMinute Lower Boundary: ", minute);
console.log("utcSecond Lower Boundary: ", second);
console.log("utcMillisecond Lower Boundary: ", millisecond);
复制代码
控制台输出结果如下,具体代码演示可以查看这个 Codepen
以上示例先基于字符串 2022-02-02T06:40:10.123Z
创建的 Date 对象 utcDateObj
(它采用 UTC 时间)。创建一系列相应的 interval,然后直接调用,并指定入参为创建的 Date 对象 utcDateObj
。这些 interval 分别返回一个新的 Date 对象,它们分别表示 utcDateObj
在相应时间尺度下的下边界时间。可以将这些时距器看作是对当前时间的转换,从入参的 Date 对象提取特定的时间字段,如所在的月份,然后以这个月的第一天的凌晨零点创建一个新的 Date 对象,这个新的 Date 对象表示这个月。这在创建时间轴刻度很实用,如下图是以天为间距、以月为间距、以年为间距的三种 intervals 的示意图:
? 如果可选参数 date
省略,则采用当前时间 new Date()
作为默认入参。直接调用 interval(date)
相当于使用该时距器的方法 interval.floor(date)
,两者不同在于后者 interval.floor()
必须传入参数。
时间边距计算器 interval
也是一个对象,有多种方法用于获取满足不同需求的 Date 对象:
-
方法
interval.floor(date)
用于计算出给定时间date
所属的时间间距的下界。对于时间尺度大于小时的 interval,返回的 Date 对象最后的时间点都是
12:00 AM
即凌晨零点,例如d3.timeDay.floor(date)
返回的是以date
日期当天的凌晨零点(当地时)为时间点的一个 Date 对象? 由于返回的 Date 对象是 interval 时间尺度的下界,所以
interval.floor(interval.floor(date) - 1)
返回的是上一个间隔的下界,例如d3.timeDay.floor(d3.timeDay.floor(date) - 1)
返回的是date
日期前一天的凌晨零点(当地时)⚠️ 比较日期是否相等时,应该先转变为数值
// 如果入参 date 已经是边距上的日期,即当天的凌晨零点,则函数返回 true function isDay(date) { return +d3.timeDay.floor(date) === +date; } 复制代码
-
方法
interval.ceil(date)
用于计算出给定时间date
所属的时间间距的上界。例如
d3.timeDay.ceil(date)
返回的是以date
日期后一天的凌晨零点(当地时)为时间点的一个 Date 对象 -
方法
interval.round(date)
类似于对时间date
进行「四舍五入」操作,根据入参date
与所属的时间间距的中点的距离,决定返回时间间距的上界还是下界。例如
d3.timeDay.round(date)
如果给定时间date
在中午或之前 12:00 PM,则返回上界,即返回的是以date
日期当天的凌晨零点(当地时)为时间点的一个 Date 对象;如果给定时间date
在中午之后 12:00 PM,则返回下界,即返回date
日期后一天的凌晨零点(当地时)为时间点的一个 Date 对象
interval 除了可以对时间进行修约,获取在特定时间尺度里的上界和下界,还可以对时间进行更多的操作:
-
方法
interval.offset(date[, step])
对入参的时间date
进行偏移处理,然后返回一个基于偏移后的时间点所创建的 Date 对象,不必是边界值。第一个参数
date
是一个 Date 对象,作为参照时间,偏移的起始点第二个(可选)参数
step
是一个整数(如果入参step
不是整数,在内部会先对其进行向下修约),用以设置偏移量(其单位是因 interval 的时间尺度而异的)。默认值是1
,可以是负值。例如
date
的时间点是 5:30 PM,则d3.timeDay.offset(date, 1)
返回一个 Date 对象,其时间点是明天的 5:30 PM? 如果
step
为0
则该方法返回一个时间点与date
相同的新的 Date 对象 -
方法
interval.range(start, stop[, step])
返回一个包含一系列 Date 对象的数组,这些 Date 对象在特定的时间范围内,且间隔都是相同的,而且这些 Date 对象是 interval 时间尺度下的下界值。第一个、第二个参数
start
(包含) 和stop
(不包括)用于设置时间范围第三个(可选)参数
step
是一个整数(如果入参step
不是整数,在内部会先对其进行向下修约),用于设置步长,即每距离多长的时间(其单位是因 interval 的时间尺度而异的)采集一个时间点,生成一个 Date 对象。step
默认值为1
例如
d3.timeDay.range(start, stop)
返回数组的第一个 Date 对象,其时间点是大于start
时间点(如果start
时间点正好是凌晨零点,则第一个时间点可以是start
),且是 interval 时间尺度下的下边界;而最后一个 Date 对象,其时间点是小于stop
时间点,也是 interval 时间尺度下的下边界? D3 还为不同的时间尺度下的时距器的方法
interval.range()
提供了相应的语法糖 :-
d3.timeMilliseconds(start, stop[, step])
和d3.utcMilliseconds(start, stop[, step])
时间尺度为毫秒级别 -
d3.timeSeconds(start, stop[, step])
和d3.utcSeconds(start, stop[, step])
时间尺度为秒级别 -
d3.timeMinutes(start, stop[, step])
和d3.utcMinutes(start, stop[, step])
时间尺度为分钟级别 -
d3.timeHours(start, stop[, step])
和d3.utcHours(start, stop[, step])
时间尺度为小时级别 -
d3.timeDays(start, stop[, step])
和d3.utcDays(start, stop[, step])
时间尺度为天级别 -
d3.timeWeeks(start, stop[, step])
和d3.utcWeeks(start, stop[, step])
时间尺度为周级别
此外对于按周计算间距的情况,由于可以按照不同起点来计算新的一周,所以提供了 7 种不同的方法:d3.timeSundays(start, stop[, step])
和d3.utcSundays(start, stop[, step])
时间尺度为周级别,且以周日为每一周的开始d3.timeMondays(start, stop[, step])
和d3.utcMondays(start, stop[, step])
以周一为每一周的开始d3.timeTuesdays(start, stop[, step])
和d3.utcTuesdays(start, stop[, step])
以周二为每一周的开始d3.timeWednesdays(start, stop[, step])
和d3.utcWednesdays(start, stop[, step])
以周三为每一周的开始d3.timeThursdays(start, stop[, step])
和d3.utcThursdays(start, stop[, step])
以周四为每一周的开始d3.timeFridays(start, stop[, step])
和d3.utcFridays(start, stop[, step])
以周五为每一周的开始d3.timeSaturdays(start, stop[, step])
和d3.utcSaturdays(start, stop[, step])
以周日为每一周的开始
-
d3.timeMonths(start, stop[, step])
和d3.utcMonths(start, stop[, step])
时间尺度为月级别 -
d3.timeYears(start, stop[, step])
和d3.utcYears(start, stop[, step])
时间尺度为年级别
以上方法中时间的名称为复数,这是为了表示这些方法的返回值是一个数组,含有多个 Date 对象
-
-
方法
interval.count(start, end)
返回在start
(不包含)和end
(包含)时间范围内,在 interval 所在的时间尺度下,间距的个数const start = '2021-04-08T15:20:05.123Z'; const end = '2021-04-15T15:20:05.123Z'; daysBetween = d3.timeDay.count(start, end); // 7 复制代码
? 开始和结束时间点是否包含在内,这一点与
interval.range()
有所不同,因为interval.count()
统计得到的是基于0
为索引的间距的数量