Flutter开发中如何在Firestore中存储和读取Duration时长类型数据
问题解答
1. 不需要使用Timestamp类型存储
Timestamp是Firestore用来存储具体时间点的类型,对应Dart的DateTime类,而你要存的是时间长度,用Timestamp只会增加不必要的转换成本,完全没有必要。
推荐直接把准备时长存为int类型的分钟数(餐食准备场景精确到分钟足够使用),如果有更精细的需求也可以存毫秒数。
2. 代码修改方案
2.1 调整ProductModel类
class ProductModel { String? productName; // 注意修正你原来的拼写错误:prdouctImgUrl改为productImgUrl String? productImgUrl; double? productPrice; // 保留Duration类型字段 Duration? preparationTime; ProductModel(); ProductModel.fromSnapshot(DocumentSnapshot snap){ productName = snap["productName"]; productImgUrl= snap["productImgUrl"]; productPrice= snap["productPrice"]; // 直接把Firestore中存储的int分钟数转成Duration即可 preparationTime= Duration(minutes: snap["preparationTime"] as int); } // 如果需要把数据写入Firestore,用这个方法转成可存储的格式 Map<String, dynamic> toJson() { return { "productName": productName, "productImgUrl": productImgUrl, "productPrice": productPrice, "preparationTime": preparationTime?.inMinutes, }; } }
2.2 页面展示逻辑调整
// 展示产品逻辑 ..... _product = ProductModel.fromSnapshot(snapshot.data!.docs[i]); // 格式化时长展示文本 String formatDuration(Duration d) { if (d.inHours > 0) { return "${d.inHours}小时${d.inMinutes.remainder(60)}分钟"; } return "${d.inMinutes}分钟"; } // 计算预计送达时间 DateTime expectedTime = DateTime.now().add(_product.preparationTime!); // 格式化时间展示,也可以用intl包的DateFormat做更规范的格式化 String formatTime(DateTime t) => "${t.month}月${t.day}日 ${t.hour}:${t.minute.toString().padLeft(2, '0')}"; return ListTile( leading: CircleAvatar( backgroundImage: NetworkImage(_product.productImgUrl), child: _product.productImgUrl.isEmpty ? Text("${_product.productName?[0].toUpperCase() ?? ''}") : const SizedBox(), radius: 15,), title: Text(_product.productName ?? ''), subtitle: Text("准备时长:${formatDuration(_product.preparationTime!)} \n 预计送达:${formatTime(expectedTime)}"), );
特殊情况说明
如果你因为特殊业务要求一定要用Timestamp存储,也可以实现转换逻辑:存的时候取Duration的毫秒数,构造一个从1970年1月1日0点开始计算的Timestamp,读的时候再取Timestamp的毫秒数转成Duration,但这种方案完全没有必要,效率远低于直接存整数。
内容的提问来源于stack exchange,提问作者Philyow Belen
相关产品推荐
相关产品推荐

