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
相关产品推荐
相关产品推荐

