Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Calendar Matrix (date-fns, ES6) inspired by https://github.com/bclinkinbeard/calendar-matrix
import getYear from 'date-fns/get_year'
import getMonth from 'date-fns/get_month'
import addDays from 'date-fns/add_days'
import startOfWeek from 'date-fns/start_of_week'
const rows = range(6)
const cols = range(7)
/**
* Returns a two-dimensional array with calendar represented dates
*/
export default function ({ year, month, weekStartsOn } = {
year: getYear(new Date()),
month: getMonth(new Date()),
weekStartsOn: 0
}) {
const matrix = []
const date = new Date(year, month)
let curDate = startOfWeek(date, { weekStartsOn })
rows.forEach(row => {
const week = []
cols.forEach(col => {
week.push(curDate)
curDate = addDays(curDate, 1)
})
matrix.push(week)
})
return matrix
}
/**
* Returns an array range from 0 to n
*/
function range (n) {
return [...Array(n).keys()]
}
@olegomon

This comment has been minimized.

Copy link

olegomon commented Jul 25, 2018

@miljan-aleksic thanks for the gist! I found it very useful. Here is a slightly different version:

import {addDays, startOfWeek} from 'date-fns'

/**
 * Returns a two-dimensional array with calendar represented dates
 */
export function matrix(year: number, month: number, weekStartsOn: 0 | 1 | 2 | 3 | 4 | 5 | 6 = 1) {
    const startDate = startOfWeek(new Date(year, month, 1), {weekStartsOn});
    const rows = 6;
    const cols = 7;
    const length = rows * cols;
    return Array.from({length})
        // create a list of dates
        .map((_, index) => addDays(startDate, index).getDate())
        // fold the array into a matrix
        .reduce((matrix, current, index, days) => !(index % cols !== 0) ? [...matrix, days.slice(index, index + cols)] : matrix, []);
}

console.log(matrix(2018, 7, 1));
@retyui

This comment has been minimized.

Copy link

retyui commented Nov 8, 2018

My useful variant, without (rows, cols) it's calculate automate

// @flow

import eachDayOfInterval from 'date-fns/eachDayOfInterval';
import endOfISOWeek from 'date-fns/endOfISOWeek';
import endOfMonth from 'date-fns/endOfMonth';
import isSameMonth from 'date-fns/isSameMonth';
import startOfISOWeek from 'date-fns/startOfISOWeek';
import startOfMonth from 'date-fns/startOfMonth';
import eachWeekOfInterval from 'date-fns/eachWeekOfInterval';

type Options = {|
  year: number,
  mount: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11,
|};
type convertFn = (Date, { isSameMonth: boolean }) => any;

export const getMountMatrix = (
  { year, mount }: Options,
  convertDate: convertFn = date => date,
) => {
  const date = new Date(year, mount);

  const matrix = eachWeekOfInterval(
    {
      start: startOfMonth(date),
      end: endOfMonth(date),
    },
    { weekStartsOn: 1 },
  );

  return matrix.map(weekDay =>
    eachDayOfInterval({
      start: startOfISOWeek(weekDay),
      end: endOfISOWeek(weekDay),
    }).map(day =>
      convertDate(day, {
        isSameMonth: isSameMonth(date, day),
      }),
    ),
  );
};

test

// @flow
import format from 'date-fns/format';

import { getMountMatrix } from '@/features/calendarScene/Calendar/uitls';

test('should create december mount days grid', () => {
  expect(
    getMountMatrix(
      { year: 2018, mount: 11 },
      (day, { isSameMonth }) => (isSameMonth ? format(day, 'dd') : '--'),
    ),
  ).toEqual([
    ['--', '--', '--', '--', '--', '01', '02'],
    ['03', '04', '05', '06', '07', '08', '09'],
    ['10', '11', '12', '13', '14', '15', '16'],
    ['17', '18', '19', '20', '21', '22', '23'],
    ['24', '25', '26', '27', '28', '29', '30'],
    ['31', '--', '--', '--', '--', '--', '--'],
  ]);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.