changed 7 years ago
Linked with GitHub

#yyphp-quiz No.2: 月間カレンダーの表を作ろう

<?php
/**
 * 月間カレンダーの表を生成して返す
 * @param int $first その月の1日の曜日番号。日=0、月=1、火=2、水=3、木=4、金=5、土=6
 * @param int $days その月の日数。30、31、28もしくは29
 * @return array 下記のような月間カレンダーを配列で返す
 * - 週ごとにひとつの配列にする。
 * - 週の配列は日曜日から土曜日の7要素が必ずある。
 * - 週の配列の中身は日付。
 * - 週の配列の中で中で前月や次月の日付になる日は0で埋める。
 * 例:
 * $calendar = getCalendarTable(1, 30);
 * この場合、$calendarの値は次のようになる:
 * [
 *   [ 0,  1,  2,  3,  4,  5,  6],
 *   [ 7,  8,  9, 10, 11, 12, 13],
 *   [14, 15, 16, 17, 18, 19, 20],
 *   [21, 22, 23, 24, 25, 26, 27],
 *   [28, 29, 30,  0,  0,  0,  0],
 * ]
 */
function getCalendarTable(int $first, int $days): array
{
    // todo: 日付関係の関数、クラス、ライブラリを使わずに実装してみて
}

// テストコード
assert(
    getCalendarTable(0, 28) === [
        [ 1,  2,  3,  4,  5,  6,  7],
        [ 8,  9, 10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19, 20, 21],
        [22, 23, 24, 25, 26, 27, 28],
    ],
    '1日が日曜日で28日間ある月'
);
assert(
    getCalendarTable(0, 31) === [
        [ 1,  2,  3,  4,  5,  6,  7],
        [ 8,  9, 10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19, 20, 21],
        [22, 23, 24, 25, 26, 27, 28],
        [29, 30, 31,  0,  0,  0,  0],
    ],
    '1日が日曜日で31日間ある月'
);
assert(
    getCalendarTable(1, 30) === [
        [ 0,  1,  2,  3,  4,  5,  6],
        [ 7,  8,  9, 10, 11, 12, 13],
        [14, 15, 16, 17, 18, 19, 20],
        [21, 22, 23, 24, 25, 26, 27],
        [28, 29, 30,  0,  0,  0,  0],
    ],
    '1日が月曜日で30日間ある月'
);
assert(
    getCalendarTable(4, 30) === [
        [ 0,  0,  0,  0,  1,  2,  3],
        [ 4,  5,  6,  7,  8,  9, 10],
        [11, 12, 13, 14, 15, 16, 17],
        [18, 19, 20, 21, 22, 23, 24],
        [25, 26, 27, 28, 29, 30,  0],
    ],
    '1日が木曜日で30日間ある月'
);
assert(
    getCalendarTable(4, 31) === [
        [ 0,  0,  0,  0,  1,  2,  3],
        [ 4,  5,  6,  7,  8,  9, 10],
        [11, 12, 13, 14, 15, 16, 17],
        [18, 19, 20, 21, 22, 23, 24],
        [25, 26, 27, 28, 29, 30, 31],
    ],
    '1日が木曜日で31日間ある月'
);
assert(
    getCalendarTable(5, 31) === [
        [ 0,  0,  0,  0,  0,  1,  2],
        [ 3,  4,  5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14, 15, 16],
        [17, 18, 19, 20, 21, 22, 23],
        [24, 25, 26, 27, 28, 29, 30],
        [31,  0,  0,  0,  0,  0,  0],
    ],
    '1日が金曜日で31日ある月'
);

解答例

解答例を開く

解答例1

function getCalendarTable(int $first, int $days): array
{
    $calendar = [];
    $numberOfWeeks = ceil(($first + $days) / 7);
    $date = 1 - $first;
    for ($y = 0; $y < $numberOfWeeks; $y++) {
        for ($x = 0; $x < 7; $x++, $date++) {
            $calendar[$y][$x] = 1 <= $date && $date <= $days ? $date : 0;
        }
    }
    return $calendar;
}

解答例2

function getCalendarTable(int $first, int $days): array
{
	return array_chunk(
		array_merge(
			array_fill(0, $first, 0),
			range(1, $days),
			array_fill(0, (7 - (($first + $days) % 7)) % 7, 0)
		),
		7
	);
}

解答例3

function getCalendarTable(int $first, int $days): array
{
    return array_chunk(
        array_map(
            function (int $date) use ($days): int {
                return 1 <= $date && $date <= $days ? $date : 0;
            },
            range(1 - $first, (ceil(($first + $days) / 7) * 7) - $first)
        )
        , 7
    );
}

解答例4

function getCalendarTable(int $first, int $days): array
{
    $lastMonthDaysCount = $first;
    $nextMonthDaysCount = ($first + $days) % 7 === 0 ? 0 : 7 - (($first + $days) % 7);

    $lastMonthDays = [];
    for ($i = 1; $i <= $lastMonthDaysCount; $i++) {
        $lastMonthDays[] = 0;
    }
    $thisMonthDays = [];
    for ($day = 1; $day <= $days; $day++) {
        $thisMonthDays[] = $day;
    }
    $nextMonthDays = [];
    for ($i = 1; $i <= $nextMonthDaysCount; $i++) {
        $nextMonthDays[] = 0;
    }

    $flatCalendar = [];
    foreach ($lastMonthDays as $day) $flatCalendar[] = $day;
    foreach ($thisMonthDays as $day) $flatCalendar[] = $day;
    foreach ($nextMonthDays as $day) $flatCalendar[] = $day;

    $calendar = [];
    $week = [];
    for ($i = 0; $i < count($flatCalendar); $i++) {
        $week[] = $flatCalendar[$i];
        if (($i + 1) % 7 === 0) {
            $calendar[] = $week;
            $week = [];
        }
    }

    return $calendar;
}
Select a repo