Dart中如何按月日排序事件列表以展示即将到来的生日
按月份和日期排序生日事件的实现方案
我开发了一款生日提醒应用,需要展示按仅月份和日期排序后的即将到来的生日,并在ListView Builder中呈现。
当前我使用以下代码对事件列表排序:
void main() { List<EventModel> events = [ EventModel( title: 'A', date: DateTime(1980, 08, 12), ), EventModel( title: 'Z', date: DateTime(2020, 12, 28), ), EventModel( title: 'B', date: DateTime(1995, 12, 21), ), ]; events.sort((a, b) => (a.date).compareTo(b.date)); for(var x in events) print(x.date.toString()); }
这段代码会按包含年份的完整日期排序,输出结果为:
1980-08-12 00:00:00.000 1995-12-21 00:00:00.000 2020-12-28 00:00:00.000
但我需要按仅月份和日期排序,得到符合即将到来生日顺序的结果:
2020-12-28 00:00:00.000 1980-08-12 00:00:00.000 1995-12-21 00:00:00.000
实现方案
要实现仅按月份和日期排序(且符合「即将到来」的逻辑),可以通过以下方式完成:
方法一:自定义排序逻辑(直接实现)
核心思路是忽略原日期的年份,将每个生日转换为当年的日期,对比其与当前日期的先后:如果生日已过,则视为下一年的生日,以此排序。
修改后的排序代码如下:
void main() { List<EventModel> events = [ EventModel(title: 'A', date: DateTime(1980, 08, 12)), EventModel(title: 'Z', date: DateTime(2020, 12, 28)), EventModel(title: 'B', date: DateTime(1995, 12, 21)), ]; DateTime now = DateTime.now(); // 计算某日期在当年的天数(从1月1日开始算) int calculateDayOfYear(DateTime date) { return DateTime(now.year, date.month, date.day) .difference(DateTime(now.year, 1, 1)) .inDays; } events.sort((a, b) { int aDay = calculateDayOfYear(a.date); int bDay = calculateDayOfYear(b.date); int currentDay = calculateDayOfYear(now); // 如果生日已过,将其视为下一年的生日(加365天) if (aDay < currentDay) aDay += 365; if (bDay < currentDay) bDay += 365; return aDay.compareTo(bDay); }); for(var x in events) print(x.date.toString()); }
方法二:扩展DateTime类(复用性更强)
如果需要在多处使用生日排序逻辑,可以给DateTime类添加扩展方法,简化代码:
extension DateTimeBirthdaySort on DateTime { int get birthdayPriority { DateTime now = DateTime.now(); DateTime thisYearBirthday = DateTime(now.year, this.month, this.day); int dayOfYear = thisYearBirthday.difference(DateTime(now.year, 1, 1)).inDays; int currentDay = now.difference(DateTime(now.year, 1, 1)).inDays; // 已过的生日优先级+365,视为下一年的日期 return dayOfYear < currentDay ? dayOfYear + 365 : dayOfYear; } }
使用时只需一行代码完成排序:
events.sort((a, b) => a.date.birthdayPriority.compareTo(b.date.birthdayPriority));
效果验证
以当前日期为12月22日为例,运行代码后输出结果与期望完全一致:
2020-12-28 00:00:00.000 1980-08-12 00:00:00.000 1995-12-21 00:00:00.000
内容的提问来源于stack exchange,提问作者user22362195
相关产品推荐
相关产品推荐

