1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.beanutils.converters;
18
19 import java.text.DateFormat;
20 import java.text.ParsePosition;
21 import java.text.SimpleDateFormat;
22 import java.util.Calendar;
23 import java.util.Date;
24 import java.util.Locale;
25 import java.util.TimeZone;
26
27 import org.apache.commons.beanutils.ConversionException;
28
29
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public abstract class DateTimeConverter extends AbstractConverter {
81
82 private String[] patterns;
83 private String displayPatterns;
84 private Locale locale;
85 private TimeZone timeZone;
86 private boolean useLocaleFormat;
87
88
89
90
91
92
93
94
95 public DateTimeConverter() {
96 super();
97 }
98
99
100
101
102
103
104
105
106
107 public DateTimeConverter(final Object defaultValue) {
108 super(defaultValue);
109 }
110
111
112
113
114
115
116
117
118
119
120 public void setUseLocaleFormat(final boolean useLocaleFormat) {
121 this.useLocaleFormat = useLocaleFormat;
122 }
123
124
125
126
127
128
129
130 public TimeZone getTimeZone() {
131 return timeZone;
132 }
133
134
135
136
137
138
139 public void setTimeZone(final TimeZone timeZone) {
140 this.timeZone = timeZone;
141 }
142
143
144
145
146
147
148
149 public Locale getLocale() {
150 return locale;
151 }
152
153
154
155
156
157
158 public void setLocale(final Locale locale) {
159 this.locale = locale;
160 setUseLocaleFormat(true);
161 }
162
163
164
165
166
167
168
169
170 public void setPattern(final String pattern) {
171 setPatterns(new String[] {pattern});
172 }
173
174
175
176
177
178
179
180
181
182 public String[] getPatterns() {
183 return patterns;
184 }
185
186
187
188
189
190
191
192
193 public void setPatterns(final String[] patterns) {
194 this.patterns = patterns;
195 if (patterns != null && patterns.length > 1) {
196 final StringBuilder buffer = new StringBuilder();
197 for (int i = 0; i < patterns.length; i++) {
198 if (i > 0) {
199 buffer.append(", ");
200 }
201 buffer.append(patterns[i]);
202 }
203 displayPatterns = buffer.toString();
204 }
205 setUseLocaleFormat(true);
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223 @Override
224 protected String convertToString(final Object value) throws Throwable {
225
226 Date date = null;
227 if (value instanceof Date) {
228 date = (Date)value;
229 } else if (value instanceof Calendar) {
230 date = ((Calendar)value).getTime();
231 } else if (value instanceof Long) {
232 date = new Date(((Long)value).longValue());
233 }
234
235 String result = null;
236 if (useLocaleFormat && date != null) {
237 DateFormat format = null;
238 if (patterns != null && patterns.length > 0) {
239 format = getFormat(patterns[0]);
240 } else {
241 format = getFormat(locale, timeZone);
242 }
243 logFormat("Formatting", format);
244 result = format.format(date);
245 if (log().isDebugEnabled()) {
246 log().debug(" Converted to String using format '" + result + "'");
247 }
248 } else {
249 result = value.toString();
250 if (log().isDebugEnabled()) {
251 log().debug(" Converted to String using toString() '" + result + "'");
252 }
253 }
254 return result;
255 }
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287 @Override
288 protected <T> T convertToType(final Class<T> targetType, final Object value) throws Exception {
289
290 final Class<?> sourceType = value.getClass();
291
292
293 if (value instanceof java.sql.Timestamp) {
294
295
296
297
298
299 final java.sql.Timestamp timestamp = (java.sql.Timestamp)value;
300 long timeInMillis = ((timestamp.getTime() / 1000) * 1000);
301 timeInMillis += timestamp.getNanos() / 1000000;
302
303 return toDate(targetType, timeInMillis);
304 }
305
306
307 if (value instanceof Date) {
308 final Date date = (Date)value;
309 return toDate(targetType, date.getTime());
310 }
311
312
313 if (value instanceof Calendar) {
314 final Calendar calendar = (Calendar)value;
315 return toDate(targetType, calendar.getTime().getTime());
316 }
317
318
319 if (value instanceof Long) {
320 final Long longObj = (Long)value;
321 return toDate(targetType, longObj.longValue());
322 }
323
324
325 final String stringValue = value.toString().trim();
326 if (stringValue.length() == 0) {
327 return handleMissing(targetType);
328 }
329
330
331 if (useLocaleFormat) {
332 Calendar calendar = null;
333 if (patterns != null && patterns.length > 0) {
334 calendar = parse(sourceType, targetType, stringValue);
335 } else {
336 final DateFormat format = getFormat(locale, timeZone);
337 calendar = parse(sourceType, targetType, stringValue, format);
338 }
339 if (Calendar.class.isAssignableFrom(targetType)) {
340 return targetType.cast(calendar);
341 } else {
342 return toDate(targetType, calendar.getTime().getTime());
343 }
344 }
345
346
347 return toDate(targetType, stringValue);
348
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370 private <T> T toDate(final Class<T> type, final long value) {
371
372
373 if (type.equals(Date.class)) {
374 return type.cast(new Date(value));
375 }
376
377
378 if (type.equals(java.sql.Date.class)) {
379 return type.cast(new java.sql.Date(value));
380 }
381
382
383 if (type.equals(java.sql.Time.class)) {
384 return type.cast(new java.sql.Time(value));
385 }
386
387
388 if (type.equals(java.sql.Timestamp.class)) {
389 return type.cast(new java.sql.Timestamp(value));
390 }
391
392
393 if (type.equals(Calendar.class)) {
394 Calendar calendar = null;
395 if (locale == null && timeZone == null) {
396 calendar = Calendar.getInstance();
397 } else if (locale == null) {
398 calendar = Calendar.getInstance(timeZone);
399 } else if (timeZone == null) {
400 calendar = Calendar.getInstance(locale);
401 } else {
402 calendar = Calendar.getInstance(timeZone, locale);
403 }
404 calendar.setTime(new Date(value));
405 calendar.setLenient(false);
406 return type.cast(calendar);
407 }
408
409 final String msg = toString(getClass()) + " cannot handle conversion to '"
410 + toString(type) + "'";
411 if (log().isWarnEnabled()) {
412 log().warn(" " + msg);
413 }
414 throw new ConversionException(msg);
415 }
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436 private <T> T toDate(final Class<T> type, final String value) {
437
438 if (type.equals(java.sql.Date.class)) {
439 try {
440 return type.cast(java.sql.Date.valueOf(value));
441 } catch (final IllegalArgumentException e) {
442 throw new ConversionException(
443 "String must be in JDBC format [yyyy-MM-dd] to create a java.sql.Date");
444 }
445 }
446
447
448 if (type.equals(java.sql.Time.class)) {
449 try {
450 return type.cast(java.sql.Time.valueOf(value));
451 } catch (final IllegalArgumentException e) {
452 throw new ConversionException(
453 "String must be in JDBC format [HH:mm:ss] to create a java.sql.Time");
454 }
455 }
456
457
458 if (type.equals(java.sql.Timestamp.class)) {
459 try {
460 return type.cast(java.sql.Timestamp.valueOf(value));
461 } catch (final IllegalArgumentException e) {
462 throw new ConversionException(
463 "String must be in JDBC format [yyyy-MM-dd HH:mm:ss.fffffffff] " +
464 "to create a java.sql.Timestamp");
465 }
466 }
467
468 final String msg = toString(getClass()) + " does not support default String to '"
469 + toString(type) + "' conversion.";
470 if (log().isWarnEnabled()) {
471 log().warn(" " + msg);
472 log().warn(" (N.B. Re-configure Converter or use alternative implementation)");
473 }
474 throw new ConversionException(msg);
475 }
476
477
478
479
480
481
482
483
484 protected DateFormat getFormat(final Locale locale, final TimeZone timeZone) {
485 DateFormat format = null;
486 if (locale == null) {
487 format = DateFormat.getDateInstance(DateFormat.SHORT);
488 } else {
489 format = DateFormat.getDateInstance(DateFormat.SHORT, locale);
490 }
491 if (timeZone != null) {
492 format.setTimeZone(timeZone);
493 }
494 return format;
495 }
496
497
498
499
500
501
502
503 private DateFormat getFormat(final String pattern) {
504 final DateFormat format = new SimpleDateFormat(pattern);
505 if (timeZone != null) {
506 format.setTimeZone(timeZone);
507 }
508 return format;
509 }
510
511
512
513
514
515
516
517
518
519
520
521 private Calendar parse(final Class<?> sourceType, final Class<?> targetType, final String value) throws Exception {
522 Exception firstEx = null;
523 for (String pattern : patterns) {
524 try {
525 final DateFormat format = getFormat(pattern);
526 final Calendar calendar = parse(sourceType, targetType, value, format);
527 return calendar;
528 } catch (final Exception ex) {
529 if (firstEx == null) {
530 firstEx = ex;
531 }
532 }
533 }
534 if (patterns.length > 1) {
535 throw new ConversionException("Error converting '" + toString(sourceType) + "' to '" + toString(targetType)
536 + "' using patterns '" + displayPatterns + "'");
537 } else {
538 throw firstEx;
539 }
540 }
541
542
543
544
545
546
547
548
549
550
551
552
553
554 private Calendar parse(final Class<?> sourceType, final Class<?> targetType, final String value, final DateFormat format) {
555 logFormat("Parsing", format);
556 format.setLenient(false);
557 final ParsePosition pos = new ParsePosition(0);
558 final Date parsedDate = format.parse(value, pos);
559 if (pos.getErrorIndex() >= 0 || pos.getIndex() != value.length() || parsedDate == null) {
560 String msg = "Error converting '" + toString(sourceType) + "' to '" + toString(targetType) + "'";
561 if (format instanceof SimpleDateFormat) {
562 msg += " using pattern '" + ((SimpleDateFormat)format).toPattern() + "'";
563 }
564 if (log().isDebugEnabled()) {
565 log().debug(" " + msg);
566 }
567 throw new ConversionException(msg);
568 }
569 final Calendar calendar = format.getCalendar();
570 return calendar;
571 }
572
573
574
575
576
577
578 @Override
579 public String toString() {
580 final StringBuilder buffer = new StringBuilder();
581 buffer.append(toString(getClass()));
582 buffer.append("[UseDefault=");
583 buffer.append(isUseDefault());
584 buffer.append(", UseLocaleFormat=");
585 buffer.append(useLocaleFormat);
586 if (displayPatterns != null) {
587 buffer.append(", Patterns={");
588 buffer.append(displayPatterns);
589 buffer.append('}');
590 }
591 if (locale != null) {
592 buffer.append(", Locale=");
593 buffer.append(locale);
594 }
595 if (timeZone != null) {
596 buffer.append(", TimeZone=");
597 buffer.append(timeZone);
598 }
599 buffer.append(']');
600 return buffer.toString();
601 }
602
603
604
605
606
607
608 private void logFormat(final String action, final DateFormat format) {
609 if (log().isDebugEnabled()) {
610 final StringBuilder buffer = new StringBuilder(45);
611 buffer.append(" ");
612 buffer.append(action);
613 buffer.append(" with Format");
614 if (format instanceof SimpleDateFormat) {
615 buffer.append("[");
616 buffer.append(((SimpleDateFormat)format).toPattern());
617 buffer.append("]");
618 }
619 buffer.append(" for ");
620 if (locale == null) {
621 buffer.append("default locale");
622 } else {
623 buffer.append("locale[");
624 buffer.append(locale);
625 buffer.append("]");
626 }
627 if (timeZone != null) {
628 buffer.append(", TimeZone[");
629 buffer.append(timeZone);
630 buffer.append("]");
631 }
632 log().debug(buffer.toString());
633 }
634 }
635 }