View Javadoc

1   /*
2    * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/util/TimeUtil.java,v 1.24 2006/02/05 13:39:17 hkollmann Exp $
3    * $Revision: 1.24 $
4    * $Date: 2006/02/05 13:39:17 $
5    *
6    * DbForms - a Rapid Application Development Framework
7    * Copyright (C) 2001 Joachim Peer <joepeer@excite.com>
8    *
9    * This library is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU Lesser General Public
11   * License as published by the Free Software Foundation; either
12   * version 2.1 of the License, or (at your option) any later version.
13   *
14   * This library is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this library; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22   */
23  
24  package org.dbforms.util;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  
29  import org.apache.regexp.RE;
30  import org.apache.regexp.RESyntaxException;
31  
32  /***
33   * Helper classes for dealing with time values
34   *
35   */
36  import java.text.SimpleDateFormat;
37  
38  import java.util.Calendar;
39  import java.util.Date;
40  import java.util.GregorianCalendar;
41  import java.util.TimeZone;
42  
43  
44  
45  /***
46   * DOCUMENT ME!
47   *
48   * @version $Revision: 1.24 $
49   * @author $author$
50   */
51  public class TimeUtil {
52     private static Log    logCat     = LogFactory.getLog(TimeUtil.class.getName());
53     static final int      SECSPERDAY = 24 * 60 * 60;
54     private static String reISO8601  = "(//d//d//d//d)(-(//d//d)(-(//d//d))?)?"
55                                        + "([T| ]?"
56                                        + "(//d//d):(//d//d)(:((//d//d)(//.(//d+))?)?)?"
57                                        + "(Z|([+-]//d//d://d//d)|([A-Z]{3}))?)?";
58  
59     /***
60      * Reformats seconds to time string with format: dd:hh:mm:ss
61      *
62      * @param seconds string to format
63      *
64      * @return String
65      */
66     public static final String seconds2String(String seconds) {
67        if (Util.isNull(seconds)) {
68           return "";
69        } else {
70           return seconds2String(Integer.valueOf(seconds));
71        }
72     }
73  
74  
75     /***
76      * Reformats seconds to time string with format: dd:hh:mm:ss
77      *
78      * @param seconds Integer to format
79      *
80      * @return String
81      */
82     public static final String seconds2String(Integer seconds) {
83        return seconds2String(seconds.intValue());
84     }
85  
86  
87     /***
88      * Reformats seconds to time string with format: dd:hh:mm:ss
89      *
90      * @param seconds string to format
91      *
92      * @return String
93      */
94     public static final String seconds2String(Long seconds) {
95        return seconds2String(seconds.longValue());
96     }
97  
98  
99     /***
100     * Reformats seconds to time string with format: dd:hh:mm:ss
101     *
102     * @param seconds string to format
103     *
104     * @return String
105     */
106    public static final String seconds2String(long seconds) {
107       long   d;
108       long   h;
109       long   m;
110       String zeit;
111       d       = (seconds / SECSPERDAY);
112       seconds = seconds - (d * SECSPERDAY);
113       h       = seconds / (60 * 60);
114       seconds = seconds - (h * 60 * 60);
115       m       = seconds / 60;
116       seconds = seconds - (m * 60);
117 
118       if (d > 0) {
119          Object[] o = {
120                          new Long(d),
121                          new Long(h),
122                          new Long(m),
123                          new Long(seconds)
124                       };
125          zeit = Util.sprintf("%i:%02i:%02i:%02i", o);
126       } else {
127          Object[] o = {
128                          new Long(h),
129                          new Long(m),
130                          new Long(seconds)
131                       };
132          zeit = Util.sprintf("%i:%02i:%02i", o);
133       }
134 
135       return zeit;
136    }
137 
138    /***
139     * Reformats minutes to time string with format: dd:hh:mm
140     *
141     * @param seconds string to format
142     *
143     * @return String
144     */
145    public static final String minutes2String(long minutes) {
146       long   d;
147       long   h;
148       long   m;
149       String zeit;
150       d       = (minutes / SECSPERDAY * 60);
151       minutes = minutes - (d * SECSPERDAY * 60);
152       h       = minutes / (60);
153       minutes = minutes - (h * 60);
154 
155       if (d > 0) {
156          Object[] o = {
157                          new Long(d),
158                          new Long(h),
159                          new Long(minutes)
160                       };
161          zeit = Util.sprintf("%i:%02i:%02i", o);
162       } else {
163          Object[] o = {
164                          new Long(h),
165                          new Long(minutes),
166                       };
167          zeit = Util.sprintf("%i:%02i", o);
168       }
169 
170       return zeit;
171    }
172 
173 
174    /***
175     * finds the end of the given day
176     *
177     * @param d        date of which end should be find
178     *
179     * @return end of the day
180     */
181    public static Date findEndOfDay(Date d) {
182       Calendar cal = Calendar.getInstance();
183       cal.setTime(d);
184       cal.set(Calendar.HOUR_OF_DAY, 0);
185       cal.set(Calendar.MINUTE, 0);
186       cal.set(Calendar.SECOND, 0);
187       cal.add(Calendar.DAY_OF_MONTH, 1);
188 
189       return cal.getTime();
190    }
191 
192 
193    /***
194     * Tries to parse a String into a Calendar objectvalue. String mustn't a full date,
195     * parts are enough. Parsing will set missing parts to default values
196     *
197     * @param loc      locale to use
198     * @param format   java format string for date/time
199     * @param s        string to be parsed
200     *
201     * @return the parsed date
202     */
203    public static Calendar parseDate(final SimpleDateFormat format,
204                                     String                 s) {
205       StringBuffer sDate = new StringBuffer();
206       StringBuffer sTime = new StringBuffer();
207       StringBuffer fDate = new StringBuffer();
208       StringBuffer fTime = new StringBuffer();
209 
210       splitDate(s, sDate, sTime);
211       splitDate(format.toPattern(), fDate, fTime);
212 
213       SimpleDateFormat f     = (SimpleDateFormat) format.clone();
214       Calendar         dDate = saveParseDate(f, fDate.toString(),
215                                              sDate.toString());
216       long             date = dDate.getTime()
217                                    .getTime();
218       f.setTimeZone(dDate.getTimeZone());
219 
220       long time   = saveParseTime(f, fTime.toString(), sTime.toString());
221       long offset = dDate.getTimeZone()
222                          .getRawOffset();
223 
224       if (!Util.isNull(sTime.toString())) {
225          time = time + offset;
226       }
227 
228       date = date + time;
229 
230       Calendar c = format.getCalendar();
231 
232       //20040304 JFM: replaced Calendar.setTimeInMillis(long) 
233       Date dateAsDate = new Date(date);
234       c.setTime(dateAsDate);
235 
236       logCat.info("parsed " + s + " to " + format.format(c.getTime()));
237 
238       return c;
239    }
240 
241 
242    /***
243     * Parses an ISO8601 date format string
244     *
245     * @param s        string to be parsed
246     *
247     * @return the parsed date
248     */
249    public static Date parseISO8601Date(String s) {
250       ISO8601 iso = parseISO8601(s);
251 
252       if (iso != null) {
253          TimeZone tz = null;
254 
255          // see if setting tz first fixes tz bug
256          if ((iso.tz != null) && !(iso.tz.length() == 0)) {
257             if (iso.tz.equals("Z")) {
258                tz = TimeZone.getTimeZone("GMT");
259             } else if (iso.tz.length() == 3) {
260                tz = TimeZone.getTimeZone(iso.tz);
261             } else {
262                tz = TimeZone.getTimeZone("GMT" + iso.tz);
263             }
264          }
265 
266          Calendar cal = new GregorianCalendar(iso.year, iso.month - 1, iso.day,
267                                               iso.hour, iso.min, iso.sec);
268 
269          if (tz != null) {
270             cal.setTimeZone(tz);
271          }
272 
273          return cal.getTime();
274       }
275 
276       // if iso
277       return null;
278    }
279 
280 
281    private static ISO8601 parseISO8601(String s) {
282       // ISO 8601 datetime: http://www.w3.org/TR/NOTE-datetime
283       // e.g. 1997-07-16T19:20:30.45+01:00
284       // additions: "T" can be a space, TZ can be a three-char code, TZ can be missing
285       try {
286          RE re = new RE(reISO8601);
287 
288          if (re.match(s)) {
289             ISO8601 iso = new ISO8601();
290             iso.year  = toInt(re.getParen(1));
291             iso.month = toInt(re.getParen(3));
292             iso.day   = toInt(re.getParen(5));
293             iso.hour  = toInt(re.getParen(7));
294             iso.min   = toInt(re.getParen(8));
295             iso.sec   = toInt(re.getParen(11));
296             iso.frac  = toInt(re.getParen(13));
297             iso.tz    = re.getParen(14);
298 
299             return iso;
300          }
301       }
302       // try
303       catch (RESyntaxException ree) {
304          ree.printStackTrace();
305       }
306 
307       return null;
308    }
309 
310 
311    private static Calendar saveParseDate(final SimpleDateFormat format,
312                                          String                 formatString,
313                                          String                 s)
314                                   throws NumberFormatException {
315       Date     d   = null;
316       Calendar cal;
317       Calendar now = Calendar.getInstance();
318 
319       if (!Util.isNull(s)) {
320          if (!Util.isNull(formatString)) {
321             format.applyPattern(formatString);
322          }
323 
324          try {
325             d = format.parse(s);
326          } catch (Exception e) {
327             logCat.error(e);
328 
329             // Make parsing more tolerant - try sql standard format too
330             SimpleDateFormat f = (SimpleDateFormat) format.clone();
331             f.applyPattern("yyyy-MM-dd");
332 
333             try {
334                d = f.parse(s);
335             } catch (Exception ex) {
336                logCat.error(ex);
337             }
338          }
339 
340          cal = format.getCalendar();
341 
342          if (d != null) {
343             cal.setTime(d);
344          } else {
345             synchronized (cal) {
346                try {
347                   // HKK: I do not know why this is necessary, but if you do not wait
348                   //      the calender HOUR_OF_DAY maybe unset...
349                   cal.wait(5);
350                } catch (Exception ex) {
351                   logCat.error(ex);
352                }
353             }
354          }
355 
356          if (!cal.isSet(Calendar.DAY_OF_MONTH)
357                    && !cal.isSet(Calendar.MONTH)
358                    && !cal.isSet(Calendar.YEAR)) {
359             throw new NumberFormatException("wrong date format");
360          }
361 
362          if (!cal.isSet(Calendar.DAY_OF_MONTH)) {
363             cal.set(Calendar.DAY_OF_MONTH, now.get(Calendar.DAY_OF_MONTH));
364          }
365 
366          if (!cal.isSet(Calendar.MONTH)) {
367             cal.set(Calendar.MONTH, now.get(Calendar.MONTH));
368          }
369 
370          if (!cal.isSet(Calendar.YEAR)) {
371             cal.set(Calendar.YEAR, now.get(Calendar.YEAR));
372          }
373 
374          if (cal.get(Calendar.YEAR) < 30) {
375             cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + 2000);
376          } else if (cal.get(Calendar.YEAR) < 100) {
377             cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + 1900);
378          }
379       } else {
380          cal = now;
381       }
382 
383       cal.set(Calendar.HOUR_OF_DAY, 0);
384       cal.set(Calendar.MINUTE, 0);
385       cal.set(Calendar.SECOND, 0);
386 
387       return cal;
388    }
389 
390 
391    private static synchronized long saveParseTime(final SimpleDateFormat format,
392                                                   String                 formatString,
393                                                   String                 s) {
394       Date d = null;
395 
396       if (!Util.isNull(s)) {
397          if (!Util.isNull(formatString)) {
398             format.applyPattern(formatString);
399          }
400 
401          try {
402             d = format.parse(s);
403          } catch (Exception e) {
404             logCat.error(e);
405 
406             // Make parsing more tolerant - try 24 hour formats too
407             SimpleDateFormat f = (SimpleDateFormat) format.clone();
408             f.applyPattern("HH:mm:ss");
409 
410             try {
411                d = f.parse(s);
412             } catch (Exception ex) {
413                logCat.error(ex);
414             }
415          }
416 
417          Calendar cal = format.getCalendar();
418 
419          if (d != null) {
420             cal.setTime(d);
421          } else {
422             synchronized (cal) {
423                try {
424                   // HKK: I do not know why this is necessary, but if you do not wait
425                   //      the calender HOUR_OF_DAY maybe unset...
426                   cal.wait(5);
427                } catch (Exception ex) {
428                   logCat.error(ex);
429                }
430             }
431          }
432 
433          if (!cal.isSet(Calendar.HOUR_OF_DAY)
434                    && !cal.isSet(Calendar.MINUTE)
435                    && !cal.isSet(Calendar.SECOND)) {
436             throw new NumberFormatException("wrong time format");
437          }
438 
439          if (!cal.isSet(Calendar.HOUR_OF_DAY)) {
440             cal.set(Calendar.HOUR_OF_DAY, 0);
441          }
442 
443          if (!cal.isSet(Calendar.MINUTE)) {
444             cal.set(Calendar.MINUTE, 0);
445          }
446 
447          if (!cal.isSet(Calendar.SECOND)) {
448             cal.set(Calendar.SECOND, 0);
449          }
450 
451          return cal.getTime()
452                    .getTime();
453       }
454 
455       return 0;
456    }
457 
458 
459    public static void splitDate(final String format,
460                                  StringBuffer sDate,
461                                  StringBuffer sTime) {
462       sDate.setLength(0);
463       sTime.setLength(0);
464 
465       int i = format.lastIndexOf(':');
466 
467       if (i > -1) {
468          i = format.lastIndexOf(' ', i);
469 
470          if (i > -1) {
471             sDate.append(format.substring(0, i));
472             sTime.append(format.substring(i + 1));
473          } else {
474             sTime.append(format);
475          }
476       } else {
477          sDate.append(format);
478       }
479    }
480 
481 
482    private static int toInt(String x) {
483       if (x == null) {
484          return 0;
485       }
486 
487       try {
488          return Integer.parseInt(x);
489       } catch (NumberFormatException e) {
490          return 0;
491       }
492    }
493 
494    /***
495     * Parses an ISO8601 date format string
496     *
497     */
498    private static class ISO8601 {
499       public String tz;
500       public int    day;
501       public int    frac;
502       public int    hour;
503       public int    min;
504       public int    month;
505       public int    sec;
506       public int    year;
507    }
508 }