首页 > 解决方案 > Dart Lang:奇怪的结果增加了 7 天。有时计算不好

问题描述

给定一个日期,假设是星期一,我希望如果我增加 7 天,我会得到一个新的星期一。

有时就是这样,在某些情况下它增加了一点,我得到了一个星期天。我可以继续增加 7 天,然后得到星期天,直到我得到一个新的星期一。

我怎样才能制定一个精确的周期,让我在一周的同一天返回。

在这里,我将代码留在 Dart 中。链接到飞镖盘

void main() {
  var date = DateTime(2020, 10, 20);
  var weekday = date.weekday;
  var endDate = DateTime(2021, 4, 8);
  while (endDate.difference(date).inDays > 0) {
    assert(date.weekday == weekday);
    print('$date ${date.weekday} $weekday');
    date = date.add(Duration(days: 7));
  }
  print('end');
}

结果是

2020-10-20 00:00:00.000 2 2
2020-10-26 23:00:00.000 1 2
2020-11-02 23:00:00.000 1 2
2020-11-09 23:00:00.000 1 2
2020-11-16 23:00:00.000 1 2
2020-11-23 23:00:00.000 1 2
2020-11-30 23:00:00.000 1 2
2020-12-07 23:00:00.000 1 2
2020-12-14 23:00:00.000 1 2
2020-12-21 23:00:00.000 1 2
2020-12-28 23:00:00.000 1 2
2021-01-04 23:00:00.000 1 2
2021-01-11 23:00:00.000 1 2
2021-01-18 23:00:00.000 1 2
2021-01-25 23:00:00.000 1 2
2021-02-01 23:00:00.000 1 2
2021-02-08 23:00:00.000 1 2
2021-02-15 23:00:00.000 1 2
2021-02-22 23:00:00.000 1 2
2021-03-01 23:00:00.000 1 2
2021-03-08 23:00:00.000 1 2
2021-03-15 23:00:00.000 1 2
2021-03-22 23:00:00.000 1 2
2021-03-30 00:00:00.000 2 2
2021-04-06 00:00:00.000 2 2
end

标签: datetimedartweekday

解决方案


正如评论中所解释的,Duration(days: 7)意味着 7 * 24 小时。(ADuration内部只是一个表示微秒数的整数。)如果您的本地时区由于夏令时而发生变化,那么将“1 天”(24 小时)添加到本地DateTime对象可能会导致DateTime本地时间与本地时间不同的对象如果夏令时在该时间间隔内开始或结束,则为原始。

DateTime文档中所述:

不同时区的两个日期之间的差异只是两个时间点之间的纳秒数。它不考虑日历天数。这意味着当地时间的两个午夜之间的差异可能小于 24 小时乘以它们之间的天数,如果两者之间有夏令时变化。如果上面的差异是使用澳大利亚当地时间计算的,那么差异是 7415 天和 23 小时,这只是 7415 报告的全天inDays

如果您只想添加日历天而不影响时间,该怎么办?您可以使用 UTC 而不是您的本地时区,但如果您想向用户显示时间,这可能不友好。或者,您可以提供自己的函数来添加多个日历日,并从原始日期复制时间:

extension DateTimeAddCalendarDays on DateTime {
  /// Adds a specified number of days to this [DateTime].
  ///
  /// Unlike `DateTime.add(Duration(days: numberOfDays))`, this adds "days"
  /// and not 24-hour increments, and therefore it leaves the time of day
  /// unchanged if a DST change would occur during the time interval.
  DateTime addCalendarDays(int numDays) => copyWith(day: day + numDays);

  /// Copies a [DateTime], overriding specified values.
  DateTime copyWith({
    int? year,
    int? month,
    int? day,
    int? hour,
    int? minute,
    int? second,
    int? millisecond,
    int? microsecond,
  }) {
    return (isUtc ? DateTime.utc : DateTime.new)(
      year ?? this.year,
      month ?? this.month,
      day ?? this.day,
      hour ?? this.hour,
      minute ?? this.minute,
      second ?? this.second,
      millisecond ?? this.millisecond,
      microsecond ?? this.microsecond,
    );
  }
}

然后替换date.add(Duration(days: 7))date.addCalendarDays(7).


推荐阅读