1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "global-handles.h" 31 #include "snapshot.h" 32 #include "cctest.h" 33 34 using namespace v8::internal; 35 36 class DateCacheMock: public DateCache { 37 public: 38 struct Rule { 39 int year, start_month, start_day, end_month, end_day, offset_sec; 40 }; 41 42 DateCacheMock(int local_offset, Rule* rules, int rules_count) 43 : local_offset_(local_offset), rules_(rules), rules_count_(rules_count) {} 44 45 protected: 46 virtual int GetDaylightSavingsOffsetFromOS(int64_t time_sec) { 47 int days = DaysFromTime(time_sec * 1000); 48 int time_in_day_sec = TimeInDay(time_sec * 1000, days) / 1000; 49 int year, month, day; 50 YearMonthDayFromDays(days, &year, &month, &day); 51 Rule* rule = FindRuleFor(year, month, day, time_in_day_sec); 52 return rule == NULL ? 0 : rule->offset_sec * 1000; 53 } 54 55 56 virtual int GetLocalOffsetFromOS() { 57 return local_offset_; 58 } 59 60 private: 61 Rule* FindRuleFor(int year, int month, int day, int time_in_day_sec) { 62 Rule* result = NULL; 63 for (int i = 0; i < rules_count_; i++) 64 if (Match(&rules_[i], year, month, day, time_in_day_sec)) { 65 result = &rules_[i]; 66 } 67 return result; 68 } 69 70 71 bool Match(Rule* rule, int year, int month, int day, int time_in_day_sec) { 72 if (rule->year != 0 && rule->year != year) return false; 73 if (rule->start_month > month) return false; 74 if (rule->end_month < month) return false; 75 int start_day = ComputeRuleDay(year, rule->start_month, rule->start_day); 76 if (rule->start_month == month && start_day > day) return false; 77 if (rule->start_month == month && start_day == day && 78 2 * 3600 > time_in_day_sec) 79 return false; 80 int end_day = ComputeRuleDay(year, rule->end_month, rule->end_day); 81 if (rule->end_month == month && end_day < day) return false; 82 if (rule->end_month == month && end_day == day && 83 2 * 3600 <= time_in_day_sec) 84 return false; 85 return true; 86 } 87 88 89 int ComputeRuleDay(int year, int month, int day) { 90 if (day != 0) return day; 91 int days = DaysFromYearMonth(year, month); 92 // Find the first Sunday of the month. 93 while (Weekday(days + day) != 6) day++; 94 return day + 1; 95 } 96 97 int local_offset_; 98 Rule* rules_; 99 int rules_count_; 100 }; 101 102 static int64_t TimeFromYearMonthDay(DateCache* date_cache, 103 int year, 104 int month, 105 int day) { 106 int64_t result = date_cache->DaysFromYearMonth(year, month); 107 return (result + day - 1) * DateCache::kMsPerDay; 108 } 109 110 111 static void CheckDST(int64_t time) { 112 Isolate* isolate = CcTest::i_isolate(); 113 DateCache* date_cache = isolate->date_cache(); 114 int64_t actual = date_cache->ToLocal(time); 115 int64_t expected = time + date_cache->GetLocalOffsetFromOS() + 116 date_cache->GetDaylightSavingsOffsetFromOS(time / 1000); 117 CHECK_EQ(actual, expected); 118 } 119 120 121 TEST(DaylightSavingsTime) { 122 LocalContext context; 123 v8::Isolate* isolate = context->GetIsolate(); 124 v8::HandleScope scope(isolate); 125 DateCacheMock::Rule rules[] = { 126 {0, 2, 0, 10, 0, 3600}, // DST from March to November in any year. 127 {2010, 2, 0, 7, 20, 3600}, // DST from March to August 20 in 2010. 128 {2010, 7, 20, 8, 10, 0}, // No DST from August 20 to September 10 in 2010. 129 {2010, 8, 10, 10, 0, 3600}, // DST from September 10 to November in 2010. 130 }; 131 132 int local_offset_ms = -36000000; // -10 hours. 133 134 DateCacheMock* date_cache = 135 new DateCacheMock(local_offset_ms, rules, ARRAY_SIZE(rules)); 136 137 reinterpret_cast<Isolate*>(isolate)->set_date_cache(date_cache); 138 139 int64_t start_of_2010 = TimeFromYearMonthDay(date_cache, 2010, 0, 1); 140 int64_t start_of_2011 = TimeFromYearMonthDay(date_cache, 2011, 0, 1); 141 int64_t august_20 = TimeFromYearMonthDay(date_cache, 2010, 7, 20); 142 int64_t september_10 = TimeFromYearMonthDay(date_cache, 2010, 8, 10); 143 CheckDST((august_20 + september_10) / 2); 144 CheckDST(september_10); 145 CheckDST(september_10 + 2 * 3600); 146 CheckDST(september_10 + 2 * 3600 - 1000); 147 CheckDST(august_20 + 2 * 3600); 148 CheckDST(august_20 + 2 * 3600 - 1000); 149 CheckDST(august_20); 150 // Check each day of 2010. 151 for (int64_t time = start_of_2011 + 2 * 3600; 152 time >= start_of_2010; 153 time -= DateCache::kMsPerDay) { 154 CheckDST(time); 155 CheckDST(time - 1000); 156 CheckDST(time + 1000); 157 } 158 // Check one day from 2010 to 2100. 159 for (int year = 2100; year >= 2010; year--) { 160 CheckDST(TimeFromYearMonthDay(date_cache, year, 5, 5)); 161 } 162 CheckDST((august_20 + september_10) / 2); 163 CheckDST(september_10); 164 CheckDST(september_10 + 2 * 3600); 165 CheckDST(september_10 + 2 * 3600 - 1000); 166 CheckDST(august_20 + 2 * 3600); 167 CheckDST(august_20 + 2 * 3600 - 1000); 168 CheckDST(august_20); 169 } 170