001: // DateParser.java
002: // $Id: DateParser.java,v 1.1.1.1 2004/06/16 13:15:12 flaviotordini Exp $
003: // (c) COPYRIGHT MIT, INRIA and Keio, 2000.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005: package org.w3c.util;
006:
007: import java.util.Calendar;
008: import java.util.Date;
009: import java.util.GregorianCalendar;
010: import java.util.NoSuchElementException;
011: import java.util.StringTokenizer;
012: import java.util.TimeZone;
013:
014: /**
015: * Date parser for ISO 8601 format
016: * http://www.w3.org/TR/1998/NOTE-datetime-19980827
017: * @version $Revision: 1.1.1.1 $
018: * @author Benoît Mahé (bmahe@w3.org)
019: */
020: public class DateParser {
021:
022: private static boolean check(StringTokenizer st, String token)
023: throws InvalidDateException {
024: try {
025: if (st.nextToken().equals(token)) {
026: return true;
027: } else {
028: throw new InvalidDateException("Missing [" + token
029: + "]");
030: }
031: } catch (NoSuchElementException ex) {
032: return false;
033: }
034: }
035:
036: private static Calendar getCalendar(String isodate)
037: throws InvalidDateException {
038: // YYYY-MM-DDThh:mm:ss.sTZD
039: StringTokenizer st = new StringTokenizer(isodate, "-T:.+Z",
040: true);
041:
042: Calendar calendar = new GregorianCalendar(TimeZone
043: .getTimeZone("UTC"));
044: calendar.clear();
045: try {
046: // Year
047: if (st.hasMoreTokens()) {
048: int year = Integer.parseInt(st.nextToken());
049: calendar.set(Calendar.YEAR, year);
050: } else {
051: return calendar;
052: }
053: // Month
054: if (check(st, "-") && (st.hasMoreTokens())) {
055: int month = Integer.parseInt(st.nextToken()) - 1;
056: calendar.set(Calendar.MONTH, month);
057: } else {
058: return calendar;
059: }
060: // Day
061: if (check(st, "-") && (st.hasMoreTokens())) {
062: int day = Integer.parseInt(st.nextToken());
063: calendar.set(Calendar.DAY_OF_MONTH, day);
064: } else {
065: return calendar;
066: }
067: // Hour
068: if (check(st, "T") && (st.hasMoreTokens())) {
069: int hour = Integer.parseInt(st.nextToken());
070: calendar.set(Calendar.HOUR_OF_DAY, hour);
071: } else {
072: calendar.set(Calendar.HOUR_OF_DAY, 0);
073: calendar.set(Calendar.MINUTE, 0);
074: calendar.set(Calendar.SECOND, 0);
075: calendar.set(Calendar.MILLISECOND, 0);
076: return calendar;
077: }
078: // Minutes
079: if (check(st, ":") && (st.hasMoreTokens())) {
080: int minutes = Integer.parseInt(st.nextToken());
081: calendar.set(Calendar.MINUTE, minutes);
082: } else {
083: calendar.set(Calendar.MINUTE, 0);
084: calendar.set(Calendar.SECOND, 0);
085: calendar.set(Calendar.MILLISECOND, 0);
086: return calendar;
087: }
088:
089: //
090: // Not mandatory now
091: //
092:
093: // Secondes
094: if (!st.hasMoreTokens()) {
095: return calendar;
096: }
097: String tok = st.nextToken();
098: if (tok.equals(":")) { // secondes
099: if (st.hasMoreTokens()) {
100: int secondes = Integer.parseInt(st.nextToken());
101: calendar.set(Calendar.SECOND, secondes);
102: if (!st.hasMoreTokens()) {
103: return calendar;
104: }
105: // frac sec
106: tok = st.nextToken();
107: if (tok.equals(".")) {
108: // bug fixed, thx to Martin Bottcher
109: String nt = st.nextToken();
110: while (nt.length() < 3) {
111: nt += "0";
112: }
113: nt = nt.substring(0, 3); //Cut trailing chars..
114: int millisec = Integer.parseInt(nt);
115: //int millisec = Integer.parseInt(st.nextToken()) * 10;
116: calendar.set(Calendar.MILLISECOND, millisec);
117: if (!st.hasMoreTokens()) {
118: return calendar;
119: }
120: tok = st.nextToken();
121: } else {
122: calendar.set(Calendar.MILLISECOND, 0);
123: }
124: } else {
125: throw new InvalidDateException(
126: "No secondes specified");
127: }
128: } else {
129: calendar.set(Calendar.SECOND, 0);
130: calendar.set(Calendar.MILLISECOND, 0);
131: }
132: // Timezone
133: if (!tok.equals("Z")) { // UTC
134: if (!(tok.equals("+") || tok.equals("-"))) {
135: throw new InvalidDateException(
136: "only Z, + or - allowed");
137: }
138: boolean plus = tok.equals("+");
139: if (!st.hasMoreTokens()) {
140: throw new InvalidDateException("Missing hour field");
141: }
142: int tzhour = Integer.parseInt(st.nextToken());
143: int tzmin = 0;
144: if (check(st, ":") && (st.hasMoreTokens())) {
145: tzmin = Integer.parseInt(st.nextToken());
146: } else {
147: throw new InvalidDateException(
148: "Missing minute field");
149: }
150: if (plus) {
151: calendar.add(Calendar.HOUR, tzhour);
152: calendar.add(Calendar.MINUTE, tzmin);
153: } else {
154: calendar.add(Calendar.HOUR, -tzhour);
155: calendar.add(Calendar.MINUTE, -tzmin);
156: }
157: }
158: } catch (NumberFormatException ex) {
159: throw new InvalidDateException("[" + ex.getMessage()
160: + "] is not an integer");
161: }
162: return calendar;
163: }
164:
165: /**
166: * Parse the given string in ISO 8601 format and build a Date object.
167: * @param isodate the date in ISO 8601 format
168: * @return a Date instance
169: * @exception InvalidDateException if the date is not valid
170: */
171: public static Date parse(String isodate)
172: throws InvalidDateException {
173: Calendar calendar = getCalendar(isodate);
174: return calendar.getTime();
175: }
176:
177: private static String twoDigit(int i) {
178: if (i >= 0 && i < 10) {
179: return "0" + String.valueOf(i);
180: }
181: return String.valueOf(i);
182: }
183:
184: /**
185: * Generate a ISO 8601 date
186: * @param date a Date instance
187: * @return a string representing the date in the ISO 8601 format
188: */
189: public static String getIsoDate(Date date) {
190: Calendar calendar = new GregorianCalendar(TimeZone
191: .getTimeZone("UTC"));
192: calendar.setTime(date);
193: StringBuffer buffer = new StringBuffer();
194: buffer.append(calendar.get(Calendar.YEAR));
195: buffer.append("-");
196: buffer.append(twoDigit(calendar.get(Calendar.MONTH) + 1));
197: buffer.append("-");
198: buffer.append(twoDigit(calendar.get(Calendar.DAY_OF_MONTH)));
199: buffer.append("T");
200: buffer.append(twoDigit(calendar.get(Calendar.HOUR_OF_DAY)));
201: buffer.append(":");
202: buffer.append(twoDigit(calendar.get(Calendar.MINUTE)));
203: buffer.append(":");
204: buffer.append(twoDigit(calendar.get(Calendar.SECOND)));
205: buffer.append(".");
206: buffer
207: .append(twoDigit(calendar.get(Calendar.MILLISECOND) / 10));
208: buffer.append("Z");
209: return buffer.toString();
210: }
211:
212: public static void test(String isodate) {
213: System.out.println("----------------------------------");
214: try {
215: Date date = parse(isodate);
216: System.out.println(">> " + isodate);
217: System.out.println(">> " + date.toString() + " ["
218: + date.getTime() + "]");
219: System.out.println(">> " + getIsoDate(date));
220: } catch (InvalidDateException ex) {
221: System.err.println(isodate + " is invalid");
222: System.err.println(ex.getMessage());
223: }
224: System.out.println("----------------------------------");
225: }
226:
227: public static void test(Date date) {
228: String isodate = null;
229: System.out.println("----------------------------------");
230: try {
231: System.out.println(">> " + date.toString() + " ["
232: + date.getTime() + "]");
233: isodate = getIsoDate(date);
234: System.out.println(">> " + isodate);
235: date = parse(isodate);
236: System.out.println(">> " + date.toString() + " ["
237: + date.getTime() + "]");
238: } catch (InvalidDateException ex) {
239: System.err.println(isodate + " is invalid");
240: System.err.println(ex.getMessage());
241: }
242: System.out.println("----------------------------------");
243: }
244:
245: public static void main(String args[]) {
246: test("1997-07-16T19:20:30.45-02:00");
247: test("1997-07-16T19:20:30+01:00");
248: test("1997-07-16T19:20:30+01:00");
249: test("1997-07-16T19:20");
250: test("1997-07-16");
251: test("1997-07");
252: test("1997");
253: test(new Date());
254: }
255:
256: }
|