java.time.temporal.WeekFields#weekOfMonth
を使うことで、指定日が月の第何週にあたるかを取得できる。
週の始まりを日曜日とするか月曜日とするかも指定できる。
このカレンダーを例とする。
𝙳𝙴𝙲𝙴𝙼𝙱𝙴𝚁 – 𝟸𝟶𝟸𝟷
𝚂𝚞|𝙼𝚘|𝚃𝚞|𝚆𝚎|𝚃𝚑|𝙵𝚛|𝚂𝚊
𝚡𝚡|𝚡𝚡|𝚡𝚡|𝟶𝟷|𝟶𝟸|𝟶𝟹|𝟶𝟺
𝟶𝟻|𝟶𝟼|𝟶𝟽|𝟶𝟾|𝟶𝟿|𝟷𝟶|𝟷𝟷
𝟷𝟸|𝟷𝟹|𝟷𝟺|𝟷𝟻|𝟷𝟼|𝟷𝟽|𝟷𝟾
𝟷𝟿|𝟸𝟶|𝟸𝟷|𝟸𝟸|𝟸𝟹|𝟸𝟺|𝟸𝟻
𝟸𝟼|𝟸𝟽|𝟸𝟾|𝟸𝟿|𝟹𝟶|𝟹𝟷|𝚡𝚡
カレンダーはこちらを使わせていただきました。
https://qwerty.dev/calendar-generator/
実装
週の始まりを日曜日とするなら
val date = LocalDate.of(2021, 12, 26)
val weekField = WeekFields.SUNDAY_START.weekOfMonth()
println(date.get(weekField)) // -> 5
週の始まりを月曜日とするなら
val date = LocalDate.of(2021, 12, 26)
val weekFieldMondayStart = WeekFields.of(DayOfWeek.MONDAY, 1).weekOfMonth()
println(date.get(weekFieldMondayStart)) // -> 4
解説
ここで使っている WeekFields.of()
は第1引数に「週の始まりとする曜日」、第2引数に「何日以上あれば最初の週とみなすか」を指定する。
WeekFields.of(DayOfWeek.MONDAY, 1)
なら週の始まりは月曜日、1日以上あれば最初の週とする。
WeekFields.SUNDAY_START
は WeekFields
に定義されている定数で、内部的には WeekFields.of(DayOfWeek.SUNDAY, 1)
。
「何日以上あれば最初の週とみなすか」ってどういうこと?
「何日以上あれば最初の週とみなすか」が指定できるのは、ISO-8601のような定義に対応するためらしい。
日時のフォーマットを定義しているISO-8601では、4日以上ある週じゃないと最初の週と見なされない。(ちなみにISO-8601では週の始まりは月曜日)
例を挙げる。
2021年12月1日は水曜日なので、日曜日までに5日ある。よって2021年12月1日は第1週である。
2022年1月1日は土曜日なので、日曜日までに2日しかない。この場合、2022年1月3日(月)からが第1週となる。
実際にISO-8601の定義に従った WeekFields
で確認してみる。
val date = LocalDate.of(2022, 1, 1)
val weekField = WeekFields.of(DayOfWeek.MONDAY, 4).weekOfMonth() // ISO-8601の定義
println(date.get(weekField)) // -> 0
このように、最初の週以前の日付は第0週として扱われる。
(なお、WeekFields
にはISO-8601に合わせた定数である ISO
が用意されているので、自分でコーディングする必要はない)