d3-time
在可视化时间序列数据、分析时间模式或处理时间时,传统时间单位的不规则性很快就会显现出来。例如,在公历中,大多数月份有31天,但有些月份有28天、29天或30天;大多数年份有365天,但闰年有366天;而通过夏令时,大多数天有24小时,但有些天有23小时或25小时。更复杂的是,世界各地的夏令时规则各不相同。
🌐 When visualizing time series data, analyzing temporal patterns, or working with time in general, the irregularities of conventional time units quickly become apparent. In the Gregorian calendar, for example, most months have 31 days but some have 28, 29 or 30; most years have 365 days but leap years have 366; and with daylight saving, most days have 24 hours but some have 23 or 25. Adding to complexity, daylight saving conventions vary around the world.
由于这些时间上的特殊性,执行看似微不足道的任务可能会变得困难。例如,如果你想计算两个日期之间经过的天数,你不能简单地相减然后除以24小时(86,400,000毫秒):
🌐 As a result of these temporal peculiarities, it can be difficult to perform seemingly-trivial tasks. For example, if you want to compute the number of days that have passed between two dates, you can’t simply subtract and divide by 24 hours (86,400,000 ms):
const start = new Date(2015, 02, 01); // 2015-03-01T00:00
const end = new Date(2015, 03, 01); // 2015-04-01T00:00
const days = (end - start) / 864e5; // 30.958333333333332, oops! 🤯然而,你可以使用 d3.timeDay.count:
🌐 You can, however, use d3.timeDay.count:
d3.timeDay.count(start, end) // 31 😌day interval 是 d3-time 提供的几种时间间隔之一。每个间隔代表一个传统的时间单位——hours、weeks、months 等——并具有计算边界日期的方法。例如,d3.timeDay 计算对应日期的午夜时间(通常是当地时间的 12:00 AM)。除了 rounding 和 counting 外,间隔还可以用于生成边界日期数组。例如,要计算当前月份的每个星期天:
🌐 The day interval is one of several provided by d3-time. Each interval represents a conventional unit of time — hours, weeks, months, etc. — and has methods to calculate boundary dates. For example, d3.timeDay computes midnight (typically 12:00 AM local time) of the corresponding day. In addition to rounding and counting, intervals can also be used to generate arrays of boundary dates. For example, to compute each Sunday in the current month:
const start = d3.timeMonth.floor(new Date(2015, 0, 15)); // 2015-01-01T00:00
const stop = d3.timeMonth.ceil(new Date(2015, 0, 15)); // 2015-02-01T00:00
const weeks = d3.timeWeek.range(start, stop); // [2015-01-04T00:00, 2015-01-11T00:00, 2015-01-18T00:00, 2015-01-25T00:00]d3-time 模块并不实现自己的日历系统;它只是实现了一个便于在 ECMAScript Date 之上进行日历计算的 API。因此,它会忽略闰秒,并且只能与本地时区和协调世界时 (UTC) 一起使用。
🌐 The d3-time module does not implement its own calendaring system; it merely implements a convenient API for calendar math on top of ECMAScript Date. Thus, it ignores leap seconds and can only work with the local time zone and Coordinated Universal Time (UTC).
该模块被 D3 的时间刻度用于生成合理的刻度,被 D3 的时间格式使用,也可以直接用于执行诸如日历布局之类的操作。
🌐 This module is used by D3’s time scales to generate sensible ticks, by D3’s time format, and can also be used directly to do things like calendar layouts.
间隔(日期)
🌐 interval(date)
d3.utcMonday() // the latest preceding Monday, UTC time来源 · 相当于 interval.floor,但如果未指定 date,默认使用当前时间。例如,d3.timeYear(date) 和 d3.timeYear.floor(date) 是等价的。
interval.floor(date)
d3.utcMonday.floor(new Date()) // the latest preceding Monday, UTC time来源 · 返回一个新的日期,表示在 date 之前或等于 date 的最新间隔边界日期。例如,d3.timeDay.floor(date) 通常返回给定 date 的本地时间凌晨 12:00。
此方法是幂等的:如果指定的 date 已经向下取整到当前间隔,则返回具有相同时间的新日期。此外,返回的日期是关联间隔可表示的最小值,因此 interval.floor(interval.floor(date) - 1) 会返回前一个间隔边界日期。
🌐 This method is idempotent: if the specified date is already floored to the current interval, a new date with an identical time is returned. Furthermore, the returned date is the minimum expressible value of the associated interval, such that interval.floor(interval.floor(date) - 1) returns the preceding interval boundary date.
请注意,== 和 === 运算符不会与 Date 对象按值比较,因此你不能使用它们来判断指定的 日期 是否已经向下取整。相反,应先将其强制转换为数字,然后再进行比较:
🌐 Note that the == and === operators do not compare by value with Date objects, and thus you cannot use them to tell whether the specified date has already been floored. Instead, coerce to a number and then compare:
// Returns true if the specified date is a day boundary.
function isDay(date) {
return +d3.timeDay.floor(date) === +date;
}这比测试时间是否为凌晨 12:00 更可靠,因为在某些时区,由于夏令时,午夜可能不存在。
🌐 This is more reliable than testing whether the time is 12:00 AM, as in some time zones midnight may not exist due to daylight saving.
interval.round(date)
d3.utcMonday.round(new Date()) // the previous or following Monday, whichever is closer来源 · 返回一个新的日期,表示最接近 date 的间隔边界日期。例如,d3.timeDay.round(date) 通常会返回给定 date 当天的本地时间 12:00 AM(如果时间在中午之前),如果时间在中午之后,则返回第二天的 12:00 AM。
该方法是幂等的:如果指定的日期已经四舍五入到当前间隔,将返回一个时间相同的新日期。
🌐 This method is idempotent: if the specified date is already rounded to the current interval, a new date with an identical time is returned.
interval.ceil(date)
d3.utcMonday.ceil(new Date()) // the following Monday来源 · 返回一个新的日期,表示大于或等于 date 的最早间隔边界日期。例如,d3.timeDay.ceil(date) 通常返回给定 date 的次日的本地时间凌晨 12:00。
此方法是幂等的:如果指定的 date 已经向上取整到当前间隔,则返回具有相同时间的新日期。此外,返回的日期是关联间隔可表示的最大值,因此 interval.ceil(interval.ceil(date) + 1) 会返回下一个间隔边界日期。
🌐 This method is idempotent: if the specified date is already ceilinged to the current interval, a new date with an identical time is returned. Furthermore, the returned date is the maximum expressible value of the associated interval, such that interval.ceil(interval.ceil(date) + 1) returns the following interval boundary date.
interval.offset(date, step)
d3.utcDay.offset(new Date(), 1) // the same time tomorrow来源 · 返回一个新的日期,该日期等于 date 加上 step 个间隔。如果未指定 step,默认为 1。如果 step 为负数,则返回的日期会在指定的 date 之前;如果 step 为零,则返回指定 date 的副本;如果 step 不是整数,则会向下取整 (floored)。此方法不会将指定的 date 四舍五入到间隔。例如,如果 date 是今天下午 5:34,那么 d3.timeDay.offset(date, 1) 将返回明天下午 5:34(即使夏令时发生变化!)
interval.range(start, stop, step)
d3.utcDay.range(new Date("2014-01-01"), new Date("2015-01-01")) // every day in 2014来源 · 返回一个日期数组,表示从 start(包含)开始到 stop(不包含)之前的每个间隔边界。如果指定了 step,则将返回每第 step 个边界;例如,对于 d3.timeDay 间隔,step 为 2 将返回每隔一天的日期。如果 step 不是整数,则会被 向下取整。
返回数组中的第一个日期是大于或等于 start 的最早边界;随后的日期按照 step 间隔 偏移 并 向下取整。因此,两个重叠的范围可能是一致的。例如,这个范围包含奇数天:
🌐 The first date in the returned array is the earliest boundary after or equal to start; subsequent dates are offset by step intervals and floored. Thus, two overlapping ranges may be consistent. For example, this range contains odd days:
d3.timeDay.range(new Date(2015, 0, 1), new Date(2015, 0, 7), 2) // [2015-01-01T00:00, 2015-01-03T00:00, 2015-01-05T00:00]包含偶数天:
🌐 While this contains even days:
d3.timeDay.range(new Date(2015, 0, 2), new Date(2015, 0, 8), 2) // [2015-01-02T00:00, 2015-01-04T00:00, 2015-01-06T00:00]当指定了 step 时,为了使范围保持一致,请改用 interval.every。
🌐 To make ranges consistent when a step is specified, use interval.every instead.
为了方便,也提供了 interval.range 的别名,形式为相应区间的复数形式,例如 utcMondays。
🌐 For convenience, aliases for interval.range are also provided as plural forms of the corresponding interval, such as utcMondays.
interval.filter(test)
来源 · 返回一个新的区间,该区间是使用指定的测试函数过滤后的本区间子集。测试函数会接收一个日期,并且仅当指定日期应被视为区间的一部分时返回true。例如,要创建一个返回每个月的1日、11日、21日和31日(如果存在)的区间:
d3.timeDay.filter((d) => (d.getDate() - 1) % 10 === 0)返回的过滤间隔不支持 interval.count。另请参阅 interval.every。
🌐 The returned filtered interval does not support interval.count. See also interval.every.
interval.每(step)
🌐 interval.every(step)
d3.unixDay.every(3)来源 · 返回此区间的 筛选 视图,表示每个 step 的日期。step 的含义取决于此区间的父区间,如 field 函数所定义。例如, d3.timeMinute.every(15) 返回一个区间,表示每十五分钟一次,从整点开始: :00, :15, :30, :45, 等等。 请注意,对于某些区间,生成的日期可能不是均匀间隔的;d3.timeDay 的父区间是 d3.timeMonth,因此区间编号在每个月开始时会重置。如果 step 无效,则返回 null。如果 step 为一,则返回此区间。
此方法可以与 interval.range 一起使用,以确保两个重叠的范围保持一致。例如,这个范围包含奇数天:
🌐 This method can be used in conjunction with interval.range to ensure that two overlapping ranges are consistent. For example, this range contains odd days:
d3.timeDay.every(2).range(new Date(2015, 0, 1), new Date(2015, 0, 7)) // [2015-01-01T00:00, 2015-01-03T00:00, 2015-01-05T00:00]就像这个一样:
🌐 As does this one:
d3.timeDay.every(2).range(new Date(2015, 0, 2), new Date(2015, 0, 8)) // [2015-01-03T00:00, 2015-01-05T00:00, 2015-01-07T00:00]返回的过滤间隔不支持 interval.count。另请参阅 interval.filter。
🌐 The returned filtered interval does not support interval.count. See also interval.filter.
interval.count(start, end)
来源 · 返回start(不包括)之后和end(包括)之前的区间边界数量。请注意,这种行为与interval.range略有不同,因为它的目的是返回相对于指定start日期的指定end日期的基于零的数字。例如,要计算当前基于零的年份中的日数:
d3.timeDay.count(d3.timeYear(now), now) // 177同样,要计算当前以周日开始的周的从零开始的周数:
🌐 Likewise, to compute the current zero-based week-of-year number for weeks that start on Sunday:
d3.timeSunday.count(d3.timeYear(now), now) // 25timeInterval(floor, offset, count, field)
const utcDay = d3.timeInterval(
(date) => date.setUTCHours(0, 0, 0, 0), // floor
(date, step) => date.setUTCDate(date.getUTCDate() + step), // offset
(start, end) => (end - start) / 864e5, // count
(date) => date.getUTCDate() - 1 // field
);来源 · 根据指定的 floor 和 offset 函数以及可选的 count 函数构造一个新的自定义区间。
floor 函数接受一个日期作为参数,并将其向下舍入到最近的间隔边界。
🌐 The floor function takes a single date as an argument and rounds it down to the nearest interval boundary.
offset 函数以一个日期和一个整数步长作为参数,并将指定日期按指定数目的边界向前推进;步长可以为正、负或零。
🌐 The offset function takes a date and an integer step as arguments and advances the specified date by the specified number of boundaries; the step may be positive, negative or zero.
可选的 count 函数接受一个开始日期和一个结束日期,这些日期已经向当前间隔下取整,并返回开始日期(不包括)和结束日期(包括)之间的边界数量。如果未指定 count 函数,则返回的间隔不会暴露 interval.count 或 interval.every 方法。注意:由于内部优化,指定的 count 函数不得在其他时间间隔上调用 interval.count。
🌐 The optional count function takes a start date and an end date, already floored to the current interval, and returns the number of boundaries between the start (exclusive) and end (inclusive). If a count function is not specified, the returned interval does not expose interval.count or interval.every methods. Note: due to an internal optimization, the specified count function must not invoke interval.count on other time intervals.
可选的 field 函数接受一个日期,该日期已被向下取整到当前时间间隔,并返回指定日期的字段值,对应于该日期(不包括该日期本身)与最近的上级边界之间的边界数量。例如,对于 d3.timeDay 间隔,它返回自本月开始以来的天数。如果未指定 field 函数,则默认为从 1970 年 1 月 1 日 UTC 的 UNIX 纪元开始计算间隔边界的数量。field 函数定义了 interval.every 的行为。
🌐 The optional field function takes a date, already floored to the current interval, and returns the field value of the specified date, corresponding to the number of boundaries between this date (exclusive) and the latest previous parent boundary. For example, for the d3.timeDay interval, this returns the number of days since the start of the month. If a field function is not specified, it defaults to counting the number of interval boundaries since the UNIX epoch of January 1, 1970 UTC. The field function defines the behavior of interval.every.
时间毫秒
🌐 timeMillisecond
来源 · 本地时间的毫秒;最短可用的时间单位。
时间秒
🌐 timeSecond
来源 · 当地时间的秒数(例如,01:23:45.0000 AM);1,000 毫秒。
时间分钟
🌐 timeMinute
来源 · 当地时间的分钟(例如,01:02:00 AM);60秒。请注意,ECMAScript 忽略闰秒。
时间小时
🌐 timeHour
来源 · 当地时间小时(例如,01:00 AM);60 分钟。请注意,由于夏令时调整,将当地时间提前一小时可能会返回同一小时或跳过一小时。
时间天
🌐 timeDay
来源 · 当地时间的天数(例如,2012年2月7日凌晨12:00);通常为24小时。由于夏令时,当地时间的天数可能在23至25小时之间。d3.unixDay 类似于 d3.utcDay,只是它从 UNIX 纪元(1970年1月1日)起计算天数,这样 interval.every 返回的是均匀间隔的日期,而不是根据每月的天数变化。
时间周
🌐 timeWeek
来源 · d3.timeSunday 的别名;7天,通常为168小时。由于夏令时,当地时间的一周可能在167到169小时之间。
时间星期日
🌐 timeSunday
来源 · 基于本地时间的周日为起始的周(例如,2012年2月5日凌晨12:00)。
时间星期一
🌐 timeMonday
来源 · 基于本地时间的周一起始周(例如,2012年2月6日 0:00)。
时间星期二
🌐 timeTuesday
来源 · 基于本地时间的星期二起始周(例如,2012年2月7日 0:00)。
时间星期三
🌐 timeWednesday
来源 · 基于本地时间的周三起始周(例如,2012年2月8日 0:00)。
时间星期四
🌐 timeThursday
来源 · 基于本地时间的周四起始周(例如,2012年2月9日 0:00)。
时间星期五
🌐 timeFriday
来源 · 基于本地时间的星期五周(例如,2012年2月10日午夜12:00)。
时间星期六
🌐 timeSaturday
来源 · 基于本地时间的周六起始周(例如,2012年2月11日凌晨12:00)。
时间月份
🌐 timeMonth
来源 · 当地时间的月份(例如,2012年2月1日凌晨12:00);天数范围为28到31天。
时间年份
🌐 timeYear
来源 · 当地时间年份(例如,2012年1月1日凌晨12:00);范围从365天到366天。
utc毫秒
🌐 utcMillisecond
来源 · UTC 时间的毫秒;可用的最短时间单位。
utcSecond
来源 · UTC 时间的秒数(例如,01:23:45.0000 AM);1,000 毫秒。
utcMinute
来源 · UTC 时间的分钟(例如,上午 01:02:00);60 秒。请注意,ECMAScript 忽略闰秒。
UTC小时
🌐 utcHour
来源 · 使用协调世界时 (UTC) 表示的时间(例如,凌晨01:00);60分钟。
utcDay
来源 · 以 UTC 时间计天数(例如,2012 年 2 月 7 日 0:00);24 小时。
utc周
🌐 utcWeek
来源 · d3.timeSunday 的别名;7天和168小时。
utc星期日
🌐 utcSunday
来源 · 基于星期日的UTC时间周(例如,2012年2月5日 12:00 AM)。
UTC星期一
🌐 utcMonday
来源 · 基于星期一的UTC时间周(例如,2012年2月6日凌晨12:00)。
UTC星期二
🌐 utcTuesday
来源 · 基于星期二的UTC时间周(例如,2012年2月7日凌晨12:00)。
utc星期三
🌐 utcWednesday
来源 · 基于星期三的UTC时间周(例如,2012年2月8日 00:00)。
utc星期四
🌐 utcThursday
来源 · 基于星期四的UTC时间周(例如,2012年2月9日 00:00)。
utc星期五
🌐 utcFriday
来源 · 基于星期五的UTC时间周(例如,2012年2月10日 00:00)。
utc星期六
🌐 utcSaturday
来源 · 基于星期六的UTC时间周(例如,2012年2月11日凌晨12:00)。
utcMonth
来源 · UTC 时间的月份(例如,2012 年 2 月 1 日凌晨 12:00);范围为 28 到 31 天。
UTC 年
🌐 utcYear
来源 · UTC 时间的年份(例如,2012 年 1 月 1 日 12:00 AM);范围为 365 到 366 天。
unixDay
类似 d3.utcDay,只是它从 UNIX 纪元(1970 年 1 月 1 日)开始计算天数,这样 interval.every 返回的是均匀间隔的日期,而不是根据月份的天数变化。
🌐 Like d3.utcDay, 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.
timeMilliseconds(start, stop, step)
d3.timeMillisecond.range 的别名。
🌐 Alias for d3.timeMillisecond.range.
timeSeconds(start, stop, step)
d3.timeSecond.range 的别名。
🌐 Alias for d3.timeSecond.range.
timeMinutes(start, stop, step)
d3.timeMinute.range 的别名。
🌐 Alias for d3.timeMinute.range.
timeHours(start, stop, step)
d3.timeHour.range 的别名。
🌐 Alias for d3.timeHour.range.
timeDays(start, stop, step)
d3.timeDay.range 的别名。
🌐 Alias for d3.timeDay.range.
timeWeeks(start, stop, step)
d3.timeWeek.range 的别名。
🌐 Alias for d3.timeWeek.range.
timeSundays(start, stop, step)
d3.timeSunday.range 的别名。
🌐 Alias for d3.timeSunday.range.
timeMondays(start, stop, step)
d3.timeMonday.range 的别名。
🌐 Alias for d3.timeMonday.range.
timeTuesdays(start, stop, step)
d3.timeTuesday.range 的别名。
🌐 Alias for d3.timeTuesday.range.
timeWednesdays(start, stop, step)
d3.timeWednesday.range 的别名。
🌐 Alias for d3.timeWednesday.range.
timeThursdays(start, stop, step)
d3.timeThursday.range 的别名。
🌐 Alias for d3.timeThursday.range.
timeFridays(start, stop, step)
d3.timeFriday.range 的别名。
🌐 Alias for d3.timeFriday.range.
timeSaturdays(start, stop, step)
d3.timeSaturday.range 的别名。
🌐 Alias for d3.timeSaturday.range.
timeMonths(start, stop, step)
d3.timeMonth.range 的别名。
🌐 Alias for d3.timeMonth.range.
timeYears(start, stop, step)
d3.timeYear.range 的别名。
🌐 Alias for d3.timeYear.range.
utcMilliseconds(start, stop, step)
d3.utcMillisecond.range 的别名。
🌐 Alias for d3.utcMillisecond.range.
utcSeconds(start, stop, step)
d3.utcSecond.range 的别名。
🌐 Alias for d3.utcSecond.range.
utcMinutes(start, stop, step)
d3.utcMinute.range 的别名。
🌐 Alias for d3.utcMinute.range.
utcHours(start, stop, step)
d3.utcHour.range 的别名。
🌐 Alias for d3.utcHour.range.
utcDays(start, stop, step)
utcWeeks(start, stop, step)
d3.utcWeek.range 的别名。
🌐 Alias for d3.utcWeek.range.
utcSundays(start, stop, step)
d3.utcSunday.range 的别名。
🌐 Alias for d3.utcSunday.range.
utcMondays(start, stop, step)
d3.utcMonday.range 的别名。
🌐 Alias for d3.utcMonday.range.
utcTuesdays(start, stop, step)
d3.utcTuesday.range 的别名。
🌐 Alias for d3.utcTuesday.range.
utcWednesdays(start, stop, step)
d3.utcWednesday.range 的别名。
🌐 Alias for d3.utcWednesday.range.
utcThursdays(start, stop, step)
d3.utcThursday.range 的别名。
🌐 Alias for d3.utcThursday.range.
utcFridays(start, stop, step)
d3.utcFriday.range 的别名。
🌐 Alias for d3.utcFriday.range.
utcSaturdays(start, stop, step)
d3.utcSaturday.range 的别名。
🌐 Alias for d3.utcSaturday.range.
utcMonths(start, stop, step)
d3.utcMonth.range 的别名。
🌐 Alias for d3.utcMonth.range.
utcYears(start, stop, step)
d3.utcYear.range 的别名。
🌐 Alias for d3.utcYear.range.
timeTicks(start, stop, count)
来源 · 相当于 d3.utcTicks,但使用本地时间。
timeTickInterval(start, stop, count)
来源 · 返回在给定相同参数的情况下 d3.timeTicks 将使用的时间间隔。
utcTicks(start, stop, count)
来源 · 返回一个数组,包含大约 count 个在 start 和 stop(包含)之间按规则间隔的日期。如果 stop 在 start 之前,日期将按逆时间顺序返回;否则日期将按时间顺序返回。以下 UTC 时间间隔将被考虑:
- 1 秒
- 5 秒
- 15 秒
- 30 秒
- 1 分钟
- 5 分钟
- 15 分钟
- 30 分钟
- 1 小时
- 3 小时
- 6 小时
- 12 小时
- 1 天
- 2 天
- 1 周
- 1 个月
- 3 个月
- 1 年
毫秒的倍数(用于小范围)和年份的倍数(用于大范围)也会被考虑,遵循 d3.ticks 的规则。使用产生的日期数量最接近 count 的间隔。例如:
🌐 Multiples of milliseconds (for small ranges) and years (for large ranges) are also considered, following the rules of d3.ticks. The interval producing the number of dates that is closest to count is used. For example:
const start = new Date("1970-03-01");
const stop = new Date("1996-03-19");
const count = 4;
const ticks = d3.utcTicks(start, stop, count); // [1975-01-01, 1980-01-01, 1985-01-01, 1990-01-01, 1995-01-01]如果 count 是一个时间间隔,这个函数的行为类似于 interval.range,只是 start 和 stop 都是包含的,并且如果 stop 在 start 之前,它可能会以逆时间顺序返回日期。
🌐 If count is a time interval, this function behaves similarly to interval.range except that both start and stop are inclusive and it may return dates in reverse chronological order if stop is before start.
utcTickInterval(start, stop, count)
来源 · 返回在相同参数下 d3.utcTicks 会使用的时间间隔。如果没有关联的间隔,例如当 start 或 stop 无效时,返回 null。
const start = new Date("1970-03-01");
const stop = new Date("1996-03-19");
const count = 4;
const interval = d3.utcTickInterval(start, stop, count); // d3.utcYear.every(5)