80 lines
2.3 KiB
Dart
80 lines
2.3 KiB
Dart
import 'course.dart';
|
|
import 'semester.dart';
|
|
import 'course_occurrence.dart';
|
|
import 'lesson_times.dart';
|
|
|
|
import 'package:timezone/timezone.dart' as tz;
|
|
|
|
export 'course.dart';
|
|
export 'semester.dart';
|
|
export 'lesson_times.dart';
|
|
export 'course_occurrence.dart';
|
|
|
|
class ScheduleEngine {
|
|
static DateTime schoolDate(DateTime instant) {
|
|
final local = tz.TZDateTime.from(instant, tz.getLocation('Asia/Shanghai'));
|
|
return DateTime.utc(local.year, local.month, local.day);
|
|
}
|
|
|
|
static int? weekNumber(Semester semester, DateTime schoolDate) {
|
|
final date = DateTime.utc(
|
|
schoolDate.year,
|
|
schoolDate.month,
|
|
schoolDate.day,
|
|
);
|
|
final delta = date.difference(semester.firstMonday).inDays;
|
|
if (delta < 0 || delta >= semester.totalWeeks * 7) return null;
|
|
return delta ~/ 7 + 1;
|
|
}
|
|
|
|
static List<CourseOccurrence> occurrences(
|
|
List<Course> courses,
|
|
Semester semester,
|
|
) {
|
|
final result = <CourseOccurrence>[];
|
|
final zone = tz.getLocation('Asia/Shanghai');
|
|
for (final course in courses) {
|
|
for (final week in course.weeks) {
|
|
if (week > semester.totalWeeks) continue;
|
|
final day = semester.firstMonday.add(
|
|
Duration(days: (week - 1) * 7 + course.weekday - 1),
|
|
);
|
|
if (day.isBefore(semester.startDate)) continue;
|
|
final first = lessonSlots[course.startPeriod - 1].startMinute;
|
|
final last = lessonSlots[course.endPeriod - 1].endMinute;
|
|
result.add(
|
|
CourseOccurrence(
|
|
key: '${course.id}/${day.toIso8601String().substring(0, 10)}',
|
|
course: course,
|
|
week: week,
|
|
start: tz.TZDateTime(
|
|
zone,
|
|
day.year,
|
|
day.month,
|
|
day.day,
|
|
first ~/ 60,
|
|
first % 60,
|
|
),
|
|
end: tz.TZDateTime(
|
|
zone,
|
|
day.year,
|
|
day.month,
|
|
day.day,
|
|
last ~/ 60,
|
|
last % 60,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
result.sort((a, b) {
|
|
final order = a.start.compareTo(b.start);
|
|
return order == 0 ? a.key.compareTo(b.key) : order;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
static bool overlaps(CourseOccurrence a, CourseOccurrence b) =>
|
|
a.start.isBefore(b.end) && b.start.isBefore(a.end);
|
|
}
|