5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Dateオブジェクトだけでカレンダーを作る

Last updated at Posted at 2022-10-19

概要

既存のカレンダーライブラリはたくさんありますが、少々柔軟性に欠けるのでイチから自分で作ろうと考えました。今回はJavaScriptの標準組み込みオブジェクトである「Dateオブジェクト」のみを使ってカレンダー生成アルゴリズムを構築していきます。(マイブームのReactで開発を進めます。)

完成したサンプルサイトはこちら↓↓

アルゴリズム

年,月を引数にとり、その月の日にちをカレンダーに見立てた二次元配列で返す関数を作ります。
以下は2022年10月の配列です。

calendar:number[][]
[
    [25, 26, 27, 28, 29, 30, 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,  2,  3,  4,  5]
]

この配列をmapでループ処理にかけてカレンダーを表示します。

Dateオブジェクトの使い方

JavaScript の Date オブジェクトは、単一の瞬間の時刻をプラットフォームに依存しない形式で表します。 Date オブジェクトは協定世界時 (UTC) の 1970 年 1 月 1 日からの経過ミリ秒数を表す Number の値を含んでいます。

Date - JavaScript | MDN

任意の時刻の取得

2022年10月1日の情報を取得します。

const day = new Date(2022, 10, 1);

引数を渡さなければ現在時刻を取得できます。

const day = new Date();

使用するメソッド

const today = new Date();

const year  = today.getFullYear()   //年を取得
const month = today.getMonth()      //月を取得
const date  = today.getDate()       //日を取得
const day   = today.getDay()        //曜日を取得

getDay()メソッドは日曜〜土曜に対応して0~6を返します。

手順

Date オブジェクトを駆使してカレンダーの配列を生成します。

各種宣言

Make_calendar.ts
let calendar:number[][] = []                //カレンダー
const first_day = new Date(year, month, 1); //任意の月の1日を取得
let week:number[] = []                      //週生成用

第一週を生成

任意の月の第一週を生成してカレンダーにpushします。
Date関数の第3引数に0を渡すと前の月の最終日を取得できます。

Make_calendar.ts
for(let i = first_day.getDay(); i < 7; i++){
    week.push(i - first_day.getDay() + 1)
}

const end_last_month = new Date(first_day.getFullYear(), first_day.getMonth(), 0)
for(let i = 0; i < first_day.getDay(); i++){
    week.unshift( end_last_month.getDate() - i)
}

calendar.push(week)

最終週を生成

Make_calendar.ts
const last_day = new Date(first_day.getFullYear(), first_day.getMonth() + 1, 0)
let last_week:number[] = []

for(let i = 0; i <= last_day.getDay(); i++){
    last_week.unshift(last_day.getDate() - i)
}

if(last_day.getDay() !== 6){
    const begin_next_month = new Date(first_day.getFullYear(), first_day.getMonth() + 1, 1)
    for(let i = 0; i < 7 - begin_next_month.getDay(); i++){
        last_week.push( begin_next_month.getDate() + i)
    }
}

中間週を生成

中間週を生成してカレンダーにpushしていきます。最終週に到達したら先ほど生成したlast_week[]をpushしましょう。

Make_calendar.ts
for(let i = 0; i < 5; i++){
    week = []
    for(let j = 0; j < 7 ; j++){
        week.push((8 - first_day.getDay() + j) + 7 * i)
    }
    if(week[0] !== last_week[0]){
        calendar.push(week)
    }else{
        calendar.push(last_week)
        break
    }
}

関数全体

Make_calendar.ts
const Make_calendar = (year:number, month:number):number[][] => {
    let calendar:number[][] = []                //カレンダー
    const first_day = new Date(year, month, 1); //任意の月の1日を取得
    let week:number[] = []                      //週生成用

    // first week========
    for(let i = first_day.getDay(); i < 7; i++){
        week.push(i - first_day.getDay() + 1)
    }

    const end_last_month = new Date(first_day.getFullYear(), first_day.getMonth(), 0)
    for(let i = 0; i < first_day.getDay(); i++){
        week.unshift( end_last_month.getDate() - i)
    }
    calendar.push(week)

    // last week============
    const last_day = new Date(first_day.getFullYear(), first_day.getMonth() + 1, 0)
    let last_week:number[] = []

    for(let i = 0; i <= last_day.getDay(); i++){
        last_week.unshift(last_day.getDate() - i)
    }

    if(last_day.getDay() !== 6){
        const begin_next_month = new Date(first_day.getFullYear(), first_day.getMonth() + 1, 1)
        for(let i = 0; i < 7 - begin_next_month.getDay(); i++){
            last_week.push( begin_next_month.getDate() + i)
        }
    }

    // middle week===========
    for(let i = 0; i < 5; i++){
        week = []
        for(let j = 0; j < 7 ; j++){
            week.push((8 - first_day.getDay() + j) + 7 * i)
        }
        if(week[0] !== last_week[0]){
            calendar.push(week)
        }else{
            calendar.push(last_week)
            break
        }
    }
    // ======================

    return calendar
}

コンポーネント設計

React × Typescript で進めます。

const Square = (props):JSX.Element => {
    return(
        <div>
            {props.date}
        </div>
    )
}

const Column = (props):JSX.Element => {
    return(
        <div>
            {props.week.map((date) => <Square date = {date} />)}
        </div>
    )
}

const Calendar = (props):JSX.Element => {

    let calendar:number[][] = Make_calendar(props.year, props.month)

    return(
        <div>
            {calendar.map((week) => <Column week = {week} />)}
        </div> 
    )
}

const Home = ():JSX.Element => {
    const today = new Date();
    const [year, setYear] = useState<number>(Number(today.getFullYear()))
    const [month, setMonth] = useState<number>(Number(today.getMonth()))
    
    return(
        <div>
            <Calendar 
                year = {year}
                month = {month}
            />
        </div>
    )
}

完成

完成したサンプルサイトはこちら↓↓

まとめ

Dateオブジェクトだけでカレンダーを作ってみました。カレンダー配列生成マシンはそこそこ便利なのでぜひ参考にしてください。

参考

5
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?