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