1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.core.impl.datetime;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.apache.commons.lang.time.DurationFormatUtils;
20 import org.joda.time.DateTime;
21 import org.kuali.rice.core.api.datetime.DateTimeService;
22 import org.kuali.rice.core.api.CoreConstants;
23 import org.kuali.rice.core.api.config.property.ConfigContext;
24 import org.springframework.beans.factory.InitializingBean;
25
26 import java.sql.Time;
27 import java.sql.Timestamp;
28 import java.text.DateFormat;
29 import java.text.ParseException;
30 import java.text.ParsePosition;
31 import java.text.SimpleDateFormat;
32 import java.util.Arrays;
33 import java.util.Calendar;
34 import java.util.Collections;
35 import java.util.Date;
36 import java.util.List;
37
38
39
40
41
42
43 public class DateTimeServiceImpl implements DateTimeService, InitializingBean {
44
45 protected String[] stringToDateFormats;
46 protected String[] stringToTimeFormats;
47 protected String[] stringToTimestampFormats;
48 protected String dateToStringFormatForUserInterface;
49 protected String timeToStringFormatForUserInterface;
50 protected String timestampToStringFormatForUserInterface;
51 protected String dateToStringFormatForFileName;
52 protected String timestampToStringFormatForFileName;
53
54
55
56
57
58 public String toDateString(Date date) {
59 return toString(date, dateToStringFormatForUserInterface);
60 }
61
62
63
64
65 public String toTimeString(Time time) {
66 return toString(time, timeToStringFormatForUserInterface);
67 }
68
69
70
71
72 public String toDateTimeString(Date date) {
73 return toString(date, timestampToStringFormatForUserInterface);
74 }
75
76
77
78
79
80 public String toString(Date date, String pattern) {
81 DateFormat dateFormat = new SimpleDateFormat(pattern);
82 dateFormat.setLenient(false);
83 return dateFormat.format(date);
84 }
85
86
87
88
89 public Date getCurrentDate() {
90 Calendar c = Calendar.getInstance();
91 c.setTime(new Date());
92 return c.getTime();
93 }
94
95
96
97
98 public Timestamp getCurrentTimestamp() {
99 return new java.sql.Timestamp(getCurrentDate().getTime());
100 }
101
102
103
104
105 public java.sql.Date getCurrentSqlDate() {
106 return new java.sql.Date(getCurrentDate().getTime());
107 }
108
109
110
111
112 public java.sql.Date getCurrentSqlDateMidnight() {
113
114 return java.sql.Date.valueOf(getCurrentSqlDate().toString());
115 }
116
117
118
119
120 public Calendar getCurrentCalendar() {
121 return getCalendar(getCurrentDate());
122 }
123
124
125
126
127 public Calendar getCalendar(Date date) {
128 if (date == null) {
129 throw new IllegalArgumentException("invalid (null) date");
130 }
131
132 Calendar currentCalendar = Calendar.getInstance();
133 currentCalendar.setTime(date);
134
135 return currentCalendar;
136 }
137
138
139
140
141
142
143 public Date convertToDate(String dateString) throws ParseException {
144 return parseAgainstFormatArray(dateString, stringToDateFormats);
145 }
146
147
148
149
150 public Date convertToDateTime(String dateTimeString) throws ParseException {
151 if (StringUtils.isBlank(dateTimeString)) {
152 throw new IllegalArgumentException("invalid (blank) date/time string");
153 }
154 return parseAgainstFormatArray(dateTimeString, stringToTimestampFormats);
155 }
156
157
158
159
160 public java.sql.Timestamp convertToSqlTimestamp(String timeString)
161 throws ParseException {
162 if (!StringUtils.isBlank(timeString)) {
163 return new java.sql.Timestamp(convertToDateTime(timeString).getTime());
164 }
165 return null;
166 }
167
168
169
170
171 public java.sql.Date convertToSqlDate(String dateString)
172 throws ParseException {
173 if (StringUtils.isBlank(dateString)) {
174 throw new IllegalArgumentException("invalid (blank) dateString");
175 }
176 Date date = parseAgainstFormatArray(dateString, stringToDateFormats);
177 return new java.sql.Date(date.getTime());
178 }
179
180
181
182
183 public java.sql.Date convertToSqlDateUpperBound(String dateString)
184 throws ParseException {
185 java.sql.Date date = convertToSqlDate(dateString);
186 DateTime dateUpperBound = new DateTime(date).plusDays(1);
187 return new java.sql.Date(dateUpperBound.getMillis());
188 }
189
190
191
192
193 public java.sql.Time convertToSqlTime(String timeString)
194 throws ParseException {
195 if (StringUtils.isBlank(timeString)) {
196 throw new IllegalArgumentException("invalid (blank) dateString");
197 }
198 Date date = parseAgainstFormatArray(timeString, stringToTimeFormats);
199 return new java.sql.Time(date.getTime());
200 }
201
202 protected Date parseAgainstFormatArray(String dateString, String[] formats) throws ParseException {
203 dateString = dateString.trim();
204 StringBuffer exceptionMessage = new StringBuffer("Date or date/time string '")
205 .append(dateString)
206 .append("' could not be converted using any of the accepted formats: ");
207 for (String dateFormatString : formats) {
208 try {
209 return parse(dateString, dateFormatString);
210 } catch (ParseException e) {
211 exceptionMessage.append(dateFormatString).append(
212 " (error offset=").append(e.getErrorOffset()).append(
213 "),");
214 }
215 }
216 throw new ParseException(exceptionMessage.toString().substring(0,
217 exceptionMessage.length() - 1), 0);
218 }
219
220
221
222
223
224 public java.sql.Date convertToSqlDate(Timestamp timestamp)
225 throws ParseException {
226 return new java.sql.Date(timestamp.getTime());
227 }
228
229 public int dateDiff(Date startDate, Date endDate, boolean inclusive) {
230 Calendar startDateCalendar = Calendar.getInstance();
231 startDateCalendar.setTime(startDate);
232
233 Calendar endDateCalendar = Calendar.getInstance();
234 endDateCalendar.setTime(endDate);
235
236 int startDateOffset = -(startDateCalendar.get(Calendar.ZONE_OFFSET) + startDateCalendar
237 .get(Calendar.DST_OFFSET))
238 / (60 * 1000);
239
240 int endDateOffset = -(endDateCalendar.get(Calendar.ZONE_OFFSET) + endDateCalendar
241 .get(Calendar.DST_OFFSET))
242 / (60 * 1000);
243
244 if (startDateOffset > endDateOffset) {
245 startDateCalendar.add(Calendar.MINUTE, endDateOffset
246 - startDateOffset);
247 }
248
249 if (inclusive) {
250 startDateCalendar.add(Calendar.DATE, -1);
251 }
252
253 int dateDiff = Integer.parseInt(DurationFormatUtils.formatDuration(
254 endDateCalendar.getTimeInMillis()
255 - startDateCalendar.getTimeInMillis(), "d", true));
256
257 return dateDiff;
258 }
259
260 protected Date parse(String dateString, String pattern) throws ParseException {
261 if (!StringUtils.isBlank(dateString)) {
262 DateFormat dateFormat = new SimpleDateFormat(pattern);
263 dateFormat.setLenient(false);
264 ParsePosition parsePosition = new ParsePosition(0);
265 Date testDate = dateFormat.parse(dateString, parsePosition);
266
267
268 if (testDate == null) {
269 throw new ParseException("The date that you provided is invalid.",parsePosition.getErrorIndex());
270 } else if (parsePosition.getIndex() != dateString.length()) {
271 throw new ParseException("The date that you provided is invalid.",parsePosition.getIndex());
272 }
273
274
275 Calendar testCalendar = Calendar.getInstance();
276 testCalendar.setLenient(false);
277 testCalendar.setTime(testDate);
278 if (testCalendar.get(Calendar.YEAR) < 1000 || testCalendar.get(Calendar.YEAR) > 9999) {
279 throw new ParseException("The date that you provided is not between the years 1000 and 9999.",-1);
280 }
281
282 if(testCalendar.get(Calendar.YEAR) == 1970 && !pattern.contains("y".toLowerCase())){
283 Calendar curCalendar = Calendar.getInstance();
284 curCalendar.setTime(new java.util.Date());
285 testCalendar.set(Calendar.YEAR, curCalendar.get(Calendar.YEAR));
286 testDate = testCalendar.getTime();
287 }
288
289 return testDate;
290 }
291 return null;
292 }
293
294
295
296
297 public String toDateStringForFilename(Date date) {
298 SimpleDateFormat dateFormat = new SimpleDateFormat(dateToStringFormatForFileName);
299 return dateFormat.format(date);
300 }
301
302
303
304
305 public String toDateTimeStringForFilename(Date date) {
306 SimpleDateFormat dateFormat = new SimpleDateFormat(timestampToStringFormatForFileName);
307 return dateFormat.format(date);
308 }
309
310
311
312
313
314
315
316 @Override
317 public void afterPropertiesSet() throws Exception {
318 if (stringToDateFormats == null) {
319 stringToDateFormats = loadAndValidateFormats(CoreConstants.STRING_TO_DATE_FORMATS, CoreConstants.STRING_TO_DATE_FORMATS_DEFAULT);
320 }
321
322 if (stringToTimeFormats == null) {
323 stringToTimeFormats = loadAndValidateFormats(CoreConstants.STRING_TO_TIME_FORMATS, CoreConstants.STRING_TO_TIME_FORMATS_DEFAULT);
324 }
325
326 if (stringToTimestampFormats == null) {
327 stringToTimestampFormats = loadAndValidateFormats(CoreConstants.STRING_TO_TIMESTAMP_FORMATS, CoreConstants.STRING_TO_TIMESTAMP_FORMATS_DEFAULT);
328 }
329
330 if (dateToStringFormatForUserInterface == null) {
331 dateToStringFormatForUserInterface = loadAndValidateFormat(CoreConstants.DATE_TO_STRING_FORMAT_FOR_USER_INTERFACE, CoreConstants.DATE_TO_STRING_FORMAT_FOR_USER_INTERFACE_DEFAULT);
332 }
333
334 if (timeToStringFormatForUserInterface == null) {
335 timeToStringFormatForUserInterface = loadAndValidateFormat(CoreConstants.TIME_TO_STRING_FORMAT_FOR_USER_INTERFACE, CoreConstants.TIME_TO_STRING_FORMAT_FOR_USER_INTERFACE_DEFAULT);
336 }
337
338 if (timestampToStringFormatForUserInterface == null) {
339 timestampToStringFormatForUserInterface = loadAndValidateFormat(CoreConstants.TIMESTAMP_TO_STRING_FORMAT_FOR_USER_INTERFACE, CoreConstants.TIMESTAMP_TO_STRING_FORMAT_FOR_USER_INTERFACE_DEFAULT);
340 }
341
342 if (dateToStringFormatForFileName == null) {
343 dateToStringFormatForFileName = loadAndValidateFormat(CoreConstants.DATE_TO_STRING_FORMAT_FOR_FILE_NAME, CoreConstants.DATE_TO_STRING_FORMAT_FOR_FILE_NAME_DEFAULT);
344 }
345
346 if (timestampToStringFormatForFileName == null) {
347 timestampToStringFormatForFileName = loadAndValidateFormat(CoreConstants.TIMESTAMP_TO_STRING_FORMAT_FOR_FILE_NAME, CoreConstants.TIMESTAMP_TO_STRING_FORMAT_FOR_FILE_NAME_DEFAULT);
348 }
349 }
350
351
352
353
354
355
356
357
358
359 private List<String> parseConfigValues(String configValue) {
360 if (configValue == null || "".equals(configValue)) {
361 return Collections.emptyList();
362 }
363 return Arrays.asList(configValue.split(";"));
364 }
365
366
367
368
369
370
371
372 private List<String> loadFormats(String property, String deflt) {
373 return parseConfigValues(loadFormat(property, deflt));
374 }
375
376
377
378
379
380
381
382 private String[] loadAndValidateFormats(String property, String deflt) {
383 List<String> dateFormatParams = loadFormats(property, deflt);
384
385 String[] validFormats = new String[dateFormatParams.size()];
386
387 for (int i = 0; i < dateFormatParams.size(); i++) {
388 String dateFormatParam = dateFormatParams.get(i);
389 if (StringUtils.isBlank(dateFormatParam)) {
390 throw new IllegalArgumentException("Core/All/" + property + " parameter contains a blank semi-colon delimited substring");
391 }
392 else {
393
394 new SimpleDateFormat(dateFormatParam);
395 validFormats[i] = dateFormatParam;
396 }
397 }
398
399 return validFormats;
400 }
401
402
403
404
405
406
407
408 private String loadFormat(String property, String deflt) {
409 String format = ConfigContext.getCurrentContextConfig().getProperty(property);
410 if (StringUtils.isBlank(format)) {
411 format = deflt;
412 }
413 return format;
414 }
415
416
417
418
419
420
421
422
423 private String loadAndValidateFormat(String property, String deflt) {
424 String format = loadFormat(property, deflt);
425
426 new SimpleDateFormat(format);
427 return format;
428 }
429 }