OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of dart.core; | |
6 | |
7 /** | |
8 * Date is the public interface to a point in time. | |
9 * | |
10 * It can represent time values that are at a distance of at most | |
11 * 8,640,000,000,000,000ms (100,000,000 days) from epoch (1970-01-01 UTC). In | |
12 * other words: [:millisecondsSinceEpoch.abs() <= 8640000000000000:]. | |
13 * | |
14 * Also see [Stopwatch] for means to measure time-spans. | |
15 */ | |
16 abstract class Date implements Comparable { | |
17 // Weekday constants that are returned by [weekday] method: | |
18 static const int MON = 1; | |
19 static const int TUE = 2; | |
20 static const int WED = 3; | |
21 static const int THU = 4; | |
22 static const int FRI = 5; | |
23 static const int SAT = 6; | |
24 static const int SUN = 7; | |
25 static const int DAYS_IN_WEEK = 7; | |
26 | |
27 // Month constants that are returned by the [month] getter. | |
28 static const int JAN = 1; | |
29 static const int FEB = 2; | |
30 static const int MAR = 3; | |
31 static const int APR = 4; | |
32 static const int MAY = 5; | |
33 static const int JUN = 6; | |
34 static const int JUL = 7; | |
35 static const int AUG = 8; | |
36 static const int SEP = 9; | |
37 static const int OCT = 10; | |
38 static const int NOV = 11; | |
39 static const int DEC = 12; | |
40 | |
41 /** | |
42 * Constructs a [Date] instance based on the individual parts. The date is | |
43 * in the local time zone. | |
44 * | |
45 * [month] and [day] are one-based. For example | |
46 * [:new Date(1938, 1, 10):] represents the 10th of January 1938. | |
47 */ | |
48 factory Date(int year, | |
49 [int month = 1, | |
50 int day = 1, | |
51 int hour = 0, | |
52 int minute = 0, | |
53 int second = 0, | |
54 int millisecond = 0]) { | |
55 return new _DateImpl( | |
56 year, month, day, hour, minute, second, millisecond, false); | |
57 } | |
58 | |
59 /** | |
60 * Constructs a [Date] instance based on the individual parts. The date is | |
61 * in the UTC time zone. | |
62 * | |
63 * [month] and [day] are one-based. For example | |
64 * [:new Date.utc(1938, 1, 10):] represents the 10th of January 1938 in | |
65 * Coordinated Universal Time. | |
66 */ | |
67 factory Date.utc(int year, | |
68 [int month = 1, | |
69 int day = 1, | |
70 int hour = 0, | |
71 int minute = 0, | |
72 int second = 0, | |
73 int millisecond = 0]) { | |
74 return new _DateImpl( | |
75 year, month, day, hour, minute, second, millisecond, true); | |
76 } | |
77 | |
78 /** | |
79 * Constructs a new [Date] instance with current date time value in the | |
80 * local time zone. | |
81 */ | |
82 factory Date.now() => new _DateImpl.now(); | |
83 | |
84 /** | |
85 * Constructs a new [Date] instance based on [formattedString]. | |
86 */ | |
87 factory Date.fromString(String formattedString) | |
88 => new _DateImpl.fromString(formattedString); | |
89 | |
90 /** | |
91 * Constructs a new [Date] instance with the given [millisecondsSinceEpoch]. | |
92 * If [isUtc] is false then the date is in the local time zone. | |
93 * | |
94 * The constructed [Date] represents | |
95 * 1970-01-01T00:00:00Z + [millisecondsSinceEpoch]ms in the given | |
96 * time zone (local or UTC). | |
97 */ | |
98 // TODO(floitsch): the spec allows default values in interfaces, but our | |
99 // tools don't yet. Eventually we want to have default values here. | |
100 // TODO(lrn): Have two constructors instead of taking an optional bool. | |
101 factory Date.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch, | |
102 {bool isUtc: false}) { | |
103 return new _DateImpl.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, | |
104 isUtc); | |
105 } | |
106 | |
107 /** | |
108 * Returns true if [this] occurs at the same time as [other]. The | |
109 * comparison is independent of whether the time is utc or in the local | |
110 * time zone. | |
111 */ | |
112 bool operator ==(Date other); | |
113 /** | |
114 * Returns true if [this] occurs before [other]. The comparison is independent | |
115 * of whether the time is utc or in the local time zone. | |
116 */ | |
117 bool operator <(Date other); | |
118 /** | |
119 * Returns true if [this] occurs at the same time or before [other]. The | |
120 * comparison is independent of whether the time is utc or in the local | |
121 * time zone. | |
122 */ | |
123 bool operator <=(Date other); | |
124 /** | |
125 * Returns true if [this] occurs after [other]. The comparison is independent | |
126 * of whether the time is utc or in the local time zone. | |
127 */ | |
128 bool operator >(Date other); | |
129 /** | |
130 * Returns true if [this] occurs at the same time or after [other]. The | |
131 * comparison is independent of whether the time is utc or in the local | |
132 * time zone. | |
133 */ | |
134 bool operator >=(Date other); | |
135 | |
136 | |
137 /** | |
138 * Returns [this] in the local time zone. Returns itself if it is already in | |
139 * the local time zone. Otherwise, this method is equivalent to | |
140 * [:new Date.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, | |
141 * isUtc: false):]. | |
142 */ | |
143 Date toLocal(); | |
144 | |
145 /** | |
146 * Returns [this] in UTC. Returns itself if it is already in UTC. Otherwise, | |
147 * this method is equivalent to | |
148 * [:new Date.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, | |
149 * isUtc: true):]. | |
150 */ | |
151 Date toUtc(); | |
152 | |
153 /** | |
154 * Returns the abbreviated time-zone name. | |
155 * | |
156 * Examples: [:"CET":] or [:"CEST":]. | |
157 */ | |
158 String get timeZoneName; | |
159 | |
160 /** | |
161 * The time-zone offset is the difference between local time and UTC. That is, | |
162 * the offset is positive for time zones west of UTC. | |
163 * | |
164 * Note, that JavaScript, Python and C return the difference between UTC and | |
165 * local time. Java, C# and Ruby return the difference between local time and | |
166 * UTC. | |
167 */ | |
168 Duration get timeZoneOffset; | |
169 | |
170 /** | |
171 * Returns the year. | |
172 */ | |
173 int get year; | |
174 | |
175 /** | |
176 * Returns the month into the year [1..12]. | |
177 */ | |
178 int get month; | |
179 | |
180 /** | |
181 * Returns the day into the month [1..31]. | |
182 */ | |
183 int get day; | |
184 | |
185 /** | |
186 * Returns the hour into the day [0..23]. | |
187 */ | |
188 int get hour; | |
189 | |
190 /** | |
191 * Returns the minute into the hour [0...59]. | |
192 */ | |
193 int get minute; | |
194 | |
195 /** | |
196 * Returns the second into the minute [0...59]. | |
197 */ | |
198 int get second; | |
199 | |
200 /** | |
201 * Returns the millisecond into the second [0...999]. | |
202 */ | |
203 int get millisecond; | |
204 | |
205 /** | |
206 * Returns the week day [MON..SUN]. In accordance with ISO 8601 | |
207 * a week starts with Monday which has the value 1. | |
208 */ | |
209 int get weekday; | |
210 | |
211 /** | |
212 * The milliseconds since 1970-01-01T00:00:00Z (UTC). This value is | |
213 * independent of the time zone. | |
214 * | |
215 * See [Stopwatch] for means to measure time-spans. | |
216 */ | |
217 int get millisecondsSinceEpoch; | |
218 | |
219 /** | |
220 * True if this [Date] is set to UTC time. | |
221 */ | |
222 bool get isUtc; | |
223 | |
224 /** | |
225 * Returns a human readable string for this instance. | |
226 * The returned string is constructed for the time zone of this instance. | |
227 */ | |
228 String toString(); | |
229 | |
230 /** | |
231 * Returns a new [Date] with the [duration] added to this instance. | |
232 */ | |
233 Date add(Duration duration); | |
234 | |
235 /** | |
236 * Returns a new [Date] with the [duration] subtracted from this instance. | |
237 */ | |
238 Date subtract(Duration duration); | |
239 | |
240 /** | |
241 * Returns a [Duration] with the difference of [:this:] and [other]. | |
242 */ | |
243 Duration difference(Date other); | |
244 } | |
245 | |
246 class _DateImpl implements Date { | |
247 final int millisecondsSinceEpoch; | |
248 final bool isUtc; | |
249 | |
250 factory _DateImpl.fromString(String formattedString) { | |
251 // Read in (a subset of) ISO 8601. | |
252 // Examples: | |
253 // - "2012-02-27 13:27:00" | |
254 // - "2012-02-27 13:27:00.423z" | |
255 // - "20120227 13:27:00" | |
256 // - "20120227T132700" | |
257 // - "20120227" | |
258 // - "2012-02-27T14Z" | |
259 // - "-123450101 00:00:00 Z" // In the year -12345. | |
260 final RegExp re = new RegExp( | |
261 r'^([+-]?\d?\d\d\d\d)-?(\d\d)-?(\d\d)' // The day part. | |
262 r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(.\d{1,6})?)?)? ?([zZ])?)?$'); | |
263 Match match = re.firstMatch(formattedString); | |
264 if (match != null) { | |
265 int parseIntOrZero(String matched) { | |
266 // TODO(floitsch): we should not need to test against the empty string. | |
267 if (matched == null || matched == "") return 0; | |
268 return int.parse(matched); | |
269 } | |
270 | |
271 double parseDoubleOrZero(String matched) { | |
272 // TODO(floitsch): we should not need to test against the empty string. | |
273 if (matched == null || matched == "") return 0.0; | |
274 return double.parse(matched); | |
275 } | |
276 | |
277 int years = int.parse(match[1]); | |
278 int month = int.parse(match[2]); | |
279 int day = int.parse(match[3]); | |
280 int hour = parseIntOrZero(match[4]); | |
281 int minute = parseIntOrZero(match[5]); | |
282 int second = parseIntOrZero(match[6]); | |
283 bool addOneMillisecond = false; | |
284 int millisecond = (parseDoubleOrZero(match[7]) * 1000).round().toInt(); | |
285 if (millisecond == 1000) { | |
286 addOneMillisecond = true; | |
287 millisecond = 999; | |
288 } | |
289 // TODO(floitsch): we should not need to test against the empty string. | |
290 bool isUtc = (match[8] != null) && (match[8] != ""); | |
291 int millisecondsSinceEpoch = _brokenDownDateToMillisecondsSinceEpoch( | |
292 years, month, day, hour, minute, second, millisecond, isUtc); | |
293 if (millisecondsSinceEpoch == null) { | |
294 throw new ArgumentError(formattedString); | |
295 } | |
296 if (addOneMillisecond) millisecondsSinceEpoch++; | |
297 return new Date.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, | |
298 isUtc: isUtc); | |
299 } else { | |
300 throw new ArgumentError(formattedString); | |
301 } | |
302 } | |
303 | |
304 static const int _MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000; | |
305 | |
306 _DateImpl.fromMillisecondsSinceEpoch(this.millisecondsSinceEpoch, | |
307 this.isUtc) { | |
308 if (millisecondsSinceEpoch.abs() > _MAX_MILLISECONDS_SINCE_EPOCH) { | |
309 throw new ArgumentError(millisecondsSinceEpoch); | |
310 } | |
311 if (isUtc == null) throw new ArgumentError(isUtc); | |
312 } | |
313 | |
314 bool operator ==(other) { | |
315 if (!(other is Date)) return false; | |
316 return (millisecondsSinceEpoch == other.millisecondsSinceEpoch); | |
317 } | |
318 | |
319 bool operator <(Date other) | |
320 => millisecondsSinceEpoch < other.millisecondsSinceEpoch; | |
321 | |
322 bool operator <=(Date other) | |
323 => millisecondsSinceEpoch <= other.millisecondsSinceEpoch; | |
324 | |
325 bool operator >(Date other) | |
326 => millisecondsSinceEpoch > other.millisecondsSinceEpoch; | |
327 | |
328 bool operator >=(Date other) | |
329 => millisecondsSinceEpoch >= other.millisecondsSinceEpoch; | |
330 | |
331 int compareTo(Date other) | |
332 => millisecondsSinceEpoch.compareTo(other.millisecondsSinceEpoch); | |
333 | |
334 int get hashCode => millisecondsSinceEpoch; | |
335 | |
336 Date toLocal() { | |
337 if (isUtc) { | |
338 return new Date.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, | |
339 isUtc: false); | |
340 } | |
341 return this; | |
342 } | |
343 | |
344 Date toUtc() { | |
345 if (isUtc) return this; | |
346 return new Date.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, | |
347 isUtc: true); | |
348 } | |
349 | |
350 String toString() { | |
351 String fourDigits(int n) { | |
352 int absN = n.abs(); | |
353 String sign = n < 0 ? "-" : ""; | |
354 if (absN >= 1000) return "$n"; | |
355 if (absN >= 100) return "${sign}0$absN"; | |
356 if (absN >= 10) return "${sign}00$absN"; | |
357 return "${sign}000$absN"; | |
358 } | |
359 | |
360 String threeDigits(int n) { | |
361 if (n >= 100) return "${n}"; | |
362 if (n >= 10) return "0${n}"; | |
363 return "00${n}"; | |
364 } | |
365 | |
366 String twoDigits(int n) { | |
367 if (n >= 10) return "${n}"; | |
368 return "0${n}"; | |
369 } | |
370 | |
371 String y = fourDigits(year); | |
372 String m = twoDigits(month); | |
373 String d = twoDigits(day); | |
374 String h = twoDigits(hour); | |
375 String min = twoDigits(minute); | |
376 String sec = twoDigits(second); | |
377 String ms = threeDigits(millisecond); | |
378 if (isUtc) { | |
379 return "$y-$m-$d $h:$min:$sec.${ms}Z"; | |
380 } else { | |
381 return "$y-$m-$d $h:$min:$sec.$ms"; | |
382 } | |
383 } | |
384 | |
385 /** Returns a new [Date] with the [duration] added to [this]. */ | |
386 Date add(Duration duration) { | |
387 int ms = millisecondsSinceEpoch; | |
388 return new Date.fromMillisecondsSinceEpoch( | |
389 ms + duration.inMilliseconds, isUtc: isUtc); | |
390 } | |
391 | |
392 /** Returns a new [Date] with the [duration] subtracted from [this]. */ | |
393 Date subtract(Duration duration) { | |
394 int ms = millisecondsSinceEpoch; | |
395 return new Date.fromMillisecondsSinceEpoch( | |
396 ms - duration.inMilliseconds, isUtc: isUtc); | |
397 } | |
398 | |
399 /** Returns a [Duration] with the difference of [this] and [other]. */ | |
400 Duration difference(Date other) { | |
401 int ms = millisecondsSinceEpoch; | |
402 int otherMs = other.millisecondsSinceEpoch; | |
403 return new Duration(milliseconds: ms - otherMs); | |
404 } | |
405 | |
406 external _DateImpl(int year, | |
407 int month, | |
408 int day, | |
409 int hour, | |
410 int minute, | |
411 int second, | |
412 int millisecond, | |
413 bool isUtc); | |
414 external _DateImpl.now(); | |
415 external static int _brokenDownDateToMillisecondsSinceEpoch( | |
416 int year, int month, int day, int hour, int minute, int second, | |
417 int millisecond, bool isUtc); | |
418 external String get timeZoneName; | |
419 external Duration get timeZoneOffset; | |
420 external int get year; | |
421 external int get month; | |
422 external int get day; | |
423 external int get hour; | |
424 external int get minute; | |
425 external int get second; | |
426 external int get millisecond; | |
427 external int get weekday; | |
428 } | |
OLD | NEW |