如何通过Future.delayed从循环中动态返回日期进度值?
日期进度计算函数问题解决
需求说明
- 编写函数接收两个日期参数,返回
Double类型的进度值,代表距离最终日期的剩余天数进度 - 进度需随日期推进自动更新(比如示例中从2022.07.23的56.25%到2022.07.24的62.5%)
示例
开始日期:2022.07.15
结束日期:2022.07.31
当前日期:2022.07.23
剩余天数:8天(总天数16天)
进度:56.25%
到2022.07.24时,函数应返回62.5%
用户实验代码(以秒为单位演示)
// ignore_for_file: avoid_print import 'dart:async'; void main() { progressDates(DateTime(2022, 7, 15), DateTime(2022, 7, 31)); } double progressDates( DateTime date1, DateTime date2, ) { DateTime now = DateTime.now(); DateTime nowDay = DateTime(now.year, now.month, now.day); int dif1 = nowDay .difference(date1) .inDays; // 开始日期到当前日期的天数差 int dif2 = date2 .difference(nowDay) .inDays; // 当前日期到结束日期的天数差 int allDays = date2.difference(date1).inDays; double inDouble = (dif1 / allDays) * 100; double temp = 100 / allDays; DateTime current = DateTime.now(); Stream timer = Stream.periodic(const Duration(seconds: 1), (i) { current = current.add(const Duration(seconds: 1)); inDouble = inDouble + temp; return inDouble; }).take(dif2); timer.listen((percentage) => percentage); double result = timer as double; print(result); return result; }
问题分析与修正
原代码核心错误是把Stream强制转换为double,这完全不符合异步数据流的逻辑。要实现需求,分两种场景处理:
场景1:同步获取当前进度(无实时更新)
如果只需要一次性获取当前时刻的进度值,直接同步计算即可:
double getCurrentProgress(DateTime startDate, DateTime endDate) { // 标准化日期为当天0点,避免时分秒干扰天数计算 DateTime today = DateTime.now(); DateTime normalizedStart = DateTime(startDate.year, startDate.month, startDate.day); DateTime normalizedEnd = DateTime(endDate.year, endDate.month, endDate.day); int totalDays = normalizedEnd.difference(normalizedStart).inDays; if (totalDays <= 0) return 0.0; // 处理结束日期早于开始日期的异常 int passedDays = DateTime(today.year, today.month, today.day).difference(normalizedStart).inDays; // 限制进度在0-100区间内 if (passedDays <= 0) return 0.0; if (passedDays >= totalDays) return 100.0; return (passedDays / totalDays) * 100; } // 使用示例 void main() { double progress = getCurrentProgress(DateTime(2022,7,15), DateTime(2022,7,31)); print("当前进度:${progress.toStringAsFixed(2)}%"); }
场景2:实时监听进度变化(自动更新)
如果需要进度随日期推进自动刷新,返回Stream<double>让调用者监听数据流:
import 'dart:async'; Stream<double> progressStream(DateTime startDate, DateTime endDate) { DateTime normalizedStart = DateTime(startDate.year, startDate.month, startDate.day); DateTime normalizedEnd = DateTime(endDate.year, endDate.month, endDate.day); int totalDays = normalizedEnd.difference(normalizedStart).inDays; if (totalDays <= 0) { return Stream.value(0.0); } StreamController<double> controller = StreamController<double>(); // 先发送当前进度 controller.add(_calculateCurrentProgress(normalizedStart, normalizedEnd)); // 计算到次日0点的时间差,到点后每天更新一次进度 DateTime now = DateTime.now(); DateTime nextDay = DateTime(now.year, now.month, now.day + 1); Duration timeToNextUpdate = nextDay.difference(now); Timer(timeToNextUpdate, () { Timer.periodic(const Duration(days: 1), (timer) { double progress = _calculateCurrentProgress(normalizedStart, normalizedEnd); controller.add(progress); // 进度到100%后关闭流并取消定时器 if (progress >= 100.0) { controller.close(); timer.cancel(); } }); }); return controller.stream; } // 内部工具函数:计算当前进度 double _calculateCurrentProgress(DateTime start, DateTime end) { DateTime today = DateTime.now(); int passedDays = DateTime(today.year, today.month, today.day).difference(start).inDays; int totalDays = end.difference(start).inDays; if (passedDays <= 0) return 0.0; if (passedDays >= totalDays) return 100.0; return (passedDays / totalDays) * 100; } // 使用示例 void main() { progressStream(DateTime(2022,7,15), DateTime(2022,7,31)) .listen((progress) { print("更新进度:${progress.toStringAsFixed(2)}%"); }); }
关键说明
- 标准化日期为当天0点,避免时分秒对天数计算的干扰
- 处理异常边界情况(结束日期早于开始日期、当前日期在时间区间外)
- 同步方案适合一次性获取进度,异步Stream方案适合需要实时更新的进度条场景
内容的提问来源于stack exchange,提问作者Flutter kyoto
相关产品推荐
相关产品推荐

