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

Side by Side Diff: frog/lib/date_implementation.dart

Issue 9568011: Unify Date.fromString and support more Iso 8601. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Improve parseInt. Created 8 years, 9 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) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 // TODO(jmesserly): the native class should be the real JS Date. 5 // TODO(jmesserly): the native class should be the real JS Date.
6 // TODO(jimhug): Making the date value non-lazy might be a good path there. 6 // TODO(jimhug): Making the date value non-lazy might be a good path there.
7 class DateImplementation implements Date { 7 class DateImplementation implements Date {
8 final int value; 8 final int value;
9 final TimeZoneImplementation timeZone; 9 final TimeZoneImplementation timeZone;
10 10
(...skipping 15 matching lines...) Expand all
26 int day, 26 int day,
27 int hours, 27 int hours,
28 int minutes, 28 int minutes,
29 int seconds, 29 int seconds,
30 int milliseconds, 30 int milliseconds,
31 TimeZoneImplementation timeZone) 31 TimeZoneImplementation timeZone)
32 : this.timeZone = timeZone, 32 : this.timeZone = timeZone,
33 value = _valueFromDecomposed(years, month, day, 33 value = _valueFromDecomposed(years, month, day,
34 hours, minutes, seconds, milliseconds, 34 hours, minutes, seconds, milliseconds,
35 timeZone.isUtc) { 35 timeZone.isUtc) {
36 if (value === null) throw new IllegalArgumentException();
36 _asJs(); 37 _asJs();
37 } 38 }
38 39
39 DateImplementation.now() 40 DateImplementation.now()
40 : timeZone = new TimeZone.local(), 41 : timeZone = new TimeZone.local(),
41 value = _now() { 42 value = _now() {
42 _asJs(); 43 _asJs();
43 } 44 }
44 45
45 factory DateImplementation.fromString(String formattedString) { 46 factory DateImplementation.fromString(String formattedString) {
46 // JavaScript's parse function is not specified and there are differences 47 // Read in (a subset of) ISO 8601.
47 // between the different implementations. Make sure we can at least read in 48 // Examples:
48 // Dart's output: try to read in (a subset of) ISO 8601 first. If that fails 49 // - "2012-02-27 13:27:00"
49 // fall back to JavaScript's implementation. 50 // - "2012-02-27 13:27:00.423z"
50 final RegExp re = 51 // - "20120227 13:27:00"
51 const RegExp(@'^([+-]?\d?\d\d\d\d)-?(\d\d)-?(\d\d) (\d\d):(\d\d):(\d\d)( ?:.(\d{1,3}))? ?([zZ]?)$'); 52 // - "20120227T132700"
53 // - "20120227"
54 // - "2012-02-27T14Z"
55 // - "-123450101 00:00:00 Z" // In the year -12345.
56 final RegExp re = const RegExp(
57 @'^([+-]?\d?\d\d\d\d)-?(\d\d)-?(\d\d)' + // The day part.
58 @'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:.(\d{1,5}))?)?)? ?([zZ])?)?$');
52 Match match = re.firstMatch(formattedString); 59 Match match = re.firstMatch(formattedString);
53 if (match !== null) { 60 if (match !== null) {
61 int parseIntOrZero(String matched) {
62 // TODO(floitsch): we should not need to test against the empty string.
63 if (matched === null || matched == "") return 0;
64 return Math.parseInt(matched);
65 }
66
54 int years = Math.parseInt(match[1]); 67 int years = Math.parseInt(match[1]);
55 int month = Math.parseInt(match[2]); 68 int month = Math.parseInt(match[2]);
56 int day = Math.parseInt(match[3]); 69 int day = Math.parseInt(match[3]);
57 int hours = Math.parseInt(match[4]); 70 int hours = parseIntOrZero(match[4]);
58 int minutes = Math.parseInt(match[5]); 71 int minutes = parseIntOrZero(match[5]);
59 int seconds = Math.parseInt(match[6]); 72 int seconds = parseIntOrZero(match[6]);
60 int milliseconds = 0; 73 bool addOneMillisecond = false;
61 if (match[7] !== null) { 74 int milliseconds = parseIntOrZero(match[7]);
62 milliseconds = Math.parseInt(match[7]); 75 if (milliseconds != 0) {
63 if (match[7].length == 1) { 76 if (match[7].length == 1) {
64 milliseconds *= 100; 77 milliseconds *= 100;
65 } else if (match[7].length == 2) { 78 } else if (match[7].length == 2) {
66 milliseconds *= 10; 79 milliseconds *= 10;
80 } else if (match[7].length == 3) {
81 // Do nothing.
82 } else if (match[7].length == 4) {
83 addOneMillisecond = ((milliseconds % 10) >= 5);
84 milliseconds ~/= 10;
67 } else { 85 } else {
68 assert(match[7].length == 3); 86 assert(match[7].length == 5);
87 addOneMillisecond = ((milliseconds %100) >= 50);
kasperl 2012/03/02 13:34:10 %100 -> % 100
floitsch 2012/03/02 17:00:29 Done.
88 milliseconds ~/= 100;
89 }
90 if (addOneMillisecond && milliseconds < 999) {
91 addOneMillisecond = false;
92 milliseconds++;
69 } 93 }
70 } 94 }
95 // TODO(floitsch): we should not need to test against the empty string.
71 bool isUtc = (match[8] !== null) && (match[8] != ""); 96 bool isUtc = (match[8] !== null) && (match[8] != "");
72 TimeZone timezone = isUtc ? const TimeZone.utc() : new TimeZone.local(); 97 TimeZone timezone = isUtc ? const TimeZone.utc() : new TimeZone.local();
73 return new DateImplementation.withTimeZone( 98 int epochValue = _valueFromDecomposed(
74 years, month, day, hours, minutes, seconds, milliseconds, timezone); 99 years, month, day, hours, minutes, seconds, milliseconds, isUtc);
100 if (epochValue === null) {
101 throw new IllegalArgumentException(formattedString);
102 }
103 if (addOneMillisecond) epochValue++;
104 return new DateImplementation.fromEpoch(epochValue, timezone);
75 } else { 105 } else {
76 return new DateImplementation.fromEpoch(formattedString, 106 throw new IllegalArgumentException(formattedString);
77 new TimeZone.local());
78 } 107 }
79 } 108 }
80 109
81 const DateImplementation.fromEpoch(this.value, this.timeZone); 110 const DateImplementation.fromEpoch(this.value, this.timeZone);
82 111
83 bool operator ==(other) { 112 bool operator ==(other) {
84 if (!(other is DateImplementation)) return false; 113 if (!(other is DateImplementation)) return false;
85 return (value == other.value) && (timeZone == other.timeZone); 114 return (value == other.value) && (timeZone == other.timeZone);
86 } 115 }
87 116
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 // TODO(jimhug): Could this please be getters? 182 // TODO(jimhug): Could this please be getters?
154 bool isLocalTime() { 183 bool isLocalTime() {
155 return !timeZone.isUtc; 184 return !timeZone.isUtc;
156 } 185 }
157 186
158 bool isUtc() { 187 bool isUtc() {
159 return timeZone.isUtc; 188 return timeZone.isUtc;
160 } 189 }
161 190
162 String toString() { 191 String toString() {
192 String fourDigits(int n) {
193 int absN = n.abs();
194 String sign = n < 0 ? "-" : "";
195 if (absN >= 1000) return "$n";
196 if (absN >= 100) return "${sign}0$absN";
197 if (absN >= 10) return "${sign}00$absN";
198 if (absN >= 1) return "${sign}000$absN";
199 }
163 String threeDigits(int n) { 200 String threeDigits(int n) {
164 if (n >= 100) return "${n}"; 201 if (n >= 100) return "${n}";
165 if (n > 10) return "0${n}"; 202 if (n > 10) return "0${n}";
166 return "00${n}"; 203 return "00${n}";
167 } 204 }
168 String twoDigits(int n) { 205 String twoDigits(int n) {
169 if (n >= 10) return "${n}"; 206 if (n >= 10) return "${n}";
170 return "0${n}"; 207 return "0${n}";
171 } 208 }
172 209
210 String y = fourDigits(year);
173 String m = twoDigits(month); 211 String m = twoDigits(month);
174 String d = twoDigits(day); 212 String d = twoDigits(day);
175 String h = twoDigits(hours); 213 String h = twoDigits(hours);
176 String min = twoDigits(minutes); 214 String min = twoDigits(minutes);
177 String sec = twoDigits(seconds); 215 String sec = twoDigits(seconds);
178 String ms = threeDigits(milliseconds); 216 String ms = threeDigits(milliseconds);
179 if (timeZone.isUtc) { 217 if (timeZone.isUtc) {
180 return "$year-$m-$d $h:$min:$sec.${ms}Z"; 218 return "$y-$m-$d $h:$min:$sec.${ms}Z";
181 } else { 219 } else {
182 return "$year-$m-$d $h:$min:$sec.$ms"; 220 return "$y-$m-$d $h:$min:$sec.$ms";
183 } 221 }
184 } 222 }
185 223
186 // TODO(jimhug): Why not use operators here? 224 // TODO(jimhug): Why not use operators here?
187 // Adds the [duration] to this Date instance. 225 // Adds the [duration] to this Date instance.
188 Date add(Duration duration) { 226 Date add(Duration duration) {
189 return new DateImplementation.fromEpoch(value + duration.inMilliseconds, 227 return new DateImplementation.fromEpoch(value + duration.inMilliseconds,
190 timeZone); 228 timeZone);
191 } 229 }
192 230
193 // Subtracts the [duration] from this Date instance. 231 // Subtracts the [duration] from this Date instance.
194 Date subtract(Duration duration) { 232 Date subtract(Duration duration) {
195 return new DateImplementation.fromEpoch(value - duration.inMilliseconds, 233 return new DateImplementation.fromEpoch(value - duration.inMilliseconds,
196 timeZone); 234 timeZone);
197 } 235 }
198 236
199 // Returns a [Duration] with the difference of [this] and [other]. 237 // Returns a [Duration] with the difference of [this] and [other].
200 Duration difference(Date other) { 238 Duration difference(Date other) {
201 return new Duration(milliseconds: value - other.value); 239 return new Duration(milliseconds: value - other.value);
202 } 240 }
203 241
204 // TODO(floitsch): Use real exception object. 242 // TODO(floitsch): Use real exception object.
205 static int _valueFromDecomposed(int years, int month, int day, 243 static int _valueFromDecomposed(int years, int month, int day,
206 int hours, int minutes, int seconds, 244 int hours, int minutes, int seconds,
207 int milliseconds, bool isUtc) native 245 int milliseconds, bool isUtc) native
208 '''var jsMonth = month - 1; 246 '''var jsMonth = month - 1;
209 var value = isUtc ? 247 var date = new Date(0);
210 Date.UTC(years, jsMonth, day, 248 if (isUtc) {
211 hours, minutes, seconds, milliseconds) : 249 date.setUTCFullYear(years, jsMonth, day);
212 new Date(years, jsMonth, day, 250 date.setUTCHours(hours, minutes, seconds, milliseconds);
213 hours, minutes, seconds, milliseconds).valueOf(); 251 } else {
214 if (isNaN(value)) throw Error("Invalid Date"); 252 date.setFullYear(years, jsMonth, day);
253 date.setHours(hours, minutes, seconds, milliseconds);
254 }
255 var value = date.valueOf();
256 if (isNaN(value)) return (void 0);
215 return value;'''; 257 return value;''';
216 258
217 static int _valueFromString(String str) native 259 static int _valueFromString(String str) native
218 '''var value = Date.parse(str); 260 '''var value = Date.parse(str);
219 if (isNaN(value)) throw Error("Invalid Date"); 261 if (isNaN(value)) throw Error("Invalid Date");
220 return value;'''; 262 return value;''';
221 263
222 static int _now() native "return new Date().valueOf();"; 264 static int _now() native "return new Date().valueOf();";
223 265
224 // Lazily keep a JS Date stored in the dart object. 266 // Lazily keep a JS Date stored in the dart object.
(...skipping 14 matching lines...) Expand all
239 return isUtc == other.isUtc; 281 return isUtc == other.isUtc;
240 } 282 }
241 283
242 String toString() { 284 String toString() {
243 if (isUtc) return "TimeZone (UTC)"; 285 if (isUtc) return "TimeZone (UTC)";
244 return "TimeZone (Local)"; 286 return "TimeZone (Local)";
245 } 287 }
246 288
247 final bool isUtc; 289 final bool isUtc;
248 } 290 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698