1

Given a date, and let's say it is Monday, I hope that if I add 7 days I will get a new Monday.

That is so sometimes, in some case it adds a little less and I get a Sunday. I can keep adding 7 days and I get Sundays until I get a new Monday back.

How can I make a precise cycle that returns me the same day of the week.

Here I leave the code in Dart. Linked to a dartpad

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');
}

The result is

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
Santi
  • 491
  • 6
  • 14
  • It's from Daylight Saving Time. Note how the times are off by one hour around late October and March. – jamesdlin Jul 01 '21 at 18:02
  • 1
    Correct. You are not adding seven calendar days. You are adding seven clock days, aka. 7 * 24 hours. When time zones change due to daylight saving, that means you won't get the same clock time as before. – lrn Jul 01 '21 at 18:20

1 Answers1

4

As explained in the comments, Duration(days: 7) means 7 * 24 hours. (A Duration internally is just an integer representing a number of microseconds.) If your local timezone changes due to Daylight Saving Time, then adding "1 day" (24 hours) to a local DateTime object can result in a DateTime object whose local time is different from the original if Daylight Saving Time started or ended within that time interval.

As mentioned in the DateTime documentation:

The difference between two dates in different time zones is just the number of nanoseconds between the two points in time. It doesn't take calendar days into account. That means that the difference between two midnights in local time may be less than 24 hours times the number of days between them, if there is a daylight saving change in between. If the difference above is calculated using Australian local time, the difference is 7415 days and 23 hours, which is only 7415 whole days as reported by inDays.

What can you do if you want to only add calendar days without affecting the time? You could use UTC instead of your local timezone, but that probably would not be friendly if you want to display times to users. Alternatively you could provide your own function to add a number of calendar days and that copies the times from the original:

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);
}

and then replace date.add(Duration(days: 7)) with date.addCalendarDays(7).

The above code is available as part of DateTimeBasics from package:basics.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204