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

Flutter中如何在Firestore单个字段收发日期与时间两类数据?

拆分Firestore中日期与时间字段的实现方案

问题背景

我在Flutter应用里设置了两个TextField:点击第一个调用showDatePicker选择日期,第二个调用showTimePicker选择时间。原本用单个DateTime? taskDate变量同时存储日期和时间,存入Firestore后自动转为包含完整日期时间的Timestamp字段。现在需要将日期和时间分别存入Firestore的独立字段,并且能对这两个字段单独操作。


1. 调整TaskModel模型类

把原来的单个taskDate字段拆分为两个独立字段,分别存储纯日期和纯时间:

class TaskModel {
  final String taskTitle;
  final DateTime taskDateOnly; // 仅保留日期,时间固定为00:00:00
  final DateTime taskTimeOnly; // 仅保留时分秒,日期固定为1970-01-01(基准日期)
  final String name;
  final String uid;

  TaskModel({
    required this.taskTitle,
    required this.taskDateOnly,
    required this.taskTimeOnly,
    required this.name,
    required this.uid,
  });

  // 转换为Firestore可识别的JSON格式,DateTime会自动转为Timestamp
  Map<String, dynamic> toJson() {
    return {
      'taskTitle': taskTitle,
      'taskDateOnly': taskDateOnly,
      'taskTimeOnly': taskTimeOnly,
      'name': name,
      'uid': uid,
    };
  }

  // 从Firestore返回的JSON解析为模型对象
  factory TaskModel.fromJson(Map<String, dynamic> json) {
    return TaskModel(
      taskTitle: json['taskTitle'],
      taskDateOnly: (json['taskDateOnly'] as Timestamp).toDate(),
      taskTimeOnly: (json['taskTimeOnly'] as Timestamp).toDate(),
      name: json['name'],
      uid: json['uid'],
    );
  }
}

2. 修改添加任务的逻辑

在调用addTask时,将用户选择的日期和时间拆分处理后传入模型:

  • 从showDatePicker获取的日期,保留年/月/日,时间置为00:00:00
  • 从showTimePicker获取的时间,用固定基准日期(如1970-01-01)承载时分秒信息
TaskModel? taskModel;
void addTask({
  required String title,
  required DateTime selectedDate, // 来自showDatePicker的日期
  required TimeOfDay selectedTime, // 来自showTimePicker的时间
}) {
  emit(AddPostLoadingState());
  
  // 处理纯日期:剥离时间部分
  final dateOnly = DateTime(
    selectedDate.year,
    selectedDate.month,
    selectedDate.day,
  );
  
  // 处理纯时间:用基准日期承载时分
  final timeOnly = DateTime(
    1970, 1, 1,
    selectedTime.hour,
    selectedTime.minute,
  );

  taskModel = TaskModel(
    taskTitle: title,
    taskDateOnly: dateOnly,
    taskTimeOnly: timeOnly,
    name: userModel!.name,
    uid: userModel!.uId,
  );

  FirebaseFirestore.instance
      .collection('tasks')
      .add(taskModel!.toJson())
      .then((value) {
    getTask();
  }).catchError((error) {
    print(error);
    emit(AddPostErrorState(error));
  });
}

3. 优化获取任务的逻辑

现在从Firestore拉取数据时,直接通过模型的fromJson方法解析拆分后的字段即可,无需额外转换:

void getTask() {
  emit(GetTaskLoadingState());
  FirebaseFirestore.instance
      .collection('tasks')
      .where('uid', isEqualTo: uId)
      .orderBy('taskDateOnly')
      .get()
      .then((value) {
    tasks = [];
    for (var element in value.docs) {
      tasks.add(TaskModel.fromJson(element.data()));
    }
    emit(GetTaskSuccessState());
  }).catchError((error) {
    print(error.toString());
    emit(GetTaskErrorState(error: error));
  });
}

4. 单独操作日期/时间字段

现在可以直接针对taskDateOnly或taskTimeOnly进行查询或修改:

  • 查询指定日期的任务:
// 查询2023年1月13日的所有任务
FirebaseFirestore.instance
    .collection('tasks')
    .where('uid', isEqualTo: uId)
    .where('taskDateOnly', isEqualTo: DateTime(2023, 1, 13))
    .get();
  • 查询指定时间之后的任务:
// 查询下午2点及之后的任务
final targetTime = DateTime(1970, 1, 1, 14, 0);
FirebaseFirestore.instance
    .collection('tasks')
    .where('uid', isEqualTo: uId)
    .where('taskTimeOnly', isGreaterThanOrEqualTo: targetTime)
    .get();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 23:31:44