001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.util;
011:
012: import java.text.*;
013: import java.text.DateFormat;
014: import java.text.SimpleDateFormat;
015: import java.util.*;
016: import java.util.Calendar;
017: import java.util.Date;
018: import java.util.StringTokenizer;
019: import java.util.TimeZone;
020:
021: import org.mmbase.util.logging.Logger;
022: import org.mmbase.util.logging.Logging;
023:
024: /**
025: * Some routines to support dates better<br /><br />
026: *
027: * The problem that generally occurs is with timezones. Therefore, we have made the following structure:<br />
028: * <ul>
029: * <li> If a date is stored in a database, it is in GMT
030: * <li> If a date is displayed, it happens in the timezone of the machine that is calling.
031: * </ul>
032: * This means that some timezone conversions have to be made.
033: * We assume nothing about timezones, we just read the value specified by the system (Timezone.getDefault() call).
034: *
035: * @deprecated use Calendar and java.util.DateFormat
036: * @author Rico Jansen
037: * @author Johannes Verelst
038: * @version $Id: DateSupport.java,v 1.29 2008/02/03 17:33:57 nklasens Exp $
039: */
040: public class DateSupport {
041:
042: // logger
043: private static Logger log = Logging
044: .getLoggerInstance(DateSupport.class);
045:
046: /**
047: * The offset for date conversions for the current zone, in seconds
048: */
049: static int offset = 0;
050: /**
051: * Whether to sue the offset.
052: * Set to <code>true</code> when initialization of this class succeeds.
053: */
054: static boolean dooffset = true;
055:
056: /**
057: * Return the number of days in the month in a specified year.
058: * Leap years have to be taken into account
059: *
060: * @param year The year valid values 0..100 where 0 is y2k 2000 untill 89 => 2089 and 90 being the year 1990
061: * @param month The month where 0 is januari
062: */
063: static public int daysInMonth(int year, int month) {
064: int months[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
065: int days = months[month];
066: year = (year < 90) ? year + 2000 : year + 1900;
067:
068: // Make an exception for the intercalary day.
069: if (month == 1) {
070: if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
071: days = 29;
072: }
073: return days;
074: }
075:
076: /**
077: * Return the number of seconds that have elapsed from the beginning of the year to the given date
078: *
079: * @param d The date
080: * @return The number of secods from January 1 to the given date
081: * @see DateSupport#daysInMonth
082: * @see DateSupport#dayInYear
083: * @see DateSupport#weekInYear
084: */
085: static public int secondInYear(Date d) {
086: Calendar c = Calendar.getInstance();
087: c.setTime(d);
088: return c.get(Calendar.DAY_OF_YEAR) * (60 * 60 * 24)
089: + c.get(Calendar.HOUR_OF_DAY) * (24 * 60)
090: + c.get(Calendar.SECOND);
091: }
092:
093: /**
094: * Return the number of days that have elapsed from the beginning of the year to the given date
095: *
096: * @param d The date
097: * @return The number of days from January 1 to the given date
098: * @see DateSupport#daysInMonth
099: * @see DateSupport#secondInYear
100: * @see DateSupport#weekInYear
101: */
102: static public int dayInYear(Date d) {
103: Calendar c = Calendar.getInstance();
104: c.setTime(d);
105: return c.get(Calendar.DAY_OF_YEAR);
106: }
107:
108: /**
109: * Return the number of weeks that have elapsed from the beginning of the year to the given date
110: *
111: * @param d The date
112: * @return The number of weeks from January 1 to the given date
113: * @see DateSupport#daysInMonth
114: * @see DateSupport#secondInYear
115: * @see DateSupport#dayInYear
116: */
117: static public int weekInYear(Date d) {
118: Calendar c = Calendar.getInstance();
119: c.setTime(d);
120: return c.get(Calendar.WEEK_OF_YEAR);
121: }
122:
123: /**
124: * Return the number milliseconds elapsed from 1-Jan-1970 to the beginning of the given week.
125: *
126: * @param year The year
127: * @param week The number of the week
128: * @return The number of milliseconds between 1-Jan-1970 and the begin of the given week.
129: */
130: static public long milliDate(int year, int week) {
131: Calendar calendar = Calendar.getInstance();
132: calendar.set(year, 0, 0);
133: calendar.set(Calendar.WEEK_OF_YEAR, week);
134: Date d = calendar.getTime();
135: return d.getTime();
136: }
137:
138: /**
139: * Return a date, based on a year, a week and the day of that week <br />
140: * For instance: 1999, 40, 4 = The 4th day of the 40th week of 1999
141: *
142: * @param year The year
143: * @param week The week
144: * @param day The number of the day in the week
145: * @return A date-object for the given date
146: */
147: static public Date Date(int year, int week, int day) {
148: Calendar cal = Calendar.getInstance();
149: cal.set(Calendar.YEAR, year);
150: cal.set(Calendar.WEEK_OF_YEAR, week);
151: cal.set(Calendar.DAY_OF_WEEK, day);
152: return cal.getTime();
153: }
154:
155: /**
156: * Create date strings in the form yyyy-mm-dd for a given Date object
157: * <br />This format is used in several database (dbm's)
158: * @param da The date input
159: * @return A string in the form yyyy-mm-dd
160: * @see DateSupport#parsedbmdate
161: */
162: public static String makedbmdate(Date da) {
163: SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd",
164: Locale.ENGLISH);
165: return f.format(da);
166: }
167:
168: /**
169: * Parse date strings in the form yyyy-mm-dd
170: * <br />This format is used in several database (dbm's)
171: * @param wh The string representing the date in 'yyyy-mm-dd' format
172: * @return A Date object for the given date
173: * @see DateSupport#makedbmdate
174: */
175: public static Date parsedbmdate(String wh) {
176: SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd",
177: Locale.ENGLISH);
178:
179: //for bw comp
180: if (wh.indexOf('/') != -1) {
181: f = new SimpleDateFormat("yyyy/MM/dd", Locale.ENGLISH);
182: }
183: try {
184: return f.parse(wh);
185: } catch (ParseException e) {
186: //idem for bw comp
187: return new Date();
188: }
189: }
190:
191: /**
192: * Puts a colon between a time of RFC-1223 format
193: *
194: * @param time A string in RFC-1223 format
195: * @return A string with an extra colon
196: */
197: public static String colontime(String time) {
198: if (time.length() == 4) {
199: return time.substring(0, 2) + ":" + time.substring(2, 4);
200: }
201: return time;
202: }
203:
204: /**
205: * Returns the number of seconds from 1-Jan-1970 to a given date
206: *
207: * @param sDate String in the form 'yyyyMMdd'
208: * @return Number of seconds from 1-Jan-1970
209: * @see DateSupport#parsetime
210: * @see DateSupport#parsedatetime
211: */
212: public static int parsedate(String sDate) {
213: SimpleDateFormat df = (SimpleDateFormat) DateFormat
214: .getDateTimeInstance();
215: TimeZone tz;
216: df.applyLocalizedPattern("yyyyMMdd");
217:
218: tz = TimeZone.getDefault();
219: df.setTimeZone(tz);
220:
221: Date date = null;
222: try {
223: date = df.parse(sDate);
224: } catch (java.text.ParseException e) {
225: log.error(e.toString());
226: }
227:
228: if (date != null)
229: return (int) ((date.getTime() - getMilliOffset()) / 1000);
230: else
231: return -1;
232: }
233:
234: /**
235: * Returns the number of seconds from 00:00:00 to a given time
236: *
237: * @param wh Time in the form 'hhmmss'
238: * @return Number of seconds from 00:00:00 to the given time
239: * @see DateSupport#parsedate
240: * @see DateSupport#parsedatetime
241: */
242: public static int parsetime(String wh) {
243: int h = 0, m = 0, s = 0;
244: try {
245: h = Integer.parseInt(wh.substring(0, 2));
246: m = Integer.parseInt(wh.substring(2, 4));
247: s = Integer.parseInt(wh.substring(4, 6));
248: } catch (Exception e) {
249: log.error("DateSupport: maketime (" + wh + ")");
250: }
251: return s + 60 * (m + 60 * h);
252: }
253:
254: /**
255: * Returns the number of seconds from 1-Jan-1970 00:00:00 to a given time
256: *
257: * @param wh Date in the form 'yyyymmddhhmmss'
258: * @return Number of seconds from 1-Jan-1970 00:00:00 to the given time
259: * @see DateSupport#parsedate
260: * @see DateSupport#parsetime
261: */
262: public static int parsedatetime(String wh) {
263: return parsedate(wh.substring(0, 8))
264: + parsetime(wh.substring(8, 14));
265: }
266:
267: /**
268: * Takes an integer representing the number of seconds from 1-Jan-1970 00:00:00 and returns the time as a string
269: *
270: * @param val Number of seconds from 1-Jan-1970 00:00:00
271: * @return String in the form 'hhmm' for the given time
272: * @see DateSupport#getTimeSec
273: * @see DateSupport#getTimeSecLen
274: * @see DateSupport#getMonthDay
275: * @see DateSupport#getMonth
276: * @see DateSupport#getYear
277: * @see DateSupport#getMonthInt
278: * @see DateSupport#getWeekDayInt
279: * @see DateSupport#getDayInt
280: */
281: public static String getTime(int val) {
282: if (dooffset) {
283: val += offset;
284: }
285: Date v = new Date((long) val * 1000);
286: SimpleDateFormat f = new SimpleDateFormat("HH:mm");
287: return f.format(v);
288: }
289:
290: /**
291: * Takes an integer representing the number of seconds from 1-Jan-1970 00:00:00 and returns the time as a string
292: *
293: * @param val Number of seconds from 1-Jan-1970 00:00:00
294: * @return String in the form 'hhmmss' for the given time
295: * @see DateSupport#getTime
296: * @see DateSupport#getTimeSecLen
297: * @see DateSupport#getMonthDay
298: * @see DateSupport#getMonth
299: * @see DateSupport#getYear
300: * @see DateSupport#getMonthInt
301: * @see DateSupport#getWeekDayInt
302: * @see DateSupport#getDayInt
303: */
304: public static String getTimeSec(int val) {
305: Date v;
306: if (val == -1) {
307: // WHY? This behaviour leads to incorrect displaying of MMEvents!!
308: v = new Date();
309: } else {
310: if (dooffset) {
311: val += offset;
312: }
313: v = new Date((long) val * 1000);
314: }
315: SimpleDateFormat f = new SimpleDateFormat("HH:mm:ss");
316: return f.format(v);
317: }
318:
319: /**
320: * Takes an integer representing the number of seconds from 00:00:00 and returns the time as a string
321: *
322: * @param val Number of seconds from 00:00:00
323: * @return String in the form 'hhmmss' for the given time
324: * @see DateSupport#getTime
325: * @see DateSupport#getTimeSec
326: * @see DateSupport#getMonthDay
327: * @see DateSupport#getMonth
328: * @see DateSupport#getYear
329: * @see DateSupport#getMonthInt
330: * @see DateSupport#getWeekDayInt
331: * @see DateSupport#getDayInt
332: */
333: public static String getTimeSecLen(int val) {
334: Date date = new Date((long) val * 1000);
335: SimpleDateFormat f = new SimpleDateFormat("HH:mm:ss");
336: f.setTimeZone(TimeZone.getTimeZone("GMT"));
337: return f.format(date);
338: }
339:
340: /**
341: * Takes an integer representing the number of seconds from 1-Jan-1970 00:00:00 and returns the day in the month
342: *
343: * @param val Number of seconds from 1-Jan-1970 00:00:00
344: * @return String containing the day of the month (1 to 31)
345: * @see DateSupport#getTime
346: * @see DateSupport#getTimeSec
347: * @see DateSupport#getTimeSecLen
348: * @see DateSupport#getMonth
349: * @see DateSupport#getYear
350: * @see DateSupport#getMonthInt
351: * @see DateSupport#getWeekDayInt
352: * @see DateSupport#getDayInt
353: */
354: public static String getMonthDay(int val) {
355: if (dooffset) {
356: val += offset;
357: }
358: Date v = new Date((long) val * 1000);
359: SimpleDateFormat f = new SimpleDateFormat("dd");
360: return f.format(v);
361: }
362:
363: /**
364: * Takes an integer representing the number of seconds from 1-Jan-1970 00:00:00 and returns the number of the month
365: *
366: * @param val Number of seconds from 1-Jan-1970 00:00:00
367: * @return String containing the number of the month (1 to 12)
368: * @see DateSupport#getTime
369: * @see DateSupport#getTimeSec
370: * @see DateSupport#getTimeSecLen
371: * @see DateSupport#getMonthDay
372: * @see DateSupport#getYear
373: * @see DateSupport#getMonthInt
374: * @see DateSupport#getWeekDayInt
375: * @see DateSupport#getDayInt
376: */
377: public static String getMonth(int val) {
378: if (dooffset) {
379: val += offset;
380: }
381: Date v = new Date((long) val * 1000);
382: SimpleDateFormat f = new SimpleDateFormat("MM");
383: return f.format(v);
384: }
385:
386: /**
387: * Takes an integer representing the number of seconds from 1-Jan-1970 00:00:00 and returns the year
388: *
389: * @param val Number of seconds from 1-Jan-1970 00:00:00
390: * @return String containing the year (1900 to ....)
391: * @see DateSupport#getTime
392: * @see DateSupport#getTimeSec
393: * @see DateSupport#getTimeSecLen
394: * @see DateSupport#getMonthDay
395: * @see DateSupport#getMonth
396: * @see DateSupport#getMonthInt
397: * @see DateSupport#getWeekDayInt
398: * @see DateSupport#getDayInt
399: */
400: public static String getYear(int val) {
401: //log.debug(val);
402: if (dooffset) {
403: val += offset;
404: }
405: Date v = new Date(((long) val) * 1000);
406: Calendar c = Calendar.getInstance();
407: c.setTime(v);
408:
409: return Integer.toString(c.get(Calendar.YEAR));
410: }
411:
412: /**
413: * Takes an integer representing the number of seconds from 1-Jan-1970 00:00:00 and returns the month as an integer
414: *
415: * @param val Number of seconds from 1-Jan-1970 00:00:00
416: * @return Integer containing the value of the month (1 to 12)
417: * @see DateSupport#getTime
418: * @see DateSupport#getTimeSec
419: * @see DateSupport#getTimeSecLen
420: * @see DateSupport#getMonthDay
421: * @see DateSupport#getMonth
422: * @see DateSupport#getYear
423: * @see DateSupport#getWeekDayInt
424: * @see DateSupport#getDayInt
425: */
426: public static int getMonthInt(int val) {
427: if (dooffset) {
428: val += offset;
429: }
430: Date v = new Date((long) val * 1000);
431: Calendar c = Calendar.getInstance();
432: c.setTime(v);
433: return c.get(Calendar.MONTH);
434: }
435:
436: /**
437: * Takes an integer representing the number of seconds from 1-Jan-1970 00:00:00
438: * and returns the number of the day in the week as an integer
439: *
440: * @param val Number of seconds from 1-Jan-1970 00:00:00
441: * @return Integer containing the number of the day in the week (0 to 6)
442: * @see DateSupport#getTime
443: * @see DateSupport#getTimeSec
444: * @see DateSupport#getTimeSecLen
445: * @see DateSupport#getMonthDay
446: * @see DateSupport#getMonth
447: * @see DateSupport#getYear
448: * @see DateSupport#getMonthInt
449: * @see DateSupport#getDayInt
450: */
451: public static int getWeekDayInt(int val) {
452: if (dooffset) {
453: val += offset;
454: }
455: Date v = new Date((long) val * 1000);
456: Calendar c = Calendar.getInstance();
457: c.setTime(v);
458: return c.get(Calendar.DAY_OF_WEEK) - 1;
459: }
460:
461: /**
462: * Takes an integer representing the number of seconds from 1-Jan-1970 00:00:00
463: * and returns the number of the day in the month as an integer
464: *
465: * @param val Number of seconds from 1-Jan-1970 00:00:00
466: * @return Integer containing the number of the day in the month (1 to 31)
467: * @see DateSupport#getTime
468: * @see DateSupport#getTimeSec
469: * @see DateSupport#getTimeSecLen
470: * @see DateSupport#getMonthDay
471: * @see DateSupport#getMonth
472: * @see DateSupport#getYear
473: * @see DateSupport#getMonthInt
474: * @see DateSupport#getWeekDayInt
475: */
476: public static int getDayInt(int val) {
477: if (dooffset) {
478: val += offset;
479: }
480: Date v = new Date((long) val * 1000);
481: Calendar c = Calendar.getInstance();
482: c.setTime(v);
483: return c.get(Calendar.DAY_OF_MONTH);
484: }
485:
486: /**
487: * Return the time-difference between our timezone and GMT
488: *
489: * @return Integer containing the number of milliseconds representing the time-difference between us and GMT
490: */
491: public static long getMilliOffset() {
492: if (!dooffset) {
493: // Do not worry about the code below, since it will never be called
494:
495: TimeZone tz1, tz2;
496: int off1, off2;
497: Date d = new Date();
498:
499: tz1 = TimeZone.getDefault(); // This is MET but they think it's the Middle East
500: tz2 = TimeZone.getTimeZone("ECT"); //Apparently we live there ?
501: off1 = tz1.getRawOffset();
502: off2 = tz2.getRawOffset();
503: if (tz1.inDaylightTime(d)) {
504: off1 += (3600 * 1000); // Activate before sunday morning
505: }
506:
507: if (tz2.inDaylightTime(d)) {
508: off2 += (3600 * 1000);
509: }
510: return off1 - off2;
511: } else {
512: return (long) offset * 1000;
513: }
514: }
515:
516: /**
517: * Return the current time in milliseconds (for the current-timezone!!)
518: *
519: * @return Integer containing the number of milliseconds representing the current time
520: */
521: public static long currentTimeMillis() {
522: return System.currentTimeMillis() - getMilliOffset();
523: }
524:
525: /**
526: * Convert a string (like "12:42:15 1/2/97") to milliseconds from 1970
527: * The timezone used is 'GMT'
528: * @param date String which contains the date and time in the format "hour:minutes:sec day/month/year"
529: * @return the elapsed milliseconds since 1970 from this date
530: */
531: public static long convertDateToLong(String date) {
532: // Next line was the old code:
533: // return (convertStringToLong(date));
534: log.debug("Converting " + date);
535: Calendar cal = Calendar.getInstance();
536: TimeZone tz = TimeZone.getDefault();
537:
538: cal.setTimeZone(tz);
539: cal = parseDate(cal, date);
540:
541: Date d = cal.getTime();
542: long l = d.getTime();
543:
544: return l;
545: }
546:
547: /*
548: * ----- private functions used by convertDateToLong --------
549: */
550:
551: /**
552: * Parse a string containing a date and put it in a calendar
553: * @param cal Calander object that is used for storing the parsed date
554: * @param date String in the form: hour:minute:second day/month/year
555: * @return Calander object representing the parsed date
556: * @see DateSupport parseDateRev
557: */
558: public static Calendar parseDate(Calendar cal, String date) {
559: StringTokenizer tok = new StringTokenizer(date, "-\n\r:/ ");
560: String token = null;
561:
562: cal.clear(Calendar.HOUR_OF_DAY);
563:
564: token = tok.nextToken();
565: cal
566: .set(Calendar.HOUR_OF_DAY, Integer.valueOf(token)
567: .intValue());
568: token = tok.nextToken();
569: cal.set(Calendar.MINUTE, Integer.valueOf(token).intValue());
570: token = tok.nextToken();
571: cal.set(Calendar.SECOND, Integer.valueOf(token).intValue());
572: token = tok.nextToken();
573: cal.set(Calendar.DAY_OF_MONTH, Integer.valueOf(token)
574: .intValue());
575: token = tok.nextToken();
576: cal.set(Calendar.MONTH, Integer.valueOf(token).intValue() - 1);
577: token = tok.nextToken();
578: cal.set(Calendar.YEAR, Integer.valueOf(token).intValue());
579: return (cal);
580: }
581:
582: /**
583: * Parse a string containing a date and put it in a calendar, the string is in reversed order
584: * @param cal Calander object that is used for storing the parsed date
585: * @param date String in the form: year/month/day hour:minute:second
586: * @return Calander object representing the parsed date
587: * @see DateSupport parseDate
588: */
589: public static Calendar parseDateRev(Calendar cal, String date) {
590: StringTokenizer tok = new StringTokenizer(date, "-\n\r:/ ");
591: String token = null;
592:
593: cal.clear(Calendar.HOUR_OF_DAY);
594:
595: token = tok.nextToken();
596: cal.set(Calendar.YEAR, Integer.valueOf(token).intValue());
597: token = tok.nextToken();
598: cal.set(Calendar.MONTH, Integer.valueOf(token).intValue() - 1);
599: token = tok.nextToken();
600: cal.set(Calendar.DAY_OF_MONTH, Integer.valueOf(token)
601: .intValue());
602: token = tok.nextToken();
603: cal
604: .set(Calendar.HOUR_OF_DAY, Integer.valueOf(token)
605: .intValue());
606: token = tok.nextToken();
607: cal.set(Calendar.MINUTE, Integer.valueOf(token).intValue());
608: token = tok.nextToken();
609: cal.set(Calendar.SECOND, Integer.valueOf(token).intValue());
610: return (cal);
611: }
612:
613: /**
614: * Return a string for a given date
615: * @param time Integer representing the time in seconds since 1-Jan-1970 00:00:00
616: * @return String in the form 'hhmmss day/month/year'
617: * @see DateSupport#date2day
618: * @see DateSupport#date2date
619: */
620: public static String date2string(int time) {
621: return getTimeSec(time) + " " + getMonthDay(time) + "/"
622: + getMonth(time) + "/" + getYear(time);
623: }
624:
625: /**
626: * Return a string for a given date
627: * @param time Integer representing the time in seconds since 1-Jan-1970 00:00:00
628: * @return String in the form 'year-month-day'
629: * @see DateSupport#date2string
630: * @see DateSupport#date2date
631: */
632: public static String date2day(int time) {
633: return getYear(time) + "-" + getMonth(time) + "-"
634: + getMonthDay(time);
635: }
636:
637: /**
638: * Return a string for a given date
639: * @param time Integer representing the time in seconds since 1-Jan-1970 00:00:00
640: * @return String in the form 'year-month-day hhmmss'
641: * @see DateSupport#date2string
642: * @see DateSupport#date2day
643: */
644: public static String date2date(int time) {
645: return getYear(time) + "-" + getMonth(time) + "-"
646: + getMonthDay(time) + " " + getTimeSec(time);
647: }
648:
649: /**
650: * Dump a date as string
651: * @param time Integer representing the time in seconds since 1-Jan-1970 00:00:00
652: * @return String with a date
653: */
654: private static String dumpdate(int d) {
655: Date dd = new Date((long) d * 1000);
656: return dd.toString();
657: }
658:
659: /**
660: * Main method used for testing purposes
661: * @param args Array of arguments
662: */
663: public static void main(String args[]) {
664: log
665: .info("Date (without corr)"
666: + date2string((int) (System.currentTimeMillis() / 1000))
667: + " " + System.currentTimeMillis() / 1000);
668: log
669: .info("Date (with corr)"
670: + date2string((int) (DateSupport
671: .currentTimeMillis() / 1000)) + " : "
672: + DateSupport.currentTimeMillis() / 1000);
673: log.info("Date " + args[0] + " "
674: + date2string(Integer.parseInt(args[0])));
675: log.info("Date " + args[0] + " "
676: + dumpdate(Integer.parseInt(args[0])));
677: String ID = System.getProperty("user.timezone", "GMT");
678: log.info("ID " + ID + " : " + getMilliOffset());
679: log.info("ParseDate " + parsedate(args[1]));
680: }
681: }
|