如何按天、周、月对具有时间戳属性的对象进行分组?
Posted
技术标签:
【中文标题】如何按天、周、月对具有时间戳属性的对象进行分组?【英文标题】:How to group objects with timestamps properties by day, week, month? 【发布时间】:2014-01-05 00:14:15 【问题描述】:在 nodejs 应用程序中,我有一个事件对象数组,格式如下:
eventsArray = [ id: 1, date: 1387271989749 , id:2, date: 1387271989760, ... ]
eventsArray 具有可变长度的 n 个元素,假设我选择时间参考为巴黎时间,我希望能够按天、周或月对元素进行分组:
groupedByDay =
2012: ... ,
2013:
dayN : [id: a0, date: b0, id: a1, date: b1, id: a2, date: b2 ],
dayN+1: [id: a3, date: b3, id: a4, date: b4, id: a5, date: b5 ],
...
,
2014: ...
groupedByWeek =
2012: ...
2013:
weekN: [id: a0, date: b0, id: a1, date: b1, id: a2, date: b2 ],
weekN+1: [id: a3, date: b3],
....
,
2014: ...
groupedByMonth =
2012: ... ,
2013:
monthN: [ id: a0, date: b0 , id: a1, b1, id: a2, b2, id: a3, b3 ],
monthN+1: [ id: a4, date: b4 , id: a5, b5, id: a6, b6],
...
,
2014: ...
在处理 unix 时间戳方面几乎没有经验,我想知道如何做到这一点,或者是否有一个 npm 模块可以让这更容易。
【问题讨论】:
您是否尝试过使用Date
提取日期然后进行相应排序?
另一个选项是moment.js,这使它变得微不足道:moment(1387271989749).week()
。
groupedbyday and rest has 2012,2013... 是否需要先按年份分组?
@user568109: 不一定,可能只是第 N 天、第 N+1 天等,其中 N 是自 1970 年以来的天数
与@punund 相同,只是使用 Momentjs。这是一个改变生活的人。
【参考方案1】:
我会做这样的事情:
var item,
i = 0,
groups = ,
year, day;
while (item = eventsArray[i++])
item = new Date(item.date);
year = item.getFullYear();
day = item.getDate();
groups[year] || (groups[year] = ); // exists OR create
groups[year][day] || (groups[year][day] = []); // exists OR create []
groups[year][day].push(item);
此版本仅按天对项目进行分组,但您可以轻松地在数周和数月内获得相同的结果,用适当的函数替换 item.getDate()
:
getWeek()
: https://***.com/a/6117889/1636522.
getMonth()
: MDN doc(从零开始!)。
【讨论】:
【参考方案2】:这是我的解决方案。请记住,日、周和月是相对于起源而言的,因为纪元:
let event = [ id: 1, date: 1387271989749 , id:2, date: 1387271989760 ];
function groupday(value, index, array)
let byday=;
let d = new Date(value['date']);
d = Math.floor(d.getTime()/(1000*60*60*24));
byday[d]=byday[d]||[];
byday[d].push(value);
return byday
function groupweek(value, index, array)
let byweek=;
let d = new Date(value['date']);
d = Math.floor(d.getTime()/(1000*60*60*24*7));
byweek[d]=byweek[d]||[];
byweek[d].push(value);
return byweek
function groupmonth(value, index, array)
let bymonth=;
d = new Date(value['date']);
d = (d.getFullYear()-1970)*12 + d.getMonth();
bymonth[d]=bymonth[d]||[];
bymonth[d].push(value);
return bymonth
console.log('grouped by day', event.map(groupday));
console.log('grouped by week',event.map(groupweek));
console.log('grouped by month',event.map(groupmonth));
注意:对象是分组的,但日、周和月的键是数字的。只有年份的键是人类可读的。
【讨论】:
我很困惑,value['date']
和 d.getTime()
本质上不一样吗?也就是说,您可以简单地使用Math.floor(value.date / 1000 * 60 * 60 * 24)
请为 op 格式化您的代码,您在变量之前错过了 let/const。【参考方案3】:
这样的东西可能很接近您的需要。
javascript Date 有 getFullYear
、getDate
和 getMonth
函数 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date),您也可以查看这篇 SO 帖子 (Convert a Unix timestamp to time in JavaScript)。
这里(排列)的基本方法是按年、然后按日和月建立哈希。
此代码不做周。你是指一年中的哪一周还是哪一个月?我怀疑您可以编写自己的日期方法来获取该数字,然后按照下面的模式获取您想要的所有数据。您可以从 JS (getDay
) 获取星期几。我不确定你想如何计算周,但这种方法可能会有所帮助。
我在浏览器中运行了这段代码(在初始化了一组虚拟事件数组之后),但我怀疑它可以很好地转换为节点。
如果您愿意的话,您应该为函数正确命名,并且可以将所有方法移动到对象原型中。
希望对你有帮助
var groupEvents = function(eventsArray)
this.dates = eventsArray;
this.arranged = ;
this.monthKey = function(month)
return 'month' + month;
;
this.dayKey = function(month)
return 'day' + month;
;
this.getYear = function(year)
this.arranged[year] = this.arranged[year] ||
return this.arranged[year]
;
this.getMonth = function(month, year)
var y = this.getYear(year);
var k = this.monthKey(month);
y[k] = y[k] || [];
return y[k]
;
this.getDate = function(day, year)
var y = this.getYear(year);
var k = this.dayKey(day);
y[k] = y[k] || [];
return y[k]
;
this.addToMonth = function(info, month, year)
var y = this.getMonth(month,year);
y.push(info);
;
this.addToDay = function(info, day, year)
var y = this.getDate(day,year);
y.push(info);
;
this.breakdownDate = function(date)
return
month: date.getMonth(),
day: date.getDate(),
year: date.getFullYear()
;
/** grab a date, break it up into day, month year
and then categorize it */
this.arrange = function()
if(!this.arranged.length)
var ii = 0;
var nn = this.dates.length;
for(; ii < nn; ++ii )
var el = this.dates[ii];
var date = new Date(el.date * 1000);
var parsed = this.breakdownDate(date);
this.addToMonth(el, parsed.month, parsed.year);
this.addToDay(el, parsed.month, parsed.year);
return this.arranged;
;
return this;
;
if(eventArray.length)
var events = new groupEvents(eventArray);
var arranged = events.arrange();
console.log(arranged);
【讨论】:
【参考方案4】:扩展@user568109 的答案,这是正确且投票赞成的,这是一个可以完成所有工作的函数,为了演示,使用更大的数组:
// Group by time period - By 'day' | 'week' | 'month' | 'year'
// ------------------------------------------------------------
var groupByTimePeriod = function (obj, timestamp, period)
var objPeriod = ;
var oneDay = 24 * 60 * 60 * 1000; // hours * minutes * seconds * milliseconds
for (var i = 0; i < obj.length; i++)
var d = new Date(obj[i][timestamp] * 1000);
if (period == 'day')
d = Math.floor(d.getTime() / oneDay);
else if (period == 'week')
d = Math.floor(d.getTime() / (oneDay * 7));
else if (period == 'month')
d = (d.getFullYear() - 1970) * 12 + d.getMonth();
else if (period == 'year')
d = d.getFullYear();
else
console.log('groupByTimePeriod: You have to set a period! day | week | month | year');
// define object key
objPeriod[d] = objPeriod[d] || [];
objPeriod[d].push(obj[i]);
return objPeriod;
;
var eventsArray = [ id: 1, date: 1317906596 , id: 2, date: 1317908605 , id: 3, date: 1317909229 , id: 4, date: 1317909478 , id: 5, date: 1317909832 , id: 6, date: 1317979141 , id: 7, date: 1317979232 , id: 8, date: 1317986965 , id: 9, date: 1318582119 , id: 10, date: 1318595862 , id: 11, date: 1318849982 , id: 12, date: 1318855706 , id: 13, date: 1318929018 , id: 14, date: 1318933265 , id: 15, date: 1318940511 , id: 16, date: 1318945096 , id: 17, date: 1319017541 , id: 18, date: 1319527136 , id: 19, date: 1318582119 , id: 20, date: 1318595862 , id: 21, date: 1318582119 , id: 22, date: 1318595862 , id: 23, date: 1319713399 , id: 24, date: 1320053428 , id: 25, date: 1320333481 , id: 26, date: 1320832755 , id: 27, date: 1321012378 , id: 28, date: 1321280993 , id: 29, date: 1321347659 , id: 30, date: 1321350476 , id: 31, date: 1321369307 , id: 32, date: 1321369614 , id: 33, date: 1321610123 , id: 34, date: 1321613205 , id: 35, date: 1321617250 , id: 36, date: 1321626603 , id: 37, date: 1321865808 , id: 38, date: 1321876609 , id: 39, date: 1321877598 , id: 40, date: 1321877832 , id: 41, date: 1321953322 , id: 42, date: 1322061969 , id: 43, date: 1322142603 , id: 44, date: 1322211686 , id: 45, date: 1322213793 , id: 46, date: 1322214569 , id: 47, date: 1322482817 , id: 48, date: 1322663742 , id: 49, date: 1322664267 , id: 50, date: 1322747231 , id: 51, date: 1322819964 , id: 52, date: 1323358224 , id: 53, date: 1323681272 , id: 54, date: 1323695093 , id: 55, date: 1323696589 , id: 56, date: 1323763763 , id: 57, date: 1322819964 , id: 58, date: 1323681272 , id: 59, date: 1323851164 , id: 60, date: 1323853123 , id: 61, date: 1323854271 , id: 62, date: 1323858072 , id: 63, date: 1325690573 , id: 64, date: 1325751893 , id: 65, date: 1325760204 , id: 66, date: 1325769098 , id: 67, date: 1325769981 , id: 68, date: 1325771632 , id: 69, date: 1325776473 , id: 70, date: 1325837346 , id: 71, date: 1326110199 , id: 72, date: 1326793097 , id: 73, date: 1326878182 , id: 74, date: 1326881341 , id: 75, date: 1326975873 , id: 76, date: 1326985667 , id: 77, date: 1327047585 , id: 78, date: 1327062945 , id: 79, date: 1327063660 , id: 80, date: 1327322844 , id: 81, date: 1327326904 , id: 82, date: 1327329215 , id: 83, date: 1327397042 , id: 84, date: 1327399839 , id: 85, date: 1327401818 , id: 86, date: 1327407161 , id: 87, date: 1327419420 , id: 88, date: 1327570243 , id: 89, date: 1327578536 , id: 90, date: 1327584554 , id: 91, date: 1327914616 , id: 92, date: 1327917019 , id: 93, date: 1327931685 , id: 94, date: 1327933025 , id: 95, date: 1327934772 , id: 96, date: 1327947074 , id: 97, date: 1328626734 , id: 98, date: 1328626734 , id: 99, date: 1330070074 , id: 100, date: 1330073135 , id: 101, date: 1330073259 , id: 102, date: 1330332445 , id: 103, date: 1330351925 , id: 104, date: 1330420928 , id: 105, date: 1330423209 , id: 106, date: 1330437337 , id: 107, date: 1330439446 ];
var objPeriodDay = groupByTimePeriod(eventsArray, 'date', 'day');
var objPeriodWeek = groupByTimePeriod(eventsArray, 'date', 'week');
var objPeriodMonth = groupByTimePeriod(eventsArray, 'date', 'month');
var objPeriodYear = groupByTimePeriod(eventsArray, 'date', 'year');
console.log(objPeriodDay);
console.log(objPeriodWeek);
console.log(objPeriodMonth);
console.log(objPeriodYear);
这里是a fiddle to go with it(您必须打开控制台才能看到输出)。
正如您将在小提琴中看到的,4 个对象的键如下:
objPeriodDay
: 自 1970 年 1 月 1 日以来的日期
objPeriodWeek
: 相对于 1970 年 1 月 1 日第一周的周数
objPeriodMonth
: 自 1970 年 1 月 1 日以来的月份数
objPeriodYear
:年份
请注意,所有这四种变体都会为您提供唯一键。例如,月份将为您提供“Dec 2011”(以自 1970 年 1 月 1 日以来的月份形式),而不仅仅是“Dec”。
【讨论】:
【参考方案5】:以上所有解决方案都是庞大的纯 JS 解决方案。如果您可以使用几个库,那么 lodash 和 moment 可以一起使用以形成一个简单的单行:
ES6
let groupedResults = _.groupBy(results, (result) => moment(result['Date'], 'DD/MM/YYYY').startOf('isoWeek'));
旧版 JS
var groupedResults = _.groupBy(results, function (result)
return moment(result['Date'], 'DD/MM/YYYY').startOf('isoWeek');
);
这将产生一个以一周开始为键的数组,例如Mon Jul 25 2016 00:00:00 GMT+0100
。我相信您可以研究如何扩展它以获得数月、数年等。
回复:@SaintScott 的 cmets
在 cmets 中提到,这并没有直接回答问题,因为原始使用 UTC 时间戳而不是格式化日期。在这种情况下,您应该使用不带第二个参数的moment()
:
moment(1387271989749).startOf('isoWeek');
或者如果使用 UNIX 时间戳,如下所示:
moment.unix(yourTimestamp).startOf('isoWeek');
...虽然这开始远离问题,并且更多地进入 Moment 文档,如果您想使用这种方法,我建议您阅读。
【讨论】:
这是迄今为止最好的答案 不对,只能用格式字符串构造字符串日期。喜欢moment("12-25-1995", "MM-DD-YYYY")
。
@SaintScott 我知道,result['Date']
是一个类似于 '25/12/1995' 的字符串。你以为是什么?
最佳答案,简单有效。谢谢!
为什么是isoWeek
?【参考方案6】:
另一个使用dayjs库的实现
var dayjs = require('dayjs')
function groupTimesBy(theList, unit = 'day', timeParamName = 'create_time')
var toReturn = ;
for(let listItem of theList)
const paramName = dayjs.unix(listItem[timeParamName]).startOf(unit).unix();
if(toReturn[paramName] == null)
toReturn[paramName] = [];
toReturn[paramName].push(listItem);
return toReturn;
let list = ['time':1609104570, 'time':1609104570];
let byDay = groupTimesBy(list, 'day', 'time');
let byWeek = groupTimesBy(list, 'week', 'time');
let byMonth = groupTimesBy(list, 'month', 'time');
let byYear = groupTimesBy(list, 'year', 'time');
【讨论】:
以上是关于如何按天、周、月对具有时间戳属性的对象进行分组?的主要内容,如果未能解决你的问题,请参考以下文章