comparison tango/tango/text/locale/Parse.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
comparison
equal deleted inserted replaced
131:5825d48b27d1 132:1700239cab2e
1 /*******************************************************************************
2
3 copyright: Copyright (c) 2005 John Chapman. All rights reserved
4
5 license: BSD style: $(LICENSE)
6
7 version: Initial release: 2005
8
9 author: John Chapman
10
11 ******************************************************************************/
12
13 module tango.text.locale.Parse;
14
15 private import tango.time.WallClock;
16
17 private import tango.core.Exception;
18
19 private import tango.text.locale.Core;
20
21 private import tango.time.chrono.Calendar;
22
23 private struct DateTimeParseResult {
24
25 int year = -1;
26 int month = -1;
27 int day = -1;
28 int hour;
29 int minute;
30 int second;
31 double fraction;
32 int timeMark;
33 Calendar calendar;
34 TimeSpan timeZoneOffset;
35 Time parsedDate;
36
37 }
38
39 package Time parseTime(char[] s, DateTimeFormat dtf) {
40 DateTimeParseResult result;
41 if (!tryParseExactMultiple(s, dtf.getAllDateTimePatterns(), dtf, result))
42 throw new IllegalArgumentException("String was not a valid Time.");
43 return result.parsedDate;
44 }
45
46 package Time parseTimeExact(char[] s, char[] format, DateTimeFormat dtf) {
47 DateTimeParseResult result;
48 if (!tryParseExact(s, format, dtf, result))
49 throw new IllegalArgumentException("String was not a valid Time.");
50 return result.parsedDate;
51 }
52
53 package bool tryParseTime(char[] s, DateTimeFormat dtf, out Time result) {
54 result = Time.min;
55 DateTimeParseResult resultRecord;
56 if (!tryParseExactMultiple(s, dtf.getAllDateTimePatterns(), dtf, resultRecord))
57 return false;
58 result = resultRecord.parsedDate;
59 return true;
60 }
61
62 package bool tryParseTimeExact(char[] s, char[] format, DateTimeFormat dtf, out Time result) {
63 result = Time.min;
64 DateTimeParseResult resultRecord;
65 if (!tryParseExact(s, format, dtf, resultRecord))
66 return false;
67 result = resultRecord.parsedDate;
68 return true;
69 }
70
71 private bool tryParseExactMultiple(char[] s, char[][] formats, DateTimeFormat dtf, inout DateTimeParseResult result) {
72 foreach (char[] format; formats) {
73 if (tryParseExact(s, format, dtf, result))
74 return true;
75 }
76 return false;
77 }
78
79 private bool tryParseExact(char[] s, char[] pattern, DateTimeFormat dtf, inout DateTimeParseResult result) {
80
81 bool doParse() {
82
83 int parseDigits(char[] s, inout int pos, int max) {
84 int result = s[pos++] - '0';
85 while (max > 1 && pos < s.length && s[pos] >= '0' && s[pos] <= '9') {
86 result = result * 10 + s[pos++] - '0';
87 --max;
88 }
89 return result;
90 }
91
92 bool parseOne(char[] s, inout int pos, char[] value) {
93 if (s[pos .. pos + value.length] != value)
94 return false;
95 pos += value.length;
96 return true;
97 }
98
99 int parseMultiple(char[] s, inout int pos, char[][] values ...) {
100 int result = -1, max;
101 foreach (int i, char[] value; values) {
102 if (value.length == 0 || s.length - pos < value.length)
103 continue;
104
105 if (s[pos .. pos + value.length] == value) {
106 if (result == 0 || value.length > max) {
107 result = i + 1;
108 max = value.length;
109 }
110 }
111 }
112 pos += max;
113 return result;
114 }
115
116 TimeSpan parseTimeZoneOffset(char[] s, inout int pos) {
117 bool sign;
118 if (pos < s.length) {
119 if (s[pos] == '-') {
120 sign = true;
121 pos++;
122 }
123 else if (s[pos] == '+')
124 pos++;
125 }
126 int hour = parseDigits(s, pos, 2);
127 int minute;
128 if (pos < s.length && s[pos] == ':') {
129 pos++;
130 minute = parseDigits(s, pos, 2);
131 }
132 //Due to dmd bug, this doesn't compile
133 //TimeSpan result = TimeSpan.hours(hour) + TimeSpan.minutes(minute);
134 TimeSpan result = TimeSpan(TimeSpan.TicksPerHour * hour + TimeSpan.TicksPerMinute * minute);
135 if (sign)
136 result = -result;
137 return result;
138 }
139
140 char[] stringOf(char c, int count = 1) {
141 char[] s = new char[count];
142 s[0 .. count] = c;
143 return s;
144 }
145
146 result.calendar = dtf.calendar;
147 result.year = result.month = result.day = -1;
148 result.hour = result.minute = result.second = 0;
149 result.fraction = 0.0;
150
151 int pos, i, count;
152 char c;
153
154 while (pos < pattern.length && i < s.length) {
155 c = pattern[pos++];
156
157 if (c == ' ') {
158 i++;
159 while (i < s.length && s[i] == ' ')
160 i++;
161 if (i >= s.length)
162 break;
163 continue;
164 }
165
166 count = 1;
167
168 switch (c) {
169 case 'd': case 'm': case 'M': case 'y':
170 case 'h': case 'H': case 's':
171 case 't': case 'z':
172 while (pos < pattern.length && pattern[pos] == c) {
173 pos++;
174 count++;
175 }
176 break;
177 case ':':
178 if (!parseOne(s, i, dtf.timeSeparator))
179 return false;
180 continue;
181 case '/':
182 if (!parseOne(s, i, dtf.dateSeparator))
183 return false;
184 continue;
185 case '\\':
186 if (pos < pattern.length) {
187 c = pattern[pos++];
188 if (s[i++] != c)
189 return false;
190 }
191 else
192 return false;
193 continue;
194 case '\'':
195 while (pos < pattern.length) {
196 c = pattern[pos++];
197 if (c == '\'')
198 break;
199 if (s[i++] != c)
200 return false;
201 }
202 continue;
203 default:
204 if (s[i++] != c)
205 return false;
206 continue;
207 }
208
209 switch (c) {
210 case 'd': // day
211 if (count == 1 || count == 2)
212 result.day = parseDigits(s, i, 2);
213 else if (count == 3)
214 result.day = parseMultiple(s, i, dtf.abbreviatedDayNames);
215 else
216 result.day = parseMultiple(s, i, dtf.dayNames);
217 if (result.day == -1)
218 return false;
219 break;
220 case 'M': // month
221 if (count == 1 || count == 2)
222 result.month = parseDigits(s, i, 2);
223 else if (count == 3)
224 result.month = parseMultiple(s, i, dtf.abbreviatedMonthNames);
225 else
226 result.month = parseMultiple(s, i, dtf.monthNames);
227 if (result.month == -1)
228 return false;
229 break;
230 case 'y': // year
231 if (count == 1 || count == 2)
232 result.year = parseDigits(s, i, 2);
233 else
234 result.year = parseDigits(s, i, 4);
235 if (result.year == -1)
236 return false;
237 break;
238 case 'h': // 12-hour clock
239 case 'H': // 24-hour clock
240 result.hour = parseDigits(s, i, 2);
241 break;
242 case 'm': // minute
243 result.minute = parseDigits(s, i, 2);
244 break;
245 case 's': // second
246 result.second = parseDigits(s, i, 2);
247 break;
248 case 't': // time mark
249 if (count == 1)
250 result.timeMark = parseMultiple(s, i, stringOf(dtf.amDesignator[0]), stringOf(dtf.pmDesignator[0]));
251 else
252 result.timeMark = parseMultiple(s, i, dtf.amDesignator, dtf.pmDesignator);
253 break;
254 case 'z':
255 result.timeZoneOffset = parseTimeZoneOffset(s, i);
256 break;
257 default:
258 break;
259 }
260 }
261
262 if (pos < pattern.length || i < s.length)
263 return false;
264
265 if (result.timeMark == 1) { // am
266 if (result.hour == 12)
267 result.hour = 0;
268 }
269 else if (result.timeMark == 2) { // pm
270 if (result.hour < 12)
271 result.hour += 12;
272 }
273
274 // If the input string didn't specify a date part, try to return something meaningful.
275 if (result.year == -1 || result.month == -1 || result.day == -1) {
276 Time now = WallClock.now;
277 if (result.month == -1 && result.day == -1) {
278 if (result.year == -1) {
279 result.year = result.calendar.getYear(now);
280 result.month = result.calendar.getMonth(now);
281 result.day = result.calendar.getDayOfMonth(now);
282 }
283 else
284 result.month = result.day = 1;
285 }
286 else {
287 if (result.year == -1)
288 result.year = result.calendar.getYear(now);
289 if (result.month == -1)
290 result.month = 1;
291 if (result.day == -1)
292 result.day = 1;
293 }
294 }
295 return true;
296 }
297
298 if (doParse()) {
299 result.parsedDate = result.calendar.toTime(result.year, result.month, result.day, result.hour, result.minute, result.second, 0);
300 return true;
301 }
302 return false;
303 }