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

如何通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 18:27:30