按周分组日期 JavaScript

18

我有波斯日期的数组,希望按周分组日期。 例如,我有以下数组:

[
    "1396-10-11 09:07:21",
    "1396-10-10 10:03:51",
    "1396-10-07 02:07:02",
    "1396-11-27 08:02:45",
    "1396-11-19 01:02:32",
    "1396-12-01 22:13:21",
    "1396-02-12 09:07:21",
    "1396-05-18 04:02:29",
    "1396-05-21 14:01:42",
    "1396-07-11 01:16:29"
]

我希望按周分组日期。

我写了下面的代码,但效果不好:

Array.prototype.groupBy = function(prop) {
  return this.reduce(function(groups, item) {
    var val = item[prop];
    groups[val] = groups[val] || [];
    groups[val].push(item);
    return groups;
  }, {});
}

const formatted = dates.map(elem => {
  return { 
    numberOfWeek: moment(elem.date, 'jYYYY-jMM-jDD').startOf('jMonth').jWeek(),
    date: moment(elem.date, 'jYYYY-jMM-jDD').format('jYYYY-jMM-jDD'), 
    score: elem.score 
  };
});

你能展示一下你目前尝试过的吗?另外,对于那个数组,期望的输出是什么? - user3483203
你应该从解析日期开始。一旦你证明了自己能够做到这一点,这里有一个相当冗长的线程,可以确定一天所在的年份周数:https://dev59.com/dW025IYBdhLWcg3wQDlb对于分组,你可以使用一个以周数为键的对象。这些只是我如何处理它的想法。像@chris说的那样,请展示你尝试过什么,我们可以从那里开始。 - wholevinski
@chris 我的代码已添加。 - Omid Nikrah
这里有一个答案可以获取任何日期的年份和周数:在 JavaScript 中像 PHP 一样获取每年的周。但是,您仍需要将输入字符串正确解析为日期。 - RobG
3个回答

24

您可以使用moment().week()来获取一年中的周数,然后按周数分组。这里是一个可用的示例,我使用array.reduce创建了一个新对象,其中包含按周数分组的日期:

const dates = [
  "1396-10-11 09:07:21",
  "1396-10-10 10:03:51",
  "1396-10-07 02:07:02",
  "1396-11-27 08:02:45",
  "1396-11-19 01:02:32",
  "1396-12-01 22:13:21",
  "1396-02-12 09:07:21",
  "1396-05-18 04:02:29",
  "1396-05-21 14:01:42",
  "1396-07-11 01:16:29"
];

const groups = dates.reduce((acc, date) => {

  // create a composed key: 'year-week' 
  const yearWeek = `${moment(date).year()}-${moment(date).week()}`;
  
  // add this key as a property to the result object
  if (!acc[yearWeek]) {
    acc[yearWeek] = [];
  }
  
  // push the current date that belongs to the year-week calculated befor
  acc[yearWeek].push(date);

  return acc;

}, {});

console.log(groups);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>


1
谢谢@YouneL,但如果我有一个四年前的日期,会发生什么?! - Omid Nikrah
2
你能详细解释一下如何将周和年份结合起来吗? - Omid Nikrah
谢谢@YouneL,但为什么“1396-11-27 08:02:45”和“1396-12-01 22:13:21”这两个日期被归为同一组? - Omid Nikrah
在你的代码输出中,“1396-11-27 08:02:45”和“1396-12-01 22:13:21”日期属于同一组。 - Omid Nikrah
1
是的,这是因为它们属于同一年的第49周,有什么问题吗?它们相差4天。 - YouneL
显示剩余5条评论

11

使用Lodash实现相同效果的另一种简单方法如下:

const groupBy = require('lodash/groupBy');
const moment = require('moment');
const data = [
   "1396-10-11 09:07:21",
   "1396-10-10 10:03:51",
   "1396-10-07 02:07:02",
   "1396-11-27 08:02:45",
   "1396-11-19 01:02:32",
   "1396-12-01 22:13:21",
   "1396-02-12 09:07:21",
   "1396-05-18 04:02:29",
   "1396-05-21 14:01:42",
   "1396-07-11 01:16:29"
];

groupBy(data, (dt) => moment(dt).week());

结果如下:

{ 
  '7': [ '1396-02-12 09:07:21' ],
  '21': [ '1396-05-18 04:02:29', '1396-05-21 14:01:42' ],
  '29': [ '1396-07-11 01:16:29' ],
  '41': [ '1396-10-07 02:07:02' ],
  '42': [ '1396-10-11 09:07:21', '1396-10-10 10:03:51' ],
  '47': [ '1396-11-19 01:02:32' ],
  '49': [ '1396-11-27 08:02:45', '1396-12-01 22:13:21' ] 
}

这似乎是一个不错的选择。 - Him Hah

0
如果你正在寻找一个像我一样的纯粹的原生JavaScript解决方案,我成功地将被接受的答案改编成了使用纯原生代码来替代moment.js。我还不得不在另一个问题中使用了这篇帖子中的PersianDate类的建议。
对于公历,你只需将PersianDate替换为默认的Date类即可。

class PersianDate extends Date {
    constructor(...args) {
        super(...args);
    }

    toLocaleDateString = () => super.toLocaleDateString('fa-IR-u-nu-latn');
    getParts = () => this.toLocaleDateString().split("/")
    getDay = () => super.getDay() === 6 ? 0 : super.getDay() + 1
    getDate = () => this.getParts()[2];
    getMonth = () => this.getParts()[1] - 1;
    getYear = () => this.getParts()[0];
    getMonthName = () => this.toLocaleDateString("fa-IR", { month: 'long' });
    getDayName = () => this.toLocaleDateString("fa-IR", { weekday: 'long' });
}

const dates = [
  "1396-10-11 09:07:21",
  "1396-10-10 10:03:51",
  "1396-10-07 02:07:02",
  "1396-11-27 08:02:45",
  "1396-11-19 01:02:32",
  "1396-12-01 22:13:21",
  "1396-02-12 09:07:21",
  "1396-05-18 04:02:29",
  "1396-05-21 14:01:42",
  "1396-07-11 01:16:29"
];

const groups = dates.reduce((acc, curr) => {
  const date = new PersianDate(curr);
  const startOfYearDate = new PersianDate(date.getFullYear(), 0, 1);
  const weekOfYear = Math.ceil(Math.floor((date.getTime() - startOfYearDate.getTime()) /
    (24 * 60 * 60 * 1000)) / 7);

  // create a composed key: 'year-week' 
  const yearWeek = `${date.getFullYear()}-${weekOfYear}`;
  
  // add this key as a property to the result object
  if (!acc[yearWeek]) {
    acc[yearWeek] = [];
  }
  
  // push the current date that belongs to the year-week calculated befor
  acc[yearWeek].push(curr);

  return acc;

}, {});

console.log(groups);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接