1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.joda.time.format;
17
18 import java.util.Arrays;
19 import java.util.Locale;
20
21 import org.joda.time.Chronology;
22 import org.joda.time.DateTimeField;
23 import org.joda.time.DateTimeFieldType;
24 import org.joda.time.DateTimeUtils;
25 import org.joda.time.DateTimeZone;
26 import org.joda.time.DurationField;
27 import org.joda.time.DurationFieldType;
28 import org.joda.time.IllegalFieldValueException;
29 import org.joda.time.IllegalInstantException;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public class DateTimeParserBucket {
57
58
59 private final Chronology iChrono;
60 private final long iMillis;
61
62
63 private DateTimeZone iZone;
64
65 private Integer iOffset;
66
67 private Locale iLocale;
68
69 private Integer iPivotYear;
70
71 private int iDefaultYear;
72
73 private SavedField[] iSavedFields = new SavedField[8];
74 private int iSavedFieldsCount;
75 private boolean iSavedFieldsShared;
76
77 private Object iSavedState;
78
79
80
81
82
83
84
85
86
87 @Deprecated
88 public DateTimeParserBucket(long instantLocal, Chronology chrono, Locale locale) {
89 this(instantLocal, chrono, locale, null, 2000);
90 }
91
92
93
94
95
96
97
98
99
100
101
102
103 @Deprecated
104 public DateTimeParserBucket(long instantLocal, Chronology chrono, Locale locale, Integer pivotYear) {
105 this(instantLocal, chrono, locale, pivotYear, 2000);
106 }
107
108
109
110
111
112
113
114
115
116
117
118 public DateTimeParserBucket(long instantLocal, Chronology chrono,
119 Locale locale, Integer pivotYear, int defaultYear) {
120 super();
121 chrono = DateTimeUtils.getChronology(chrono);
122 iMillis = instantLocal;
123 iZone = chrono.getZone();
124 iChrono = chrono.withUTC();
125 iLocale = (locale == null ? Locale.getDefault() : locale);
126 iPivotYear = pivotYear;
127 iDefaultYear = defaultYear;
128 }
129
130
131
132
133
134 public Chronology getChronology() {
135 return iChrono;
136 }
137
138
139
140
141
142
143
144 public Locale getLocale() {
145 return iLocale;
146 }
147
148
149
150
151
152 public DateTimeZone getZone() {
153 return iZone;
154 }
155
156
157
158
159 public void setZone(DateTimeZone zone) {
160 iSavedState = null;
161 iZone = zone;
162 }
163
164
165
166
167
168
169 @Deprecated
170 public int getOffset() {
171 return (iOffset != null ? iOffset : 0);
172 }
173
174
175
176
177 public Integer getOffsetInteger() {
178 return iOffset;
179 }
180
181
182
183
184
185 @Deprecated
186 public void setOffset(int offset) {
187 iSavedState = null;
188 iOffset = offset;
189 }
190
191
192
193
194 public void setOffset(Integer offset) {
195 iSavedState = null;
196 iOffset = offset;
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212 public Integer getPivotYear() {
213 return iPivotYear;
214 }
215
216
217
218
219
220
221
222
223
224
225 public void setPivotYear(Integer pivotYear) {
226 iPivotYear = pivotYear;
227 }
228
229
230
231
232
233
234
235
236 public void saveField(DateTimeField field, int value) {
237 saveField(new SavedField(field, value));
238 }
239
240
241
242
243
244
245
246 public void saveField(DateTimeFieldType fieldType, int value) {
247 saveField(new SavedField(fieldType.getField(iChrono), value));
248 }
249
250
251
252
253
254
255
256
257 public void saveField(DateTimeFieldType fieldType, String text, Locale locale) {
258 saveField(new SavedField(fieldType.getField(iChrono), text, locale));
259 }
260
261 private void saveField(SavedField field) {
262 SavedField[] savedFields = iSavedFields;
263 int savedFieldsCount = iSavedFieldsCount;
264
265 if (savedFieldsCount == savedFields.length || iSavedFieldsShared) {
266
267 SavedField[] newArray = new SavedField
268 [savedFieldsCount == savedFields.length ? savedFieldsCount * 2 : savedFields.length];
269 System.arraycopy(savedFields, 0, newArray, 0, savedFieldsCount);
270 iSavedFields = savedFields = newArray;
271 iSavedFieldsShared = false;
272 }
273
274 iSavedState = null;
275 savedFields[savedFieldsCount] = field;
276 iSavedFieldsCount = savedFieldsCount + 1;
277 }
278
279
280
281
282
283
284
285
286 public Object saveState() {
287 if (iSavedState == null) {
288 iSavedState = new SavedState();
289 }
290 return iSavedState;
291 }
292
293
294
295
296
297
298
299
300
301 public boolean restoreState(Object savedState) {
302 if (savedState instanceof SavedState) {
303 if (((SavedState) savedState).restoreState(this)) {
304 iSavedState = savedState;
305 return true;
306 }
307 }
308 return false;
309 }
310
311
312
313
314
315
316
317
318 public long computeMillis() {
319 return computeMillis(false, null);
320 }
321
322
323
324
325
326
327
328
329
330 public long computeMillis(boolean resetFields) {
331 return computeMillis(resetFields, null);
332 }
333
334
335
336
337
338
339
340
341
342
343
344 public long computeMillis(boolean resetFields, String text) {
345 SavedField[] savedFields = iSavedFields;
346 int count = iSavedFieldsCount;
347 if (iSavedFieldsShared) {
348 iSavedFields = savedFields = (SavedField[])iSavedFields.clone();
349 iSavedFieldsShared = false;
350 }
351 sort(savedFields, count);
352 if (count > 0) {
353
354 DurationField months = DurationFieldType.months().getField(iChrono);
355 DurationField days = DurationFieldType.days().getField(iChrono);
356 DurationField first = savedFields[0].iField.getDurationField();
357 if (compareReverse(first, months) >= 0 && compareReverse(first, days) <= 0) {
358 saveField(DateTimeFieldType.year(), iDefaultYear);
359 return computeMillis(resetFields, text);
360 }
361 }
362
363 long millis = iMillis;
364 try {
365 for (int i = 0; i < count; i++) {
366 millis = savedFields[i].set(millis, resetFields);
367 }
368 if (resetFields) {
369 for (int i = 0; i < count; i++) {
370 millis = savedFields[i].set(millis, i == (count - 1));
371 }
372 }
373 } catch (IllegalFieldValueException e) {
374 if (text != null) {
375 e.prependMessage("Cannot parse \"" + text + '"');
376 }
377 throw e;
378 }
379
380 if (iOffset != null) {
381 millis -= iOffset;
382 } else if (iZone != null) {
383 int offset = iZone.getOffsetFromLocal(millis);
384 millis -= offset;
385 if (offset != iZone.getOffset(millis)) {
386 String message = "Illegal instant due to time zone offset transition (" + iZone + ')';
387 if (text != null) {
388 message = "Cannot parse \"" + text + "\": " + message;
389 }
390 throw new IllegalInstantException(message);
391 }
392 }
393
394 return millis;
395 }
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415 private static void sort(SavedField[] array, int high) {
416 if (high > 10) {
417 Arrays.sort(array, 0, high);
418 } else {
419 for (int i=0; i<high; i++) {
420 for (int j=i; j>0 && (array[j-1]).compareTo(array[j])>0; j--) {
421 SavedField t = array[j];
422 array[j] = array[j-1];
423 array[j-1] = t;
424 }
425 }
426 }
427 }
428
429 class SavedState {
430 final DateTimeZone iZone;
431 final Integer iOffset;
432 final SavedField[] iSavedFields;
433 final int iSavedFieldsCount;
434
435 SavedState() {
436 this.iZone = DateTimeParserBucket.this.iZone;
437 this.iOffset = DateTimeParserBucket.this.iOffset;
438 this.iSavedFields = DateTimeParserBucket.this.iSavedFields;
439 this.iSavedFieldsCount = DateTimeParserBucket.this.iSavedFieldsCount;
440 }
441
442 boolean restoreState(DateTimeParserBucket enclosing) {
443 if (enclosing != DateTimeParserBucket.this) {
444 return false;
445 }
446 enclosing.iZone = this.iZone;
447 enclosing.iOffset = this.iOffset;
448 enclosing.iSavedFields = this.iSavedFields;
449 if (this.iSavedFieldsCount < enclosing.iSavedFieldsCount) {
450
451
452
453
454 enclosing.iSavedFieldsShared = true;
455 }
456 enclosing.iSavedFieldsCount = this.iSavedFieldsCount;
457 return true;
458 }
459 }
460
461 static class SavedField implements Comparable<SavedField> {
462 final DateTimeField iField;
463 final int iValue;
464 final String iText;
465 final Locale iLocale;
466
467 SavedField(DateTimeField field, int value) {
468 iField = field;
469 iValue = value;
470 iText = null;
471 iLocale = null;
472 }
473
474 SavedField(DateTimeField field, String text, Locale locale) {
475 iField = field;
476 iValue = 0;
477 iText = text;
478 iLocale = locale;
479 }
480
481 long set(long millis, boolean reset) {
482 if (iText == null) {
483 millis = iField.set(millis, iValue);
484 } else {
485 millis = iField.set(millis, iText, iLocale);
486 }
487 if (reset) {
488 millis = iField.roundFloor(millis);
489 }
490 return millis;
491 }
492
493
494
495
496
497
498 public int compareTo(SavedField obj) {
499 DateTimeField other = obj.iField;
500 int result = compareReverse
501 (iField.getRangeDurationField(), other.getRangeDurationField());
502 if (result != 0) {
503 return result;
504 }
505 return compareReverse
506 (iField.getDurationField(), other.getDurationField());
507 }
508 }
509
510 static int compareReverse(DurationField a, DurationField b) {
511 if (a == null || !a.isSupported()) {
512 if (b == null || !b.isSupported()) {
513 return 0;
514 }
515 return -1;
516 }
517 if (b == null || !b.isSupported()) {
518 return 1;
519 }
520 return -a.compareTo(b);
521 }
522 }