You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何按日期、月份、年份区分即将进行与已完成会议?

问题分析

你当前的筛选逻辑存在本质问题:用dd/MM/yyyy格式的字符串做日期比较时,是按字典序而非实际日期顺序判断的。比如"05/10/2024"(10月5日)会被认为小于"20/09/2024"(9月20日),因为字符串首字符0 < 2,完全不符合实际日期逻辑。

要实现「会议开始前显示在即将进行页,结束后显示在已完成页」的需求,必须将日期+时间转成可正确比较的DateTime或Firestore的Timestamp类型,再进行筛选。


解决方案

推荐优先在Firestore端完成筛选(效率更高),以下分两种场景给出实现代码:

场景1:Firestore存储完整时间戳(推荐)

如果能修改Firestore字段,新增Start Timestamp和End Timestamp字段(类型设为Timestamp),直接存储会议的完整开始/结束时间,查询逻辑会非常简洁:

即将进行会议的Stream

StreamBuilder(
  stream: meeting
      .where("Meeting Type", isEqualTo: type)
      .where("Start Timestamp", isGreaterThanOrEqualTo: Timestamp.now())
      .snapshots(),
  builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
    if (streamSnapshot.hasData) {
      QuerySnapshot? querySnapshot = streamSnapshot.data;
      List<QueryDocumentSnapshot> documents = querySnapshot!.docs;
      List<Map> items = documents.map((e) => {
        "Meeting Date": e['Meeting Date'],
        "Meeting Name": e['Meeting Name'],
        "Place": e['Place'],
        "Time From": e['Time From'],
        "To Time": e['To Time']
      }).toList();
      
      // 后续UI构建逻辑(比如ListView)
      return ListView.builder(
        itemCount: items.length,
        itemBuilder: (ctx, idx) => ListTile(
          title: Text(items[idx]['Meeting Name']),
          subtitle: Text("${items[idx]['Meeting Date']} ${items[idx]['Time From']} - ${items[idx]['To Time']}"),
        ),
      );
    }
    return const CircularProgressIndicator();
  },
)

已完成会议的Stream

StreamBuilder(
  stream: meeting
      .where("Meeting Type", isEqualTo: type)
      .where("End Timestamp", isLessThan: Timestamp.now())
      .snapshots(),
  builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
    if (streamSnapshot.hasData) {
      QuerySnapshot? querySnapshot = streamSnapshot.data;
      List<QueryDocumentSnapshot> documents = querySnapshot!.docs;
      List<Map> items = documents.map((e) => {
        "Meeting Date": e['Meeting Date'],
        "Meeting Name": e['Meeting Name'],
        "Place": e['Place'],
        "Time From": e['Time From'],
        "To Time": e['To Time']
      }).toList();
      
      // 后续UI构建逻辑
      return ListView.builder(
        itemCount: items.length,
        itemBuilder: (ctx, idx) => ListTile(
          title: Text(items[idx]['Meeting Name']),
          subtitle: Text("${items[idx]['Meeting Date']} ${items[idx]['Time From']} - ${items[idx]['To Time']}"),
        ),
      );
    }
    return const CircularProgressIndicator();
  },
)

场景2:无法修改Firestore字段(基于现有字符串字段处理)

如果必须保留原有的Meeting Date(dd/MM/yyyy字符串)、Time From、To Time字段,只能在客户端拉取所有数据后,转成DateTime再筛选:

即将进行会议的实现

StreamBuilder(
  stream: meeting
      .where("Meeting Type", isEqualTo: type)
      .snapshots(),
  builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
    if (streamSnapshot.hasData) {
      final now = DateTime.now();
      final documents = streamSnapshot.data!.docs;
      
      // 筛选即将进行的会议:开始时间 >= 当前时间
      final upcomingDocs = documents.where((doc) {
        // 解析会议日期
        final dateParts = (doc['Meeting Date'] as String).split('/');
        final meetingDate = DateTime(
          int.parse(dateParts[2]),
          int.parse(dateParts[1]),
          int.parse(dateParts[0]),
        );
        // 解析开始时间
        final timeParts = (doc['Time From'] as String).split(':');
        final meetingStartTime = DateTime(
          meetingDate.year,
          meetingDate.month,
          meetingDate.day,
          int.parse(timeParts[0]),
          int.parse(timeParts[1]),
        );
        
        return meetingStartTime.isAfter(now) || meetingStartTime.isAtSameMomentAs(now);
      }).toList();
      
      List<Map> items = upcomingDocs.map((e) => {
        "Meeting Date": e['Meeting Date'],
        "Meeting Name": e['Meeting Name'],
        "Place": e['Place'],
        "Time From": e['Time From'],
        "To Time": e['To Time']
      }).toList();
      
      return ListView.builder(
        itemCount: items.length,
        itemBuilder: (ctx, idx) => ListTile(
          title: Text(items[idx]['Meeting Name']),
          subtitle: Text("${items[idx]['Meeting Date']} ${items[idx]['Time From']} - ${items[idx]['To Time']}"),
        ),
      );
    }
    return const CircularProgressIndicator();
  },
)

已完成会议的实现

StreamBuilder(
  stream: meeting
      .where("Meeting Type", isEqualTo: type)
      .snapshots(),
  builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
    if (streamSnapshot.hasData) {
      final now = DateTime.now();
      final documents = streamSnapshot.data!.docs;
      
      // 筛选已完成的会议:结束时间 < 当前时间
      final completedDocs = documents.where((doc) {
        // 解析会议日期
        final dateParts = (doc['Meeting Date'] as String).split('/');
        final meetingDate = DateTime(
          int.parse(dateParts[2]),
          int.parse(dateParts[1]),
          int.parse(dateParts[0]),
        );
        // 解析结束时间
        final timeParts = (doc['To Time'] as String).split(':');
        final meetingEndTime = DateTime(
          meetingDate.year,
          meetingDate.month,
          meetingDate.day,
          int.parse(timeParts[0]),
          int.parse(timeParts[1]),
        );
        
        return meetingEndTime.isBefore(now);
      }).toList();
      
      List<Map> items = completedDocs.map((e) => {
        "Meeting Date": e['Meeting Date'],
        "Meeting Name": e['Meeting Name'],
        "Place": e['Place'],
        "Time From": e['Time From'],
        "To Time": e['To Time']
      }).toList();
      
      return ListView.builder(
        itemCount: items.length,
        itemBuilder: (ctx, idx) => ListTile(
          title: Text(items[idx]['Meeting Name']),
          subtitle: Text("${items[idx]['Meeting Date']} ${items[idx]['Time From']} - ${items[idx]['To Time']}"),
        ),
      );
    }
    return const CircularProgressIndicator();
  },
)

内容的提问来源于stack exchange,提问作者divya manickam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 14:35:12