// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import "package:expect/expect.dart"; // Make sure that date-times close to daylight savings work correctly. // See http://dartbug.com/30550 /// A list of (decomposed) date-times where daylight saving changes /// happen. /// /// This list covers multiple timezones to increase test coverage on /// different machines. final daylightSavingChanges = [ // TZ environment, y, m, d, h, change. ["Europe/Paris", 2017, 03, 26, 02, 60], ["Europe/Paris", 2017, 10, 29, 03, -60], ["Antarctica/Troll", 2017, 03, 19, 01, 120], ["Antarctica/Troll", 2017, 10, 29, 03, -120], ["Australia/Canberra", 2017, 04, 02, 03, -60], ["Australia/Canberra", 2017, 10, 01, 02, 60], ["Australia/Lord_Howe", 2017, 04, 02, 02, -30], ["Australia/Lord_Howe", 2017, 10, 01, 02, 30], ["Atlantic/Bermuda", 2017, 03, 12, 02, 60], // US and Canada. ["Atlantic/Bermuda", 2017, 11, 05, 02, -60], ["America/Campo_Grande", 2017, 02, 19, 00, -60], // Brazil ["America/Campo_Grande", 2017, 10, 15, 00, 60], ["America/Santiago", 2017, 05, 14, 00, -60], ["America/Santiago", 2017, 08, 13, 00, 60], ["Chile/EasterIsland", 2017, 05, 13, 22, -60], ["Chile/EasterIsland", 2017, 08, 12, 22, 60], ["Pacific/Fiji", 2017, 01, 15, 03, -60], ["Pacific/Fiji", 2017, 11, 05, 02, 60], ["America/Scoresbysund", 2017, 03, 26, 00, 60], // Ittoqqortoormiit. ["America/Scoresbysund", 2017, 10, 29, 01, -60], ["Asia/Tehran", 2017, 03, 22, 00, 60], ["Asia/Tehran", 2017, 09, 22, 00, -60], ["Israel", 2017, 03, 24, 02, 60], ["Israel", 2017, 10, 29, 02, -60], ["Asia/Amman", 2017, 03, 31, 00, 60], ["Asia/Amman", 2017, 10, 27, 01, -60], ["Mexico/General", 2017, 04, 02, 02, 60], ["Mexico/General", 2017, 10, 29, 02, -60], ]; void runTests() { // Makes sure we don't go into the wrong direction during a // daylight-savings change (as happened in #30550). for (var test in daylightSavingChanges) { for (int i = 0; i < 2; i++) { var year = test[1] as int; var month = test[2] as int; var day = test[3] as int; var hour = test[4] as int; var minute = i == 0 ? 0 : test[5] as int; // Rather adjust the hours than keeping the minutes. hour += minute ~/ 60; minute = minute.remainder(60) as int; if (hour < 0) { hour += 24; day--; } { // Check that microseconds are taken into account. var dtMillisecond = new DateTime(year, month, day, hour, minute, 0, 1); var dtSecond = new DateTime(year, month, day, hour, minute, 1); Expect.equals(const Duration(milliseconds: 999), dtSecond.difference(dtMillisecond)); dtMillisecond = new DateTime(year, month, day, hour, minute, 0, -1); dtSecond = new DateTime(year, month, day, hour, minute, -1); Expect.equals(const Duration(milliseconds: 999), dtMillisecond.difference(dtSecond)); } var dt1 = new DateTime(year, month, day, hour); var dt2 = new DateTime(year, month, day, hour, 1); // Earlier: int earlierDay = day; int earlierHour = hour - 1; if (earlierHour < 0) { earlierHour = 23; earlierDay--; } var dt3 = new DateTime(year, month, earlierDay, earlierHour, 59); var diff1 = dt2.difference(dt1).inMinutes; var diff2 = dt1.difference(dt3).inMinutes; if (diff1 == 1 && diff2 == 1 && dt1.hour == hour && dt1.minute == 0) { // Regular date-time. continue; } // At most one is at a distance of more than a minute. Expect.isTrue(diff1 == 1 || diff2 == 1); if (diff2 < 0) { // This happens, when we ask for invalid times. // Suppose daylight-saving is at 2:00 and switches to 3:00. If we // ask for 2:59, we get 3:59 (59 minutes after 2:00). Expect.isFalse(dt3.day == earlierDay && dt3.hour == earlierHour); // If that's the case, then removing one minute from dt1 should // not yield a date-time with the earlier values, and it should // be far away from dt3. var dt4 = dt1.add(const Duration(minutes: -1)); Expect.isFalse(dt4.day == earlierDay && dt4.hour == earlierHour); Expect.isTrue(dt4.isBefore(dt1)); Expect.isTrue(dt4.day < earlierDay || (dt4.day == earlierDay && dt4.hour < earlierHour)); continue; } // They must be in the right order. Expect.isTrue(dt1.isBefore(dt2)); Expect.isTrue(dt3.isBefore(dt1)); } } } void main() { // The following code constructs a String with all timezones that are // relevant for this test. // This can be helpful for running tests in multiple timezones. // Typically, one would write something like: // for tz in ; do TZ=$tz tools/test.py ...; done var result = new StringBuffer(); for (int i = 0; i < daylightSavingChanges.length; i += 2) { if (i != 0) result.write(" "); result.write(daylightSavingChanges[i][0]); } runTests(); }