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

Side by Side Diff: dart/frog/leg/lib/mockimpl.dart

Issue 9424027: Implement Date. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 10 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
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 // Mocks of classes and interfaces that Leg cannot read directly. 5 // Mocks of classes and interfaces that Leg cannot read directly.
6 6
7 // TODO(ahe): Remove this file. 7 // TODO(ahe): Remove this file.
8 8
9 class JSSyntaxRegExp implements RegExp { 9 class JSSyntaxRegExp implements RegExp {
10 JSSyntaxRegExp(String pattern, 10 JSSyntaxRegExp(String pattern,
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 74
75 bool operator ==(Object other) { 75 bool operator ==(Object other) {
76 if (!(other is TimeZoneImplementation)) return false; 76 if (!(other is TimeZoneImplementation)) return false;
77 return isUtc == other.isUtc; 77 return isUtc == other.isUtc;
78 } 78 }
79 79
80 final bool isUtc; 80 final bool isUtc;
81 } 81 }
82 82
83 class DateImplementation implements Date { 83 class DateImplementation implements Date {
84 final int value;
85 final TimeZoneImplementation timeZone;
86
84 factory DateImplementation(int years, 87 factory DateImplementation(int years,
85 int month, 88 int month,
86 int day, 89 int day,
87 int hours, 90 int hours,
88 int minutes, 91 int minutes,
89 int seconds, 92 int seconds,
90 int milliseconds) { 93 int milliseconds) {
91 return new DateImplementation.withTimeZone( 94 return new DateImplementation.withTimeZone(
92 years, month, day, 95 years, month, day,
93 hours, minutes, seconds, milliseconds, 96 hours, minutes, seconds, milliseconds,
94 new TimeZoneImplementation.local()); 97 new TimeZoneImplementation.local());
95 } 98 }
96 99
97 DateImplementation.withTimeZone(int years, 100 DateImplementation.withTimeZone(int years,
98 int month, 101 int month,
99 int day, 102 int day,
100 int hours, 103 int hours,
101 int minutes, 104 int minutes,
102 int seconds, 105 int seconds,
103 int milliseconds, 106 int milliseconds,
104 TimeZoneImplementation timeZone) 107 TimeZoneImplementation timeZone)
105 : timeZone = timeZone, 108 : this.timeZone = checkNull(timeZone),
106 value = brokenDownDateToMillisecondsSinceEpoch_( 109 value = Primitives.valueFromDecomposedDate(years, month, day,
107 years, month, day, hours, minutes, seconds, milliseconds, 110 hours, minutes, seconds,
108 timeZone.isUtc); 111 milliseconds,
112 timeZone.isUtc) {
113 _asJs();
114 }
109 115
110 DateImplementation.now() 116 DateImplementation.now()
111 : timeZone = new TimeZone.local(), 117 : timeZone = new TimeZone.local(),
112 value = Primitives.getCurrentMs(); 118 value = Primitives.dateNow() {
113 119 _asJs();
114 factory DateImplementation.fromString(String formattedString) {
115 int substringToNumber(String str, int from, int to) {
116 int result = 0;
117 for (int i = from; i < to; i++) {
118 result = result * 10 + str.charCodeAt(i) - "0".charCodeAt(0);
119 }
120 return result;
121 }
122
123 // TODO(floitsch): improve DateImplementation parsing.
124 // Parse ISO 8601: "2011-05-14 00:37:18.231Z".
125 int yearMonthSeparator = formattedString.indexOf("-", 0);
126 if (yearMonthSeparator < 0) throw "UNIMPLEMENTED";
127 int monthDaySeparator =
128 formattedString.indexOf("-", yearMonthSeparator + 1);
129 if (monthDaySeparator < 0) throw "UNIMPLEMENTED";
130 int dateTimeSeparator = formattedString.indexOf(" ", monthDaySeparator + 1);
131 if (dateTimeSeparator < 0) throw "UNIMPLEMENTED";
132 int hoursMinutesSeparator =
133 formattedString.indexOf(":", dateTimeSeparator + 1);
134 if (hoursMinutesSeparator < 0) throw "UNIMPLEMENTED";
135 int minutesSecondsSeparator =
136 formattedString.indexOf(":", hoursMinutesSeparator + 1);
137 if (minutesSecondsSeparator < 0) throw "UNIMPLEMENTED";
138 int secondsMillisecondsSeparator =
139 formattedString.indexOf(".", minutesSecondsSeparator + 1);
140 bool isUtc = formattedString.endsWith("Z");
141 int end = formattedString.length - (isUtc ? 1 : 0);
142 if (secondsMillisecondsSeparator < 0) secondsMillisecondsSeparator = end;
143
144 int year = substringToNumber(formattedString, 0, yearMonthSeparator);
145 int month = substringToNumber(formattedString,
146 yearMonthSeparator + 1,
147 monthDaySeparator);
148 int day = substringToNumber(formattedString,
149 monthDaySeparator + 1,
150 dateTimeSeparator);
151 int hours = substringToNumber(formattedString,
152 dateTimeSeparator + 1,
153 hoursMinutesSeparator);
154 int minutes = substringToNumber(formattedString,
155 hoursMinutesSeparator + 1,
156 minutesSecondsSeparator);
157 int seconds = substringToNumber(formattedString,
158 minutesSecondsSeparator + 1,
159 secondsMillisecondsSeparator);
160 int milliseconds = substringToNumber(formattedString,
161 secondsMillisecondsSeparator + 1,
162 end);
163 TimeZone timeZone = (isUtc ? const TimeZone.utc() : new TimeZone.local());
164 return new DateImplementation.withTimeZone(
165 year, month, day, hours, minutes, seconds, milliseconds, timeZone);
166 } 120 }
167 121
168 const DateImplementation.fromEpoch(int this.value, 122 DateImplementation.fromString(String formattedString)
169 TimeZone this.timeZone); 123 : timeZone = new TimeZone.local(),
124 value = Primitives.valueFromDateString(formattedString) {
125 _asJs();
126 }
170 127
171 bool operator ==(Object other) { 128 const DateImplementation.fromEpoch(this.value, this.timeZone);
129
130 bool operator ==(other) {
172 if (!(other is DateImplementation)) return false; 131 if (!(other is DateImplementation)) return false;
173 return value == other.value && timeZone == other.timeZone; 132 return (value == other.value) && (timeZone == other.timeZone);
174 } 133 }
175 134
176 int compareTo(Date other) { 135 int compareTo(Date other) {
136 checkNull(other);
177 return value.compareTo(other.value); 137 return value.compareTo(other.value);
178 } 138 }
179 139
180 Date changeTimeZone(TimeZone targetTimeZone) { 140 Date changeTimeZone(TimeZone targetTimeZone) {
181 if (targetTimeZone === null) { 141 if (targetTimeZone == null) {
182 targetTimeZone = new TimeZoneImplementation.local(); 142 targetTimeZone = new TimeZoneImplementation.local();
183 } 143 }
184 return new Date.fromEpoch(value, targetTimeZone); 144 return new Date.fromEpoch(value, targetTimeZone);
185 } 145 }
186 146
187 int get year() { 147 int get year() => Primitives.getYear(this);
188 int secondsSinceEpoch = secondsSinceEpoch_;
189 // According to V8 some library calls have troubles with negative values.
190 // Therefore clamp to 0 - year 2035 (which is less than the size of 32bit).
191 if (secondsSinceEpoch >= 0 && secondsSinceEpoch < SECONDS_YEAR_2035_) {
192 return Primitives.getYear(secondsSinceEpoch, timeZone.isUtc);
193 }
194 148
195 // Approximate the result. We don't take timeZone into account. 149 int get month() => Primitives.getMonth(this);
196 int approximateYear = yearsFromSecondsSinceEpoch_(secondsSinceEpoch);
197 int equivalentYear = equivalentYear_(approximateYear);
198 int y = Primitives.getYear(equivalentSeconds_(secondsSinceEpoch_),
199 timeZone.isUtc);
200 return approximateYear + (y - equivalentYear);
201 }
202 150
203 int get month() => Primitives.getMonth(equivalentSeconds_(secondsSinceEpoch_), 151 int get day() => Primitives.getDay(this);
204 timeZone.isUtc);
205 152
206 int get day() => Primitives.getDay(equivalentSeconds_(secondsSinceEpoch_), 153 int get hours() => Primitives.getHours(this);
207 timeZone.isUtc);
208 154
209 int get hours() => Primitives.getHours(equivalentSeconds_(secondsSinceEpoch_), 155 int get minutes() => Primitives.getMinutes(this);
210 timeZone.isUtc);
211 156
212 int get minutes() => 157 int get seconds() => Primitives.getSeconds(this);
213 Primitives.getMinutes(equivalentSeconds_(secondsSinceEpoch_),
214 timeZone.isUtc);
215 158
216 int get seconds() => 159 int get milliseconds() => Primitives.getMilliseconds(this);
217 Primitives.getSeconds(equivalentSeconds_(secondsSinceEpoch_),
218 timeZone.isUtc);
219
220 int get milliseconds() {
221 return value % Duration.MILLISECONDS_PER_SECOND;
222 }
223
224 int get secondsSinceEpoch_() {
225 // Always round down.
226 if (value < 0) {
227 return (value + 1) ~/ Duration.MILLISECONDS_PER_SECOND - 1;
228 } else {
229 return value ~/ Duration.MILLISECONDS_PER_SECOND;
230 }
231 }
232 160
233 int get weekday() { 161 int get weekday() {
234 final Date unixTimeStart = 162 // Adjust by one because JS weeks start on Sunday.
ngeoffray 2012/02/21 12:08:07 I'd prefer moving this adjustment in Primitives. A
235 new Date.withTimeZone(1970, 1, 1, 0, 0, 0, 0, timeZone); 163 var day = Primitives.getWeekday(this);
236 int msSince1970 = this.difference(unixTimeStart).inMilliseconds; 164 return (day + 6) % 7;
237 // Adjust the milliseconds to avoid problems with summer-time.
238 if (hours < 2) {
239 msSince1970 += 2 * Duration.MILLISECONDS_PER_HOUR;
240 }
241 // Compute the floor of msSince1970 / Duration.MS_PER_DAY.
242 int daysSince1970;
243 if (msSince1970 >= 0) {
244 daysSince1970 = msSince1970 ~/ Duration.MILLISECONDS_PER_DAY;
245 } else {
246 daysSince1970 = (msSince1970 - Duration.MILLISECONDS_PER_DAY + 1) ~/
247 Duration.MILLISECONDS_PER_DAY;
248 }
249 // 1970-1-1 was a Thursday.
250 return ((daysSince1970 + Date.THU) % Date.DAYS_IN_WEEK);
251 } 165 }
252 166
253 bool isLocalTime() { 167 bool isLocalTime() {
254 return !timeZone.isUtc; 168 return !timeZone.isUtc;
255 } 169 }
256 170
257 bool isUtc() { 171 bool isUtc() {
258 return timeZone.isUtc; 172 return timeZone.isUtc;
259 } 173 }
260 174
261 String toString() { 175 String toString() {
262 String threeDigits(int n) {
263 if (n >= 100) return "${n}";
264 if (n > 10) return "0${n}";
265 return "00${n}";
266 }
267 String twoDigits(int n) {
268 if (n >= 10) return "${n}";
269 return "0${n}";
270 }
271
272 String m = twoDigits(month); 176 String m = twoDigits(month);
273 String d = twoDigits(day); 177 String d = twoDigits(day);
274 String h = twoDigits(hours); 178 String h = twoDigits(hours);
275 String min = twoDigits(minutes); 179 String min = twoDigits(minutes);
276 String sec = twoDigits(seconds); 180 String sec = twoDigits(seconds);
277 String ms = threeDigits(milliseconds); 181 String ms = threeDigits(milliseconds);
278 if (timeZone.isUtc) { 182 if (timeZone.isUtc) {
279 return "$year-$m-$d $h:$min:$sec.${ms}Z"; 183 return "$year-$m-$d $h:$min:$sec.${ms}Z";
280 } else { 184 } else {
281 return "$year-$m-$d $h:$min:$sec.$ms"; 185 return "$year-$m-$d $h:$min:$sec.$ms";
282 } 186 }
283 } 187 }
284 188
285 // Adds the [duration] to this Date instance. 189 // Adds the [duration] to this Date instance.
286 Date add(Duration duration) { 190 Date add(Duration duration) {
191 checkNull(duration);
287 return new DateImplementation.fromEpoch(value + duration.inMilliseconds, 192 return new DateImplementation.fromEpoch(value + duration.inMilliseconds,
288 timeZone); 193 timeZone);
289 } 194 }
290 195
291 // Subtracts the [duration] from this Date instance. 196 // Subtracts the [duration] from this Date instance.
292 Date subtract(Duration duration) { 197 Date subtract(Duration duration) {
198 checkNull(duration);
293 return new DateImplementation.fromEpoch(value - duration.inMilliseconds, 199 return new DateImplementation.fromEpoch(value - duration.inMilliseconds,
294 timeZone); 200 timeZone);
295 } 201 }
296 202
297 // Returns a [Duration] with the difference of [this] and [other]. 203 // Returns a [Duration] with the difference of [this] and [other].
298 Duration difference(Date other) { 204 Duration difference(Date other) {
299 return new DurationImplementation(milliseconds: value - other.value); 205 checkNull(other);
206 return new Duration(milliseconds: value - other.value);
300 } 207 }
301 208
302 final int value; 209 // Lazily keep a JS Date stored in the dart object.
303 final TimeZoneImplementation timeZone; 210 var _asJs() => Primitives.lazyAsJsDate(this);
304
305 static final int SECONDS_YEAR_2035_ = 2051222400;
306
307 // Returns the UTC year for the corresponding [secondsSinceEpoch].
308 // It is relatively fast for values in the range 0 to year 2098.
309 // Code is adapted from V8.
310 static int yearsFromSecondsSinceEpoch_(int secondsSinceEpoch) {
311 final int DAYS_IN_4_YEARS = 4 * 365 + 1;
312 final int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1;
313 final int DAYS_IN_400_YEARS = 4 * DAYS_IN_100_YEARS + 1;
314 final int DAYS_1970_TO_2000 = 30 * 365 + 7;
315 final int DAYS_OFFSET = 1000 * DAYS_IN_400_YEARS + 5 * DAYS_IN_400_YEARS -
316 DAYS_1970_TO_2000;
317 final int YEARS_OFFSET = 400000;
318 final int DAYS_YEAR_2098 = DAYS_IN_100_YEARS + 6 * DAYS_IN_4_YEARS;
319
320 int days = secondsSinceEpoch ~/ Duration.SECONDS_PER_DAY;
321 if (days > 0 && days < DAYS_YEAR_2098) {
322 // According to V8 this fast case works for dates from 1970 to 2099.
323 return 1970 + (4 * days + 2) ~/ DAYS_IN_4_YEARS;
324 } else {
325 days += DAYS_OFFSET;
326 int result = 400 * (days ~/ DAYS_IN_400_YEARS) - YEARS_OFFSET;
327 days = days.remainder(DAYS_IN_400_YEARS);
328 days--;
329 int yd1 = days ~/ DAYS_IN_100_YEARS;
330 days = days.remainder(DAYS_IN_100_YEARS);
331 result += 100 * yd1;
332 days++;
333 int yd2 = days ~/ DAYS_IN_4_YEARS;
334 days = days.remainder(DAYS_IN_4_YEARS);
335 result += 4 * yd2;
336 days--;
337 int yd3 = days ~/ 365;
338 days = days.remainder(365);
339 result += yd3;
340 return result;
341 }
342 }
343
344 // Given [secondsSinceEpoch] returns seconds such that they are at the same
345 // time in an equivalent year (see [equivalentYear_]).
346 // Leap seconds are ignored.
347 static int equivalentSeconds_(int secondsSinceEpoch) {
348 if (secondsSinceEpoch >= 0 && secondsSinceEpoch < SECONDS_YEAR_2035_) {
349 return secondsSinceEpoch;
350 }
351 int year = yearsFromSecondsSinceEpoch_(secondsSinceEpoch);
352 int days = dayFromYear_(year);
353 int equivalentYear = equivalentYear_(year);
354 int equivalentDays = dayFromYear_(equivalentYear);
355 int diffDays = equivalentDays - days;
356 return secondsSinceEpoch + diffDays * Duration.SECONDS_PER_DAY;
357 }
358
359 // Returns the days since 1970 for the start of the given [year].
360 // [year] may be before epoch.
361 static int dayFromYear_(int year) {
362 int flooredDivision(int a, int b) {
363 return (a - (a < 0 ? b - 1 : 0)) ~/ b;
364 }
365
366 return 365 * (year - 1970)
367 + flooredDivision(year - 1969, 4)
368 - flooredDivision(year - 1901, 100)
369 + flooredDivision(year - 1601, 400);
370 }
371
372 // Returns a year in the range 2008-2035 matching
373 // - leap year, and
374 // - week day of first day.
375 // Leap seconds are ignored.
376 // Adapted from V8's date implementation. See ECMA 262 - 15.9.1.9.
377 static equivalentYear_(int year) {
378 // Returns 1 if in leap year. 0 otherwise.
379 bool inLeapYear(year) {
380 return (year.remainder(4) == 0) &&
381 ((year.remainder(100) != 0) || (year.remainder(400) == 0));
382 }
383
384 // Returns the week day (in range 0 - 6).
385 int weekDay(year) {
386 // 1/1/1970 was a Thursday.
387 return (dayFromYear_(year) + 4) % 7;
388 }
389 // 1/1/1956 was a Sunday (i.e. weekday 0). 1956 was a leap-year.
390 // 1/1/1967 was a Sunday (i.e. weekday 0).
391 // Without leap years a subsequent year has a week day + 1 (for example
392 // 1/1/1968 was a Monday). With leap-years it jumps over one week day
393 // (e.g. 1/1/1957 was a Tuesday).
394 // After 12 years the weekdays have advanced by 12 days + 3 leap days =
395 // 15 days. 15 % 7 = 1. So after 12 years the week day has always
396 // (now independently of leap-years) advanced by one.
397 // weekDay * 12 gives thus a year starting with the wanted weekDay.
398 int recentYear = (inLeapYear(year) ? 1956 : 1967) + (weekDay(year) * 12);
399 // Close to the year 2008 the calendar cycles every 4 * 7 years (4 for the
400 // leap years, 7 for the weekdays).
401 // Find the year in the range 2008..2037 that is equivalent mod 28.
402 return 2008 + (recentYear - 2008) % 28;
403 }
404
405 static brokenDownDateToMillisecondsSinceEpoch_(
406 int years, int month, int day,
407 int hours, int minutes, int seconds, int milliseconds,
408 bool isUtc) {
409 if ((month < 1) || (month > 12)) {
410 throw new IllegalArgumentException();
411 }
412 if ((day < 1) || (day > 31)) {
413 throw new IllegalArgumentException();
414 }
415 // Leap seconds can lead to hours == 24.
416 if ((hours < 0) || (hours > 24)) {
417 throw new IllegalArgumentException();
418 }
419 if ((hours == 24) && ((minutes != 0) || (seconds != 0))) {
420 throw new IllegalArgumentException();
421 }
422 if ((minutes < 0) || (minutes > 59)) {
423 throw new IllegalArgumentException();
424 }
425 if ((seconds < 0) || (seconds > 59)) {
426 throw new IllegalArgumentException();
427 }
428 if ((milliseconds < 0) || (milliseconds > 999)) {
429 throw new IllegalArgumentException();
430 }
431 int equivalentYear;
432 int offsetInSeconds;
433 // According to V8 some library calls have troubles with negative values.
434 // Therefore clamp to 1970 - year 2035 (which is less than the size of
435 // 32bit).
436 // We exclude the year 1970 when the time is not UTC, since the epoch
437 // value could then be negative.
438 if (years < (isUtc ? 1970 : 1971) || years > 2035) {
439 equivalentYear = equivalentYear_(years);
440 int offsetInDays = (dayFromYear_(years) - dayFromYear_(equivalentYear));
441 // Leap seconds are ignored.
442 offsetInSeconds = offsetInDays * Duration.SECONDS_PER_DAY;
443 } else {
444 equivalentYear = years;
445 offsetInSeconds = 0;
446 }
447 int secondsSinceEpoch = Primitives.brokenDownDateToSecondsSinceEpoch(
448 equivalentYear, month, day, hours, minutes, seconds, isUtc);
449 int adjustedSeconds = secondsSinceEpoch + offsetInSeconds;
450 return adjustedSeconds * Duration.MILLISECONDS_PER_SECOND + milliseconds;
451 }
452 } 211 }
453 212
454 class ListFactory<E> implements List<E> { 213 class ListFactory<E> implements List<E> {
455 factory List([int length]) => Primitives.newList(length); 214 factory List([int length]) => Primitives.newList(length);
456 factory List.from(Iterable<E> other) { 215 factory List.from(Iterable<E> other) {
457 List<E> result = new List<E>(); 216 List<E> result = new List<E>();
458 Iterator<E> iterator = other.iterator(); 217 Iterator<E> iterator = other.iterator();
459 while (iterator.hasNext()) { 218 while (iterator.hasNext()) {
460 result.add(iterator.next()); 219 result.add(iterator.next());
461 } 220 }
462 return result; 221 return result;
463 } 222 }
464 } 223 }
224
225 class DurationImplementation implements Duration {
226 final int inMilliseconds;
227
228 const DurationImplementation([int days = 0,
229 int hours = 0,
230 int minutes = 0,
231 int seconds = 0,
232 int milliseconds = 0])
233 : inMilliseconds = days * Duration.MILLISECONDS_PER_DAY +
234 hours * Duration.MILLISECONDS_PER_HOUR +
235 minutes * Duration.MILLISECONDS_PER_MINUTE +
236 seconds * Duration.MILLISECONDS_PER_SECOND +
237 milliseconds;
238
239 int get inDays() {
240 return inMilliseconds ~/ Duration.MILLISECONDS_PER_DAY;
241 }
242
243 int get inHours() {
244 return inMilliseconds ~/ Duration.MILLISECONDS_PER_HOUR;
245 }
246
247 int get inMinutes() {
248 return inMilliseconds ~/ Duration.MILLISECONDS_PER_MINUTE;
249 }
250
251 int get inSeconds() {
252 return inMilliseconds ~/ Duration.MILLISECONDS_PER_SECOND;
253 }
254
255 bool operator ==(other) {
256 if (other is !Duration) return false;
257 return inMilliseconds == other.inMilliseconds;
258 }
259
260 int hashCode() {
261 return inMilliseconds.hashCode();
262 }
263
264 int compareTo(Duration other) {
265 return inMilliseconds.compareTo(other.inMilliseconds);
266 }
267
268 String toString() {
269 if (inMilliseconds < 0) {
270 Duration duration =
271 new DurationImplementation(milliseconds: -inMilliseconds);
272 return "-${duration}";
273 }
274 String twoDigitMinutes =
275 twoDigits(inMinutes.remainder(Duration.MINUTES_PER_HOUR));
276 String twoDigitSeconds =
277 twoDigits(inSeconds.remainder(Duration.SECONDS_PER_MINUTE));
278 String threeDigitMs =
279 threeDigits(inMilliseconds.remainder(Duration.MILLISECONDS_PER_SECOND));
280 return "${inHours}:${twoDigitMinutes}:${twoDigitSeconds}.${threeDigitMs}";
281 }
282 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698