Dartで1ヶ月分のカレンダーを生成するサンプル
Dartで、1ヶ月分のカレンダーを生成する処理を書いてみました。 特段難しいことも無く、スマートに書けるなという印象です(自分が最初に書いたコードは3倍ほど有って酷いものでしたが。。。)
今回作成した1ヶ月分のカレンダーは、フロントエンド側で12ヶ月分のカレンダーを表示するというのが目的なので、デザインのことも考えて以下のようなルールにしました。
- 各月は、前月と次月の日付を含んだ42日分固定。
- つまり各月は6週間分の日付が含まれる。
- 週の初めは日曜日。
コード
import 'dart:core';
class CalendarService {
List<DateTime> createOneMonthCalendarAt(DateTime target) {
final DateTime firstDay = DateTime.utc(target.year, target.month, 1);
DateTime startDay = firstDay;
int count = 0;
while(startDay.weekday != DateTime.sunday) {
startDay = DateTime.utc(firstDay.year, firstDay.month, 1 - count);
count++;
}
// 7days * 6 weeks == 42 (max weeks of a month.)
List<DateTime> calendar = List.generate(42, (i) => i)
.map((int i) => DateTime.utc(startDay.year, startDay.month, startDay.day+i)).toList();
return calendar;
}
}
テストコードは以下のような感じです
import 'package:test/test.dart';
import 'package:intl/intl.dart';
void main() {
CalendarService calendarService;
setUp(() async {
calendarService = CalendarService();
});
test("createOneMonthCalendarAt", () {
// create and test a calendar with all days of December 2019.
List<DateTime> dec2019 = calendarService.createOneMonthCalendarAt( DateTime.utc(2019, 12, 1));
expect(dec2019.length, 42);
expect(dec2019.first,DateTime.utc(2019, 12, 1));
expect(dec2019.last, DateTime.utc(2020, 1, 11));
List.generate(31, (i) => i+1).forEach((int day) {
expect(calendarService.createOneMonthCalendarAt(DateTime.utc(2019, 12, day)), dec2019);
});
// create and test a calendar with all days of January 2020.
List<DateTime> jan2020 = calendarService.createOneMonthCalendarAt(DateTime(2020, 1, 1));
expect(jan2020.length, 42);
expect(jan2020.first, DateTime.utc(2019, 12, 29));
expect(jan2020.last, DateTime.utc(2020, 2, 8));
List.generate(31, (i) => i+1).forEach((int day) {
expect(calendarService.createOneMonthCalendarAt(DateTime.utc(2020, 1, day)), jan2020);
});
});
}
その他
最初にカレンダーの開始日を求めるために前月まで日付を遡る部分が、whileじゃなくて変数を使わずに再帰などで上手いこと書ければよかったのですが、DartにはFPな言語には普通に有るListのhead()
とtail()
に相当するメソッドが存在しないようで、とりあえず見送りました。
恐らくクライアント側で動かすことを考えたときに、下手にスタックを食いつぶしてエラーになるようなコードを書かせないように意図的にこの辺りのメソッドを省いているような気がします。(あくまで気がするだけ)
公開日:2019/04/23