Scalaで当月の日をすべて表示する

# はじめに

Scala でカレンダーを実装したいと思って調べていたところ、JAVAでカレンダーのClassがあるようなので、こちらで値が取得できるか試してみます。

https://docs.oracle.com/javase/jp/8/docs/api/java/util/Calendar.html

# 実装

## 現在の年を表示する

まずは、最小構成のコードで、現在のカレンダーの年を表示させる。

```scala
package mvc.util

import java.util.Calendar

/**
 * Calendar
 */
object GetCalendar {
  /**
   * Execute process
   */
  def main(args: Array[String]): Unit = {
    val cl = Calendar.getInstance();
    println("------------- 年を表示 -------------")
    println("年：" + cl.get(Calendar.YEAR));
  }
}
```

作成したコードをコンパイルして、runMain を実行する。

```
[SBT] > runMain mvc.util.Calendar
[info] running (fork) mvc.util.GetCalendar
[info] ------------- 年を表示 -------------
[info] 年：2022
[success]
```

期待通り、現在の年（2022/10時点）が表示された。

## 現在の年・月・日・曜日を表示する

年だけではなく、今日の月、日、曜日も表示できるようにしてみる。

```scala
object GetCalendar {
  /**
   * Execute process
   */
  def main(args: Array[String]): Unit = {
    val cl = Calendar.getInstance()

    val year  = cl.get(Calendar.YEAR);
    val month = cl.get(Calendar.MONTH) + 1;
    val day   = cl.get(Calendar.DATE);
    val week  = cl.get(Calendar.DAY_OF_WEEK) - 1
    val weeks = Seq("日", "月", "火", "水", "木", "金", "土")

    println("------------- 今日 -------------")
    println("今日は、" + year + "年" + month + "月" + day + "日" + "(" + weeks(week) + ")")
  }
}
```

上記のコードで、runMain を実行する。

```
[SBT] > runMain mvc.util.GetCalendar
[info] running (fork) mvc.util.GetCalendar
[info] ------------- 今日 -------------
[info] 今日は、2022年10月27日(木)
[success] 
```

正しく表示されているので、期待通りの挙動が確認できた。

## addメソッドで翌日以降を取得する

Calendarクラスのaddメソッドを使って、翌日以降の取得と翌月の末日がカレンダー通りになっている確認する。

```scala
  for (_ <- 0 to 34){
    cl.add(Calendar.DAY_OF_MONTH, 1)
    println(sdf.format(cl.getTime()))
  }
```

上記のコードを実行してみる。

```
[SBT] > runMain mvc.util.GetCalendar
[info] ------------- DebugCode -------------
[info] 今日は、2022年10月27日(木)
[info] ------------- DebugCode -------------
[info] Fri Oct 28 23:13:34 JST 2022
[info] Sat Oct 29 23:13:34 JST 2022
[info] Sun Oct 30 23:13:34 JST 2022
[info] Mon Oct 31 23:13:34 JST 2022
[info] Tue Nov 01 23:13:34 JST 2022
[info] Wed Nov 02 23:13:34 JST 2022
// 省略
[info] Tue Nov 29 23:13:34 JST 2022
[info] Wed Nov 30 23:13:34 JST 2022
[info] Thu Dec 01 23:13:34 JST 2022
```

カレンダー通り、翌月末日が30日になっていることが確認できた！
あとは、フォーマットが見づらいので、 `SimpleDateFormat` を利用して整形する。


```scala
import java.text.SimpleDateFormat

    val prepare = new SimpleDateFormat("yyyy.MM.dd(E)")

    for (_ <- 0 to 34){
      cl.add(Calendar.DAY_OF_MONTH, 1)
      println(prepare.format(cl.getTime()))
    }
```

再度実行してみる。

```
[info] 2022.10.28(金)
[info] 2022.10.29(土)
[info] 2022.10.30(日)
[info] 2022.10.31(月)
[info] 2022.11.01(火)
// 省略
```

これでだいぶ見やすくなリマした。
曜日を出力するときに日本語で表示できないか迷走してたら、 `E` で表示できることに気づいてだいぶスッキリしましたw
JAVAのドキュメントは日本語でかなり見やすいので助かります。


> 参照： https://docs.oracle.com/javase/jp/8/docs/api/java/text/SimpleDateFormat.html


ここまでできたのであとすこしです！
表示対象を今月のみにできるように、forの値を少し工夫します。

## 月末日を取得

月末の値を取得したいので、CalendarクラスのgetActualMinimumメソッドを利用してみます。
試しに今月末日の値が取得できるか試してみる。

> getActualMinimumメソッド
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Calendar.html#getActualMinimum-int-

```scala
    val lastDay  = cl.getActualMaximum(Calendar.DAY_OF_MONTH)

    println("------------- DebugCode -------------")
    println(lastDay)
```

実行した結果が下記の通り。

```
[info] ------------- DebugCode -------------
[info] 31
```

2022年10月は、末日が31日なので、期待通りの挙動が確認できました。


## 当月の日をすべて表示

当月の月初をsetメソッドで設定し、末日までの回数分の日を表示させます。

```scala
    val lastDay = cl.getActualMaximum(Calendar.DAY_OF_MONTH)

    cl.set(year, month, 1)

    for (_ <- 1 to lastDay){
      println(prepare.format(cl.getTime()))
      cl.add(Calendar.DAY_OF_MONTH, 1)
    }
```

出力した結果が下記になります。

```
[info] ------------- DebugCode -------------
[info] 2022.10.01(土)
[info] 2022.10.02(日)
// 省略
[info] 2022.10.30(日)
[info] 2022.10.31(月)
[success]
```

ようやく表示が確認できましたー！

## 最終コード

```scala
package mvc.util

import java.util.Calendar
import java.text.SimpleDateFormat

/**
 * Calendar
 */
object GetCalendar {
  /**
   * Execute process
   */
  def main(args: Array[String]): Unit = {
    val cl      = Calendar.getInstance()
    val year    = cl.get(Calendar.YEAR);
    val month   = cl.get(Calendar.MONTH);
    val lastDay = cl.getActualMaximum(Calendar.DAY_OF_MONTH)
    val prepare = new SimpleDateFormat("yyyy.MM.dd(E)")

    cl.set(year, month, 1)
    for (_ <- 1 to lastDay){
      println(prepare.format(cl.getTime()))
      cl.add(Calendar.DAY_OF_MONTH, 1)
    }
  }
}
```

> 参考記事
https://www.sejuku.net/blog/24848
https://cobot.hatenablog.com/entry/2012/05/04/112919
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Calendar.html
> 

# 最後に

JAVAのCalendarクラスで、当月の日を表示させる処理を記述してみました。

もっと簡単な方法やScalaでリファクタリングできそうな気がしますね。
あとは、翌月以降のデータも取得してみたり、取得した年・月・日のデータをビューに表示できるように、これから取り組んでいきたいと思います。

最後まで読んでいただきありがとうございました！