OLD | NEW |
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 part of utilslib; | 5 part of utilslib; |
6 | 6 |
7 /** | 7 /** |
8 * General purpose date/time utilities. | 8 * General purpose date/time utilities. |
9 */ | 9 */ |
10 class DateUtils { | 10 class DateUtils { |
11 // TODO(jmesserly): localized strings | 11 // TODO(jmesserly): localized strings |
12 static const WEEKDAYS = const ['Monday', 'Tuesday', 'Wednesday', 'Thursday', | 12 static const WEEKDAYS = const ['Monday', 'Tuesday', 'Wednesday', 'Thursday', |
13 'Friday', 'Saturday', 'Sunday']; | 13 'Friday', 'Saturday', 'Sunday']; |
14 | 14 |
15 static const YESTERDAY = 'Yesterday'; | 15 static const YESTERDAY = 'Yesterday'; |
16 | 16 |
17 static const MS_IN_WEEK = Date.DAYS_IN_WEEK * Duration.MILLISECONDS_PER_DAY; | 17 static const MS_IN_WEEK = DateTime.DAYS_IN_WEEK * Duration.MILLISECONDS_PER_DA
Y; |
18 | 18 |
19 // TODO(jmesserly): workaround for missing Date.fromDate in Dartium | 19 // TODO(jmesserly): workaround for missing DateTime.fromDate in Dartium |
20 // Remove this once that is implemented. See b/5055106 | 20 // Remove this once that is implemented. See b/5055106 |
21 // Parse a string like: "Mon, 27 Jun 2011 15:22:00 -0700" | 21 // Parse a string like: "Mon, 27 Jun 2011 15:22:00 -0700" |
22 static Date fromString(String text) { | 22 static DateTime fromString(String text) { |
23 final parts = text.split(' '); | 23 final parts = text.split(' '); |
24 if (parts.length == 1) { | 24 if (parts.length == 1) { |
25 return _parseIsoDate(text); | 25 return _parseIsoDate(text); |
26 } | 26 } |
27 | 27 |
28 if (parts.length != 6) { | 28 if (parts.length != 6) { |
29 throw 'bad date format, expected 6 parts: $text'; | 29 throw 'bad date format, expected 6 parts: $text'; |
30 } | 30 } |
31 | 31 |
32 // skip parts[0], the weekday | 32 // skip parts[0], the weekday |
(...skipping 17 matching lines...) Expand all Loading... |
50 | 50 |
51 int hours = int.parse(timeParts[0]); | 51 int hours = int.parse(timeParts[0]); |
52 int minutes = int.parse(timeParts[1]); | 52 int minutes = int.parse(timeParts[1]); |
53 int seconds = int.parse(timeParts[2]); | 53 int seconds = int.parse(timeParts[2]); |
54 | 54 |
55 // TODO(jmesserly): TimeZone is not implemented in Dartium. This ugly | 55 // TODO(jmesserly): TimeZone is not implemented in Dartium. This ugly |
56 // hack applies the timezone from the string to the final time | 56 // hack applies the timezone from the string to the final time |
57 int zoneOffset = int.parse(parts[5]) ~/ 100; | 57 int zoneOffset = int.parse(parts[5]) ~/ 100; |
58 | 58 |
59 // Pretend it's a UTC time | 59 // Pretend it's a UTC time |
60 Date result = new Date.utc(year, month, day, hours, minutes, seconds, 0); | 60 DateTime result = new DateTime.utc(year, month, day, hours, minutes, seconds
, 0); |
61 // Shift it to the proper zone, but it's still a UTC time | 61 // Shift it to the proper zone, but it's still a UTC time |
62 result = result.subtract(new Duration(hours: zoneOffset)); | 62 result = result.subtract(new Duration(hours: zoneOffset)); |
63 // Then render it as a local time | 63 // Then render it as a local time |
64 return result.toLocal(); | 64 return result.toLocal(); |
65 } | 65 } |
66 | 66 |
67 /** Parse a string like: 2011-07-19T22:03:04.000Z */ | 67 /** Parse a string like: 2011-07-19T22:03:04.000Z */ |
68 // TODO(jmesserly): workaround for Date.fromDate, which has issues: | 68 // TODO(jmesserly): workaround for DateTime.fromDate, which has issues: |
69 // * on Dart VM it doesn't handle all of ISO 8601. See b/5055106. | 69 // * on Dart VM it doesn't handle all of ISO 8601. See b/5055106. |
70 // * on DartC it doesn't work on Safari. See b/5062557. | 70 // * on DartC it doesn't work on Safari. See b/5062557. |
71 // Remove this once that function is fully implemented | 71 // Remove this once that function is fully implemented |
72 static Date _parseIsoDate(String text) { | 72 static DateTime _parseIsoDate(String text) { |
73 void ensure(bool value) { | 73 void ensure(bool value) { |
74 if (!value) { | 74 if (!value) { |
75 throw 'bad date format, expected YYYY-MM-DDTHH:MM:SS.mmmZ: $text'; | 75 throw 'bad date format, expected YYYY-MM-DDTHH:MM:SS.mmmZ: $text'; |
76 } | 76 } |
77 } | 77 } |
78 | 78 |
79 bool isUtc = text.endsWith('Z'); | 79 bool isUtc = text.endsWith('Z'); |
80 if (isUtc) { | 80 if (isUtc) { |
81 text = text.substring(0, text.length - 1); | 81 text = text.substring(0, text.length - 1); |
82 } | 82 } |
83 | 83 |
84 final parts = text.split('T'); | 84 final parts = text.split('T'); |
85 ensure(parts.length == 2); | 85 ensure(parts.length == 2); |
86 | 86 |
87 final date = parts[0].split('-'); | 87 final date = parts[0].split('-'); |
88 ensure(date.length == 3); | 88 ensure(date.length == 3); |
89 | 89 |
90 final time = parts[1].split(':'); | 90 final time = parts[1].split(':'); |
91 ensure(time.length == 3); | 91 ensure(time.length == 3); |
92 | 92 |
93 final seconds = time[2].split('.'); | 93 final seconds = time[2].split('.'); |
94 ensure(seconds.length >= 1 && seconds.length <= 2); | 94 ensure(seconds.length >= 1 && seconds.length <= 2); |
95 int milliseconds = 0; | 95 int milliseconds = 0; |
96 if (seconds.length == 2) { | 96 if (seconds.length == 2) { |
97 milliseconds = int.parse(seconds[1]); | 97 milliseconds = int.parse(seconds[1]); |
98 } | 98 } |
99 | 99 |
100 return new Date( | 100 return new DateTime( |
101 int.parse(date[0]), | 101 int.parse(date[0]), |
102 int.parse(date[1]), | 102 int.parse(date[1]), |
103 int.parse(date[2]), | 103 int.parse(date[2]), |
104 int.parse(time[0]), | 104 int.parse(time[0]), |
105 int.parse(time[1]), | 105 int.parse(time[1]), |
106 int.parse(seconds[0]), | 106 int.parse(seconds[0]), |
107 milliseconds); | 107 milliseconds); |
108 } | 108 } |
109 | 109 |
110 /** | 110 /** |
111 * A date/time formatter that takes into account the current date/time: | 111 * A date/time formatter that takes into account the current date/time: |
112 * - if it's from today, just show the time | 112 * - if it's from today, just show the time |
113 * - if it's from yesterday, just show 'Yesterday' | 113 * - if it's from yesterday, just show 'Yesterday' |
114 * - if it's from the same week, just show the weekday | 114 * - if it's from the same week, just show the weekday |
115 * - otherwise, show just the date | 115 * - otherwise, show just the date |
116 */ | 116 */ |
117 static String toRecentTimeString(Date then) { | 117 static String toRecentTimeString(DateTime then) { |
118 bool datesAreEqual(Date d1, Date d2) { | 118 bool datesAreEqual(DateTime d1, DateTime d2) { |
119 return (d1.year == d2.year) && (d1.month == d2.month) && | 119 return (d1.year == d2.year) && (d1.month == d2.month) && |
120 (d1.day == d2.day); | 120 (d1.day == d2.day); |
121 } | 121 } |
122 | 122 |
123 final now = new Date.now(); | 123 final now = new DateTime.now(); |
124 if (datesAreEqual(then, now)) { | 124 if (datesAreEqual(then, now)) { |
125 return toHourMinutesString(new Duration( | 125 return toHourMinutesString(new Duration( |
126 days: 0, | 126 days: 0, |
127 hours: then.hour, | 127 hours: then.hour, |
128 minutes: then.minute, | 128 minutes: then.minute, |
129 seconds: then.second, | 129 seconds: then.second, |
130 milliseconds: then.millisecond)); | 130 milliseconds: then.millisecond)); |
131 } | 131 } |
132 | 132 |
133 final today = new Date(now.year, now.month, now.day, 0, 0, 0, 0); | 133 final today = new DateTime(now.year, now.month, now.day, 0, 0, 0, 0); |
134 Duration delta = today.difference(then); | 134 Duration delta = today.difference(then); |
135 if (delta.inMilliseconds < Duration.MILLISECONDS_PER_DAY) { | 135 if (delta.inMilliseconds < Duration.MILLISECONDS_PER_DAY) { |
136 return YESTERDAY; | 136 return YESTERDAY; |
137 } else if (delta.inMilliseconds < MS_IN_WEEK) { | 137 } else if (delta.inMilliseconds < MS_IN_WEEK) { |
138 return WEEKDAYS[getWeekday(then)]; | 138 return WEEKDAYS[getWeekday(then)]; |
139 } else { | 139 } else { |
140 // TODO(jmesserly): locale specific date format | 140 // TODO(jmesserly): locale specific date format |
141 String twoDigits(int n) { | 141 String twoDigits(int n) { |
142 if (n >= 10) return "${n}"; | 142 if (n >= 10) return "${n}"; |
143 return "0${n}"; | 143 return "0${n}"; |
144 } | 144 } |
145 String twoDigitMonth = twoDigits(then.month); | 145 String twoDigitMonth = twoDigits(then.month); |
146 String twoDigitDay = twoDigits(then.day); | 146 String twoDigitDay = twoDigits(then.day); |
147 return "${then.year}-${twoDigitMonth}-${twoDigitDay}"; | 147 return "${then.year}-${twoDigitMonth}-${twoDigitDay}"; |
148 } | 148 } |
149 } | 149 } |
150 | 150 |
151 // TODO(jmesserly): this is a workaround for unimplemented Date.weekday | 151 // TODO(jmesserly): this is a workaround for unimplemented DateTime.weekday |
152 // Code inspired by v8/src/date.js | 152 // Code inspired by v8/src/date.js |
153 static int getWeekday(Date dateTime) { | 153 static int getWeekday(DateTime dateTime) { |
154 final unixTimeStart = new Date(1970, 1, 1, 0, 0, 0, 0); | 154 final unixTimeStart = new DateTime(1970, 1, 1, 0, 0, 0, 0); |
155 int msSince1970 = dateTime.difference(unixTimeStart).inMilliseconds; | 155 int msSince1970 = dateTime.difference(unixTimeStart).inMilliseconds; |
156 int daysSince1970 = msSince1970 ~/ Duration.MILLISECONDS_PER_DAY; | 156 int daysSince1970 = msSince1970 ~/ Duration.MILLISECONDS_PER_DAY; |
157 // 1970-1-1 was Thursday | 157 // 1970-1-1 was Thursday |
158 return ((daysSince1970 + Date.THU) % Date.DAYS_IN_WEEK); | 158 return ((daysSince1970 + DateTime.THU) % DateTime.DAYS_IN_WEEK); |
159 } | 159 } |
160 | 160 |
161 /** Formats a time in H:MM A format */ | 161 /** Formats a time in H:MM A format */ |
162 // TODO(jmesserly): should get 12 vs 24 hour clock setting from the locale | 162 // TODO(jmesserly): should get 12 vs 24 hour clock setting from the locale |
163 static String toHourMinutesString(Duration duration) { | 163 static String toHourMinutesString(Duration duration) { |
164 assert(duration.inDays == 0); | 164 assert(duration.inDays == 0); |
165 int hours = duration.inHours; | 165 int hours = duration.inHours; |
166 String a; | 166 String a; |
167 if (hours >= 12) { | 167 if (hours >= 12) { |
168 a = 'pm'; | 168 a = 'pm'; |
169 if (hours != 12) { | 169 if (hours != 12) { |
170 hours -= 12; | 170 hours -= 12; |
171 } | 171 } |
172 } else { | 172 } else { |
173 a = 'am'; | 173 a = 'am'; |
174 if (hours == 0) { | 174 if (hours == 0) { |
175 hours += 12; | 175 hours += 12; |
176 } | 176 } |
177 } | 177 } |
178 String twoDigits(int n) { | 178 String twoDigits(int n) { |
179 if (n >= 10) return "${n}"; | 179 if (n >= 10) return "${n}"; |
180 return "0${n}"; | 180 return "0${n}"; |
181 } | 181 } |
182 String mm = | 182 String mm = |
183 twoDigits(duration.inMinutes.remainder(Duration.MINUTES_PER_HOUR)); | 183 twoDigits(duration.inMinutes.remainder(Duration.MINUTES_PER_HOUR)); |
184 return "${hours}:${mm} ${a}"; | 184 return "${hours}:${mm} ${a}"; |
185 } | 185 } |
186 } | 186 } |
OLD | NEW |