rex0220 計算式プラグイン テーブルで月カレンダー(週単位)

[計算式プラグイン]()を使って、テーブルに月カレンダーを表示してみました。

# 概要

横並びプラグイン確認用に、カレンダーと画像を並べた例です。
テーブルのカレンダーを、計算式プラグインで計算しています。

計算式は、最初に日～土の項目毎に計算する仕組みでしたが、
テーブルにまとめてデータをセットする方法に変更して、パフォーマンス改善を行いました。
覚書として両方の計算式を載せておきます。

![2024-07-16_11h06_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/21b3fb0d-aa76-0886-6b9a-9af98f41bd45.png)

# アプリの設定

![2024-07-16_11h11_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/1af5e363-2b38-0a39-d541-6b811d8c5931.png)

# 計算式プラグイン設定

最初は、日～土の項目毎に日にち計算で、設定しました。
ただ日数分の計算が行われるので、テーブルにまとめて値をセットする方式に変更しました。

## 改善前：テーブル内項目に計算式を設定

月の日数以上に、計算が必要

- テーブルに、必要な行数を設定
- 日～土の項目毎に日にち計算

![2024-07-16_16h58_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/2fdda09a-716e-cc50-b772-06a8540338bf.png)

```改善前.js
OPTION: 循環参照を許可

// タイトル SINGLE_LINE_TEXT
DATE_FORMAT(開始日,"YYYY年M月")

// 開始日 DATE (editable)
DATE_STARTOF(開始日,"month")

// カレンダー:テーブル1 SUBTABLE
LET(
  sDate, DATE_STARTOF(開始日, "month"),
  eDate, DATE_ENDOF(sDate, "month"),
  fDow, DATE_FORMAT(sDate, "e"),
  tDays, DATE_DIFF(sDate, eDate, "day") +fDow + 1,
  CEIL(tDays / 7)
)

// テーブル1.日:日1 NUMBER
LET(
  fDow,DATE_FORMAT(開始日, "e"),
  eMonth,DATE_ENDOF(開始日,"month","D"),
  rno,ROWNO(テーブル1),
  day,1+rno*7-fDow,
  IF(day>0&&day<=eMonth,day)
)

// テーブル1.月:月1 NUMBER
LET(
  fDow,DATE_FORMAT(開始日, "e"),
  eMonth,DATE_ENDOF(開始日,"month","D"),
  rno,ROWNO(テーブル1),
  day,2+rno*7-fDow,
  IF(day>0&&day<=eMonth,day)
)

// テーブル1.火:火1 NUMBER
LET(
  fDow,DATE_FORMAT(開始日, "e"),
  eMonth,DATE_ENDOF(開始日,"month","D"),
  rno,ROWNO(テーブル1),
  day,3+rno*7-fDow,
  IF(day>0&&day<=eMonth,day)
)

// テーブル1.水:水1 NUMBER
LET(
  fDow,DATE_FORMAT(開始日, "e"),
  eMonth,DATE_ENDOF(開始日,"month","D"),
  rno,ROWNO(テーブル1),
  day,4+rno*7-fDow,
  IF(day>0&&day<=eMonth,day)
)

// テーブル1.木:木1 NUMBER
LET(
  fDow,DATE_FORMAT(開始日, "e"),
  eMonth,DATE_ENDOF(開始日,"month","D"),
  rno,ROWNO(テーブル1),
  day,5+rno*7-fDow,
  IF(day>0&&day<=eMonth,day)
)

// テーブル1.金:金1 NUMBER
LET(
  fDow,DATE_FORMAT(開始日, "e"),
  eMonth,DATE_ENDOF(開始日,"month","D"),
  rno,ROWNO(テーブル1),
  day,6+rno*7-fDow,
  IF(day>0&&day<=eMonth,day)
)

// テーブル1.土:土1 NUMBER
LET(
  fDow,DATE_FORMAT(開始日, "e"),
  eMonth,DATE_ENDOF(開始日,"month","D"),
  rno,ROWNO(テーブル1),
  day,7+rno*7-fDow,
  IF(day>0&&day<=eMonth,day)
)
```

## 改善後1：テーブルデータをまとめてセット

月カレンダーの csv データを作成して、テーブルにまとめてセット

- テーブル行単位に、日にちを組み立てていく感じ
- 配列から CSV に変換して、テーブルにセット

![2024-07-16_17h07_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/431c0c5e-12f2-4dc1-74d5-3aab142857c4.png)

```改善後1.js
OPTION: 循環参照を許可

// タイトル SINGLE_LINE_TEXT
DATE_FORMAT(開始日,"YYYY年M月")

// 開始日 DATE (editable)
DATE_STARTOF(開始日,"month")

// カレンダー:テーブル1 SUBTABLE
LET(
  sDate, DATE_STARTOF(開始日, "month"),
  eDate, DATE_ENDOF(sDate, "month"),
  mDays, DATE_ENDOF(sDate, "month","D"),
  fDow, DATE_FORMAT(sDate, "e"),
  tDays, DATE_DIFF(sDate, eDate, "day") +fDow + 1,
  line, CEIL(tDays / 7),
  csv, JOIN(ARRAY_FOR(line,x,
    JOIN(ARRAY_FOR(7,y,
      LET(
        day,y+x*7-fDow+1,
        IF(day>0&&day<=mDays,day)
      )
    ),",")
  ),NEWLINE()),
  CSV_TVAL("日1,月1,火1,水1,木1,金1,土1"&NEWLINE()&csv)
)

// テーブル1.日:日1 NUMBER

// テーブル1.月:月1 NUMBER

// テーブル1.火:火1 NUMBER

// テーブル1.水:水1 NUMBER

// テーブル1.木:木1 NUMBER

// テーブル1.金:金1 NUMBER

// テーブル1.土:土1 NUMBER
```

# 改善後2：ループ処理を削減

単純に csv を組み立てるだけということで、2重のループ処理を減らしてみました。
ステップが短い分、わかりやすいかも。

- 月の初めの曜日までの空文字の配列、月の日数分の日にちの配列をまとめて
- 配列を 7個単位に改行、それ以外はカンマで配列を連結
- csv をCSV_TVAL 関数でテーブルにセット

```改善後2.js
// カレンダー:テーブル1 SUBTABLE
LET(
  sDate, DATE_STARTOF(開始日, "month"), // 月初日
  days, DATE_ENDOF(sDate, "month", "D"), // 月の日数
  fDay, DATE_FORMAT(sDate, "e"), // 初曜
  arr, ARRAY(ARRAY_FOR(fDay, x, ""), ARRAY_FOR(days, x, x+1)), // 配列作成
  csv, JOIN(ARRAY_MAP(arr, x, idx, x & IF((idx+1)%7=0, NEWLINE(), ",")),""), // CSV変換
  CSV_TVAL("日1,月1,火1,水1,木1,金1,土1"&NEWLINE()&csv) // テーブル設定
)
```