Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(751)

Side by Side Diff: runtime/lib/date_patch.dart

Issue 10857029: Revert "Sharing of sources for corelib date implementation between VM and" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/lib/date.dart ('k') | runtime/lib/lib_impl_sources.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 // Dart core library.
5
6 // VM implementation of DateImplementation.
7 patch class DateImplementation {
8 /* patch */ DateImplementation(int years,
9 [int month = 1,
10 int day = 1,
11 int hour = 0,
12 int minute = 0,
13 int second = 0,
14 int millisecond = 0,
15 bool isUtc = false])
16 : this.isUtc = isUtc,
17 this.millisecondsSinceEpoch = _brokenDownDateToMillisecondsSinceEpoch(
18 years, month, day, hour, minute, second, millisecond, isUtc) {
19 if (millisecondsSinceEpoch === null) throw new IllegalArgumentException();
20 if (isUtc === null) throw new IllegalArgumentException();
21 }
22
23 /* patch */ DateImplementation.now()
24 : isUtc = false,
25 millisecondsSinceEpoch = _getCurrentMs() {
26 }
27
28 /* patch */ String get timeZoneName() {
29 if (isUtc) return "UTC";
30 return _timeZoneName(millisecondsSinceEpoch);
31 }
32
33 /* patch */ Duration get timeZoneOffset() {
34 if (isUtc) return new Duration(0);
35 int offsetInSeconds = _timeZoneOffsetInSeconds(millisecondsSinceEpoch);
36 return new Duration(seconds: offsetInSeconds);
37 }
38
39 /* patch */ int get year() => _decomposeIntoYearMonthDay(_localDateInUtcMs)[0] ;
40
41 /* patch */ int get month() => _decomposeIntoYearMonthDay(_localDateInUtcMs)[1 ];
42
43 /* patch */ int get day() => _decomposeIntoYearMonthDay(_localDateInUtcMs)[2];
44
45 /* patch */ int get hour() {
46 int valueInHours = _flooredDivision(_localDateInUtcMs,
47 Duration.MILLISECONDS_PER_HOUR);
48 return valueInHours % Duration.HOURS_PER_DAY;
49 }
50
51 /* patch */ int get minute() {
52 int valueInMinutes = _flooredDivision(_localDateInUtcMs,
53 Duration.MILLISECONDS_PER_MINUTE);
54 return valueInMinutes % Duration.MINUTES_PER_HOUR;
55 }
56
57 /* patch */ int get second() {
58 // Seconds are unaffected by the timezone the user is in. So we can
59 // directly use the millisecondsSinceEpoch and not [_localDateInUtcMs].
60 int valueInSeconds =
61 _flooredDivision(millisecondsSinceEpoch,
62 Duration.MILLISECONDS_PER_SECOND);
63 return valueInSeconds % Duration.SECONDS_PER_MINUTE;
64 }
65
66 /* patch */ int get millisecond() {
67 // Milliseconds are unaffected by the timezone the user is in. So we can
68 // directly use the value and not the [_localDateInUtcValue].
69 return millisecondsSinceEpoch % Duration.MILLISECONDS_PER_SECOND;
70 }
71
72 /** Returns the weekday of [this]. In accordance with ISO 8601 a week
73 * starts with Monday. Monday has the value 1 up to Sunday with 7. */
74 /* patch */ int get weekday() {
75 int daysSince1970 =
76 _flooredDivision(_localDateInUtcMs, Duration.MILLISECONDS_PER_DAY);
77 // 1970-1-1 was a Thursday.
78 return ((daysSince1970 + Date.THU - Date.MON) % Date.DAYS_IN_WEEK) +
79 Date.MON;
80 }
81
82
83 /** The first list contains the days until each month in non-leap years. The
84 * second list contains the days in leap years. */
85 static final List<List<int>> _DAYS_UNTIL_MONTH =
86 const [const [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
87 const [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]];
88
89 // Returns the UTC year, month and day for the corresponding
90 // [millisecondsSinceEpoch].
91 // Code is adapted from V8.
92 static List<int> _decomposeIntoYearMonthDay(int millisecondsSinceEpoch) {
93 // TODO(floitsch): cache result.
94 final int DAYS_IN_4_YEARS = 4 * 365 + 1;
95 final int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1;
96 final int DAYS_IN_400_YEARS = 4 * DAYS_IN_100_YEARS + 1;
97 final int DAYS_1970_TO_2000 = 30 * 365 + 7;
98 final int DAYS_OFFSET = 1000 * DAYS_IN_400_YEARS + 5 * DAYS_IN_400_YEARS -
99 DAYS_1970_TO_2000;
100 final int YEARS_OFFSET = 400000;
101
102 int resultYear = 0;
103 int resultMonth = 0;
104 int resultDay = 0;
105
106 // Always round down.
107 int days = _flooredDivision(millisecondsSinceEpoch,
108 Duration.MILLISECONDS_PER_DAY);
109 days += DAYS_OFFSET;
110 resultYear = 400 * (days ~/ DAYS_IN_400_YEARS) - YEARS_OFFSET;
111 days = days.remainder(DAYS_IN_400_YEARS);
112 days--;
113 int yd1 = days ~/ DAYS_IN_100_YEARS;
114 days = days.remainder(DAYS_IN_100_YEARS);
115 resultYear += 100 * yd1;
116 days++;
117 int yd2 = days ~/ DAYS_IN_4_YEARS;
118 days = days.remainder(DAYS_IN_4_YEARS);
119 resultYear += 4 * yd2;
120 days--;
121 int yd3 = days ~/ 365;
122 days = days.remainder(365);
123 resultYear += yd3;
124
125 bool isLeap = (yd1 == 0 || yd2 != 0) && yd3 == 0;
126 if (isLeap) days++;
127
128 List<int> daysUntilMonth = _DAYS_UNTIL_MONTH[isLeap ? 1 : 0];
129 for (resultMonth = 12;
130 daysUntilMonth[resultMonth - 1] > days;
131 resultMonth--) {
132 // Do nothing.
133 }
134 resultDay = days - daysUntilMonth[resultMonth - 1] + 1;
135 return <int>[resultYear, resultMonth, resultDay];
136 }
137
138 /**
139 * Returns the amount of milliseconds in UTC that represent the same values
140 * as [this].
141 *
142 * Say [:t:] is the result of this function, then
143 * * [:this.year == new Date.fromMillisecondsSinceEpoch(t, true).year:],
144 * * [:this.month == new Date.fromMillisecondsSinceEpoch(t, true).month:],
145 * * [:this.day == new Date.fromMillisecondsSinceEpoch(t, true).day:],
146 * * [:this.hour == new Date.fromMillisecondsSinceEpoch(t, true).hour:],
147 * * ...
148 *
149 * Daylight savings is computed as if the date was computed in [1970..2037].
150 * If [this] lies outside this range then it is a year with similar
151 * properties (leap year, weekdays) is used instead.
152 */
153 int get _localDateInUtcMs() {
154 int ms = millisecondsSinceEpoch;
155 if (isUtc) return ms;
156 int offset =
157 _timeZoneOffsetInSeconds(ms) * Duration.MILLISECONDS_PER_SECOND;
158 return ms + offset;
159 }
160
161 static int _flooredDivision(int a, int b) {
162 return (a - (a < 0 ? b - 1 : 0)) ~/ b;
163 }
164
165 // Returns the days since 1970 for the start of the given [year].
166 // [year] may be before epoch.
167 static int _dayFromYear(int year) {
168 return 365 * (year - 1970)
169 + _flooredDivision(year - 1969, 4)
170 - _flooredDivision(year - 1901, 100)
171 + _flooredDivision(year - 1601, 400);
172 }
173
174 static bool _isLeapYear(y) {
175 return (y.remainder(4) == 0) &&
176 ((y.remainder(100) != 0) || (y.remainder(400) == 0));
177 }
178
179 static _brokenDownDateToMillisecondsSinceEpoch(
180 int years, int month, int day,
181 int hour, int minute, int second, int millisecond,
182 bool isUtc) {
183 if ((month < 1) || (month > 12)) return null;
184 if ((day < 1) || (day > 31)) return null;
185 // Leap seconds can lead to hour == 24.
186 if ((hour < 0) || (hour > 24)) return null;
187 if ((hour == 24) && ((minute != 0) || (second != 0))) return null;
188 if ((minute < 0) || (minute > 59)) return null;
189 if ((second < 0) || (second > 59)) return null;
190 if ((millisecond < 0) || (millisecond > 999)) return null;
191
192 // First compute the seconds in UTC, independent of the [isUtc] flag. If
193 // necessary we will add the time-zone offset later on.
194 int days = day - 1;
195 days += _DAYS_UNTIL_MONTH[_isLeapYear(years) ? 1 : 0][month - 1];
196 days += _dayFromYear(years);
197 int millisecondsSinceEpoch = days * Duration.MILLISECONDS_PER_DAY +
198 hour * Duration.MILLISECONDS_PER_HOUR +
199 minute * Duration.MILLISECONDS_PER_MINUTE+
200 second * Duration.MILLISECONDS_PER_SECOND +
201 millisecond;
202
203 // Since [_timeZoneOffsetInSeconds] will crash if the input is far out of
204 // the valid range we do a preliminary test that weeds out values that can
205 // not become valid even with timezone adjustments.
206 // The timezone adjustment is always less than a day, so adding a security
207 // margin of one day should be enough.
208 if (millisecondsSinceEpoch.abs() >
209 (_MAX_MILLISECONDS_SINCE_EPOCH + Duration.MILLISECONDS_PER_DAY)) {
210 return null;
211 }
212
213 if (!isUtc) {
214 // Note that we need to remove the local timezone adjustement before
215 // asking for the correct zone offset.
216 int adjustment = _localTimeZoneAdjustmentInSeconds() *
217 Duration.MILLISECONDS_PER_SECOND;
218 int zoneOffset =
219 _timeZoneOffsetInSeconds(millisecondsSinceEpoch - adjustment);
220 millisecondsSinceEpoch -= zoneOffset * Duration.MILLISECONDS_PER_SECOND;
221 }
222 if (millisecondsSinceEpoch.abs() > _MAX_MILLISECONDS_SINCE_EPOCH) {
223 return null;
224 }
225 return millisecondsSinceEpoch;
226 }
227
228 static int _weekDay(y) {
229 // 1/1/1970 was a Thursday.
230 return (_dayFromYear(y) + 4) % 7;
231 }
232
233 /**
234 * Returns a year in the range 2008-2035 matching
235 * * leap year, and
236 * * week day of first day.
237 *
238 * Leap seconds are ignored.
239 * Adapted from V8's date implementation. See ECMA 262 - 15.9.1.9.
240 */
241 static _equivalentYear(int year) {
242 // Returns the week day (in range 0 - 6).
243 // 1/1/1956 was a Sunday (i.e. weekday 0). 1956 was a leap-year.
244 // 1/1/1967 was a Sunday (i.e. weekday 0).
245 // Without leap years a subsequent year has a week day + 1 (for example
246 // 1/1/1968 was a Monday). With leap-years it jumps over one week day
247 // (e.g. 1/1/1957 was a Tuesday).
248 // After 12 years the weekdays have advanced by 12 days + 3 leap days =
249 // 15 days. 15 % 7 = 1. So after 12 years the week day has always
250 // (now independently of leap-years) advanced by one.
251 // weekDay * 12 gives thus a year starting with the wanted weekDay.
252 int recentYear = (_isLeapYear(year) ? 1956 : 1967) + (_weekDay(year) * 12);
253 // Close to the year 2008 the calendar cycles every 4 * 7 years (4 for the
254 // leap years, 7 for the weekdays).
255 // Find the year in the range 2008..2037 that is equivalent mod 28.
256 return 2008 + (recentYear - 2008) % 28;
257 }
258
259 /**
260 * Returns the UTC year for the corresponding [secondsSinceEpoch].
261 * It is relatively fast for values in the range 0 to year 2098.
262 *
263 * Code is adapted from V8.
264 */
265 static int _yearsFromSecondsSinceEpoch(int secondsSinceEpoch) {
266 final int DAYS_IN_4_YEARS = 4 * 365 + 1;
267 final int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1;
268 final int DAYS_YEAR_2098 = DAYS_IN_100_YEARS + 6 * DAYS_IN_4_YEARS;
269
270 int days = secondsSinceEpoch ~/ Duration.SECONDS_PER_DAY;
271 if (days > 0 && days < DAYS_YEAR_2098) {
272 // According to V8 this fast case works for dates from 1970 to 2099.
273 return 1970 + (4 * days + 2) ~/ DAYS_IN_4_YEARS;
274 }
275 int ms = secondsSinceEpoch * Duration.MILLISECONDS_PER_SECOND;
276 return _decomposeIntoYearMonthDay(ms)[0];
277 }
278
279 /**
280 * Returns a date in seconds that is equivalent to the current date. An
281 * equivalent date has the same fields ([:month:], [:day:], etc.) as the
282 * [this], but the [:year:] is in the range [1970..2037].
283 *
284 * * The time since the beginning of the year is the same.
285 * * If [this] is in a leap year then the returned seconds are in a leap
286 * year, too.
287 * * The week day of [this] is the same as the one for the returned date.
288 */
289 static int _equivalentSeconds(int millisecondsSinceEpoch) {
290 final int CUT_OFF_SECONDS = 2100000000;
291
292 int secondsSinceEpoch = _flooredDivision(millisecondsSinceEpoch,
293 Duration.MILLISECONDS_PER_SECOND);
294
295 if (secondsSinceEpoch < 0 || secondsSinceEpoch >= CUT_OFF_SECONDS) {
296 int year = _yearsFromSecondsSinceEpoch(secondsSinceEpoch);
297 int days = _dayFromYear(year);
298 int equivalentYear = _equivalentYear(year);
299 int equivalentDays = _dayFromYear(equivalentYear);
300 int diffDays = equivalentDays - days;
301 secondsSinceEpoch += diffDays * Duration.SECONDS_PER_DAY;
302 }
303 return secondsSinceEpoch;
304 }
305
306 static int _timeZoneOffsetInSeconds(int millisecondsSinceEpoch) {
307 int equivalentSeconds = _equivalentSeconds(millisecondsSinceEpoch);
308 return _timeZoneOffsetInSecondsForClampedSeconds(equivalentSeconds);
309 }
310
311 static String _timeZoneName(int millisecondsSinceEpoch) {
312 int equivalentSeconds = _equivalentSeconds(millisecondsSinceEpoch);
313 return _timeZoneNameForClampedSeconds(equivalentSeconds);
314 }
315
316 // Natives
317 static int _getCurrentMs() native "DateNatives_currentTimeMillis";
318
319 static String _timeZoneNameForClampedSeconds(int secondsSinceEpoch)
320 native "DateNatives_timeZoneName";
321
322 static int _timeZoneOffsetInSecondsForClampedSeconds(int secondsSinceEpoch)
323 native "DateNatives_timeZoneOffsetInSeconds";
324
325 static int _localTimeZoneAdjustmentInSeconds()
326 native "DateNatives_localTimeZoneAdjustmentInSeconds";
327 }
OLDNEW
« no previous file with comments | « runtime/lib/date.dart ('k') | runtime/lib/lib_impl_sources.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698