moment-range
- 安装
- Node / NPM 环境
- 浏览器环境
- 低版本浏览器与 IE11 兼容
- 使用示例
- 创建日期范围
- rangeFromInterval
- parseZoneRange
- rangeFromISOString
- 属性访问
- 范围查询
- 判断相邻
- 计算中心时间
- 判断包含
- 判断归属
- 判断重叠
- 获取交集
- 判断是否为范围对象
- 范围操作
- 合并范围
- 深克隆范围 -
- 对齐时间区间
- 减去范围
- 范围迭代
- 按时间单位迭代
- 按指定范围迭代
- 按时间单位反向迭代
- 按指定范围反向迭代
- 范围比较
- 判断相等
- 计算时间差
- 格式转换
toDate转换为日期数组toString转换为字符串valueOf获取时间戳差
Node / NPM 环境 通过 npm 安装: npm install --save moment-range
ES6 语法引入:
js
import Moment from 'moment';
import { extendMoment } from 'moment-range';
const moment = extendMoment(Moment);
TypeScript 语法引入:
js
import * as Moment from 'moment';
import { extendMoment } from 'moment-range';
const moment = extendMoment(Moment);
CommonJS 语法引入:
js
const Moment = require('moment');
const MomentRange = require('moment-range');
const moment = MomentRange.extendMoment(Moment);
浏览器环境
直接通过脚本标签引入:
html
预览
<script src="moment.js"></script>
<script src="moment-range.js"></script>
初始化扩展:
js
window['moment-range'].extendMoment(moment);
使用示例
创建日期范围
创建基础日期范围:
js
const start = new Date(2012, 0, 15);
const end = new Date(2012, 4, 23);
const range = moment.range(start, end);
也可通过 moment 实例创建:
js
const start = moment('2011-04-15', 'YYYY-MM-DD');
const end = moment('2011-11-27', 'YYYY-MM-DD');
const range = moment.range(start, end);
传入数组形式的起止时间也支持:
js
const dates = [moment('2011-04-15', 'YYYY-MM-DD'), moment('2011-11-27', 'YYYY-MM-DD')];
const range = moment.range(dates);
通过 ISO 8601 时间间隔字符串创建:
js
const timeInterval = '2015-01-17T09:50:04+00:00/2015-04-17T08:29:55+00:00';
const range = moment.range(timeInterval);
基于指定时间,创建其到某时间单位结束的范围:
js
const date = moment('2011-04-15', 'YYYY-MM-DD');
const range = date.range('month'); // 2011-04-15 至 2011-04-30
创建开区间范围(起始 / 结束为最早 / 最晚时间):
js
const rangeUntil = moment.range(null, '2011-05-05'); // 最早时间 至 2011-05-05
const rangeFrom = moment.range('2011-03-05'); // 2011-03-05 至 最晚时间
const rangeAllTime = moment.range(); // 最早时间 至 最晚时间
注意:除 0 外,任何假值都会被视为缺失的日期,从而创建开区间范围。
提示:若未指定时间戳,Date 和 moment 实例都会默认使用 00:00:000。如果需要让范围包含结束日期的所有时间戳,创建 Date 实例时请使用 .setHours(23,59,59,999),创建 moment 实例时请使用 .endOf('day')。
rangeFromInterval
根据指定的时间单位、数量和基准日期创建范围,count 支持正负值,若未传入基准日期则默认使用当前时间:
js
const interval = 'month';
const count = 4;
const date = moment('2017-07-20');
const range1 = moment.rangeFromInterval(interval, count, date); // 2017-07-20 至 2017-11-20
const range2 = moment.rangeFromInterval('month', -2, date); // 2017-05-20 至 2017-07-20
注意:基准日期可传入 Date 实例、字符串或 Moment 实例;当 count 为负值时,传入的基准日期会作为范围的结束时间。
parseZoneRange
4.0.0 版本中已废弃:为遵循命名规范,该方法已被 rangeFromISOString 替代。
rangeFromISOString
将 ISO 8601 时间间隔字符串转换为日期范围,同时通过 moment.parseZone 保留时区信息:
js
const interval = '2015-01-17T09:50:00+03:00/2015-04-17T08:29:55-04:00';
const range = moment.rangeFromISOString(interval);
range.toString(); // '2015-01-17T09:50:00+03:00/2015-04-17T08:29:55-04:00'
属性访问
可直接访问范围的起始和结束 moment 实例:
js
const start = new Date(2012, 0, 15);
const end = new Date(2012, 4, 23);
const range = moment.range(start, end);
range.start // 起始 moment 实例
range.end // 结束 moment 实例
范围查询
以下示例均基于以下 moment 实例:
js
const a = moment('2016-03-10');
const b = moment('2016-03-15');
const c = moment('2016-03-29');
const d = moment('2016-04-01');
判断相邻
检查两个范围是否相接但不重叠:
js
const range1 = moment.range(a, b);
const range2 = moment.range(b, c);
const range3 = moment.range(c, d);
range1.adjacent(range2) // true
range1.adjacent(range3) // false
计算中心时间
计算当前范围的中心时间戳:
js
const start = new Date(2011, 2, 5);
const end = new Date(2011, 3, 5);
const range = moment.range(start, end);
range.center(); // 1300622400000
判断包含
检查范围是否包含指定的日期 /moment 实例,默认包含起始和结束日期:
js
const range = moment.range(a, c);
range.contains(a); // true
range.contains(b); // true
range.contains(c); // true
range.contains(d); // false
可通过 excludeStart 和 excludeEnd 配置,控制是否排除起始 / 结束日期:
js
const range = moment.range(a, c);
range.contains(a); // true
range.contains(a, { excludeStart: true }); // false
range.contains(c); // true
range.contains(c, { excludeEnd: true }); // false
4.0.0 版本中已废弃:原 exclusive 配置用于控制是否排除起止日期:提示:设置 { excludeStart: true, excludeEnd: true } 可实现与原 exclusive: true 相同的效果。
js
range.contains(c); // true
range.contains(c, { exclusive: false }); // true
range.contains(c, { exclusive: true }); // false
判断归属
检查指定的 moment 实例是否位于当前范围内:
js
const range = moment.range(a, c);
b.within(range); // true
判断重叠
检查两个范围是否存在重叠:
js
const range1 = moment.range(a, c);
const range2 = moment.range(b, d);
range1.overlaps(range2); // true
可配置是否将相邻范围视为重叠:
js
const range1 = moment.range(a, b);
const range2 = moment.range(b, c);
range1.overlaps(range2) // false
range1.overlaps(range2, { adjacent: false }) // false
range1.overlaps(range2, { adjacent: true }) // true
获取交集
获取两个范围的交集范围,若无交集则返回 null:
js
const range1 = moment.range(a, c);
const range2 = moment.range(b, d);
range1.intersect(range2); // moment.range(b, c)
判断是否为范围对象
检查指定对象是否为 moment-range 范围实例:
js
moment.isRange(range); // true
moment.isRange(IamNotRange); // false
范围操作
合并范围
合并重叠或相邻的两个范围,若无重叠 / 相邻则返回 null:
js
const range1 = moment.range(a, c);
const range2 = moment.range(b, d);
range1.add(range2); // moment.range(a, d)
const range3 = moment.range(a, b);
const range4 = moment.range(c, d);
range3.add(range4); // null
可配置是否合并相邻范围:
js
const range1 = moment.range(a, b);
const range2 = moment.range(b, c);
range1.add(range2); // null
range1.add(range2, { adjacent: false }); // null
range1.add(range2, { adjacent: true }); // moment.range(a, c)
深克隆范围
对当前范围进行深克隆,修改克隆后的范围不会影响原范围:
js
const range1 = moment.range(a, d);
const range2 = range1.clone();
range2.start.add(2, 'days');
range1.start.toDate().getTime() === range2.start.toDate().getTime() // false
对齐时间区间
将范围的起始和结束时间对齐到指定的时间单位,补全不完整的时间区间:
js
const start = moment('2018-01-25 17:05:33');
const end = moment('2018-01-28 06:10:00');
const range1 = moment.range(start, end);
const range2 = range1.snapTo('day'); // 2018-01-25T00:00:00 -> 2018-01-28T23:59:59
range1.diff('days'); // 2
range2.diff('days'); // 3
减去范围
从当前范围中减去指定的子范围,返回剩余的范围数组(若无剩余则返回 [null]):
js
const range_ab = moment.range(a, b);
const range_bc = moment.range(b, c);
const range_cd = moment.range(c, d);
const range_ad = moment.range(a, d);
range_ad.subtract(range_bc); // [moment.range(a, b), moment.range(c, d)]
range_ac.subtract(range_bc); // [moment.range(a, b)]
range_ab.subtract(range_cd); // [moment.range(a, b)]
range_bc.subtract(range_bd); // [null]
范围迭代
所有迭代方法都会返回一个可迭代对象,可便捷、高效地按指定规则遍历范围。
按时间单位迭代
按指定的时间单位遍历范围,支持 moment.js add 方法的所有单位:'years' | 'quarters' | 'months' | 'weeks' | 'days' | 'hours' | 'minutes' | 'seconds' | 'milliseconds'
js
const range = moment.range('2010-01-01', '2015-01-01');
// 按月份遍历
for (let month of range.by('month')) {
month.format('YYYY-MM-DD');
}
// 按年份遍历并转为数组
const years = Array.from(range.by('year'));
years.length == 6 // true
years.map(m => m.format('YYYY')) // ['2010', '2011', '2012', '2013', '2014', '2015']
设置 excludeEnd: true 可排除范围的最后一个时间片段:
js
const range = moment.range('2018-01-01 00:00', '2018-01-01 05:30');
const hours = Array.from(range.by('hour', { excludeEnd: true }));
hours.length == 5 // true
hours.map(m => m.format('HH:mm')) // ['00:00', '01:00', '02:00', '03:00', '04:00']
支持通过 step 设置迭代步长,默认步长为 1:
js
const start = new Date(2012, 2, 2);
const end = new Date(2012, 2, 6);
const range1 = moment.range(start, end);
// 步长为2,包含结束时间
let acc = Array.from(range1.by('day', { step: 2 }));
acc.map(m => m.format('DD')) // ['02', '04', '06']
// 步长为2,排除结束时间
acc = Array.from(range1.by('day', { excludeEnd: true, step: 2 }));
acc.map(m => m.format('DD')) // ['02', '04']
对于不完整的时间区间,可结合 snapTo() 方法补全后再迭代:
js
const start = moment("2017-01-01T13:30:00");
const end = moment("2017-01-05T01:45:12");
const r1 = moment.range(start, end);
const r2 = r1.snapTo('day'); // 补全为完整的日期区间
Array.from(r1.by('days')).map(m => m.format('DD')); // ['01', '02', '03', '04']
Array.from(r2.by('days')).map(m => m.format('DD')); // ['01', '02', '03', '04', '05']
4.0.0 版本中已废弃:原 exclusive 配置用于控制是否排除结束时间;提示:设置 { excludeEnd: true } 可实现与原 exclusive: true 相同的效果。
按指定范围迭代
按另一个范围的时长遍历当前范围:
js
const start = new Date(2012, 2, 1); // 1号
const two = new Date(2012, 2, 2); // 2号
const end = new Date(2012, 2, 5); // 5号
const range1 = moment.range(start, end);
const range2 = moment.range(start, two); // 时长为1天的范围
基础迭代:
js
const acc = Array.from(range1.byRange(range2));
acc.length == 5 // true
acc.map(m => m.format('DD')) // ['01','02','03','04','05']
排除最后一个时间片段:
js
const acc = Array.from(range1.byRange(range2, { excludeEnd: true }));
acc.length == 4 // true
acc.map(m => m.format('DD')) // ['01','02','03','04']
设置迭代步长:
js
let acc = Array.from(range1.byRange(range2, { step: 2 }));
acc.map(m => m.format('DD')) // ['01', '03', '05']
acc = Array.from(range1.byRange(range2, { excludeEnd: true, step: 2 }));
acc.map(m => m.format('DD')) // ['01', '03']
4.0.0 版本中已废弃:原 exclusive 配置用于控制是否排除结束时间;提示:设置 { excludeEnd: true } 可实现与原 exclusive: true 相同的效果。
按时间单位反向迭代
按指定的时间单位倒序遍历范围:
js
const range = moment.range('2012-01-01', '2015-01-01');
const acc = Array.from(range.reverseBy('years'));
acc.map(m => m.format('YYYY')) // ['2015', '2014', '2013', '2012']
设置 excludeStart: true 可排除范围的起始时间片段:
js
const range = moment.range('2012-01-01', '2015-01-01');
const acc = Array.from(range.reverseBy('years', { excludeStart: true }));
acc.map(m => m.format('YYYY')) // ['2015', '2014', '2013']
设置反向迭代步长:
js
const start = new Date(2012, 2, 2);
const end = new Date(2012, 2, 6);
const range1 = moment.range(start, end);
// 步长为2,包含起始时间
let acc = Array.from(range1.reverseBy('day', { step: 2 }));
acc.map(m => m.format('DD')) // ['06', '04', '02']
// 步长为2,排除起始时间
acc = Array.from(range1.reverseBy('day', { excludeStart: true, step: 2 }));
acc.map(m => m.format('DD')) // ['06', '04']
4.0.0 版本中已废弃:原 exclusive 配置用于控制是否排除起始时间;提示:设置 { excludeStart: true } 可实现与原 exclusive: true 相同的效果。
按指定范围反向迭代
按另一个范围的时长倒序遍历当前范围:
js
const start = new Date(2012, 2, 1);
const two = new Date(2012, 2, 2);
const end = new Date(2012, 2, 5);
const range1 = moment.range(start, end);
const range2 = moment.range(start, two); // 时长为1天的范围
基础反向迭代:
js
const acc = Array.from(range1.reverseByRange(range2));
acc.length == 5 // true
acc.map(m => m.format('DD')) // ['05', '04', '03', '02', '01']
排除起始时间片段:
js
const acc = Array.from(range1.reverseByRange(range2, { excludeStart: true }));
acc.length == 4 // true
acc.map(m => m.format('DD')) // ['05', '04', '03', '02']
设置反向迭代步长:
js
let acc = Array.from(range1.reverseByRange(range2, { step: 2 }));
acc.map(m => m.format('DD')) // ['05', '03', '01']
acc = Array.from(range1.reverseByRange(range2, { excludeStart: true, step: 2 }));
acc.map(m => m.format('DD')) // ['05', '03']
4.0.0 版本中已废弃:原 exclusive 配置用于控制是否排除起始时间;提示:设置 { excludeStart: true } 可实现与原 exclusive: true 相同的效果。
范围比较
可通过简单的数学运算比较范围长度或计算总时长 / 时长差:
js
const range1 = moment.range(new Date(2011, 2, 5), new Date(2011, 3, 15));
const range2 = moment.range(new Date(1995, 0, 1), new Date(1995, 12, 25));
range2 > range1 // true,比较范围时长
range1 + range2 // 两个范围的总时长(毫秒)
Math.abs(range1 - range2); // 两个范围的时长差(毫秒)
判断相等
检查两个范围是否完全相同(起始和结束时间均一致):
js
const range1 = moment.range(new Date(2011, 2, 5), new Date(2011, 3, 15));
const range2 = moment.range(new Date(2011, 2, 5), new Date(2011, 3, 15));
const range3 = moment.range(new Date(2011, 3, 5), new Date(2011, 6, 15));
range1.isSame(range2); // true
range2.isSame(range3); // false
range1.isEqual(range2); // true(isEqual 是 isSame 的别名)
range2.isEqual(range3); // false
计算时间差
计算范围的总时长,支持 moment.js add 方法的所有时间单位,默认返回毫秒数:
js
const start = new Date(2011, 2, 5);
const end = new Date(2011, 5, 5);
const range = moment.range(start, end);
range.diff('months'); // 3
range.diff('days'); // 92
range.diff(); // 7945200000(默认返回毫秒)
可配置是否保留小数,默认会像 moment.js 一样截断小数取整:
js
const d1 = new Date(Date.UTC(2011, 4, 1));
const d2 = new Date(Date.UTC(2011, 4, 5, 12));
const range = moment.range(d1, d2);
range.diff('days') // 4(默认截断)
range.diff('days', false) // 4(显式截断)
range.diff('days', true) // 4.75(保留小数)
#duration 是 #diff 的别名,二者可互换使用。
格式转换
toDate 转换为日期数组
将日期范围转换为包含起止 Date 实例的数组:
js
const start = new Date(2011, 2, 5);
const end = new Date(2011, 5, 5);
const range = moment.range(start, end);
range.toDate(); // [new Date(2011, 2, 5), new Date(2011, 5, 5)]
toString 转换为字符串
将日期范围转换为ISO 8601 时间间隔格式的字符串:
js
const start = '2015-01-17T09:50:04+00:00';
const end = '2015-04-17T08:29:55+00:00';
const range = moment.range(moment.utc(start), moment.utc(end));
range.toString() // '2015-01-17T09:50:04+00:00/2015-04-17T08:29:55+00:00'
valueOf 获取时间戳差
返回范围结束时间与起始时间的毫秒差(与直接调用 diff() 效果一致):
js
const start = new Date(2011, 2, 5);
const end = new Date(2011, 5, 5);
const range = moment.range(start, end);
range.valueOf(); // 7945200000