// DateParser.java
// $Id: DateParser.java,v 1.5 2005/05/14 15:53:00 dbarashev Exp $
// (c) COPYRIGHT MIT, INRIA and Keio, 2000.
// Please first read the full copyright statement in file COPYRIGHT.html
package com.sap.runlet.abstractinterpreter.util;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.NoSuchElementException;
import java.util.SimpleTimeZone;
import java.util.StringTokenizer;
import java.util.TimeZone;
/**
* Date parser for ISO 8601 format
* http://www.w3.org/TR/1998/NOTE-datetime-19980827
*
* @version $Revision: 1.5 $
* @author Beno�� Mah(bmahe@w3.org)
*/
public class DateParser {
private static boolean check(StringTokenizer st, String token)
throws InvalidDateException {
try {
if (st.nextToken().equals(token)) {
return true;
} else {
throw new InvalidDateException("Missing [" + token + "]");
}
} catch (NoSuchElementException ex) {
return false;
}
}
private static Calendar getCalendar(String isodate)
throws InvalidDateException {
// YYYY-MM-DD[ T]hh:mm:ss.sTZD
StringTokenizer st = new StringTokenizer(isodate, "-T:.,+Z ", true);
Calendar calendar = new GregorianCalendar();
calendar.clear();
try {
// Year
if (st.hasMoreTokens()) {
int year = Integer.parseInt(st.nextToken());
calendar.set(Calendar.YEAR, year);
} else {
return calendar;
}
// Month
if (check(st, "-") && (st.hasMoreTokens())) {
int month = Integer.parseInt(st.nextToken()) - 1;
calendar.set(Calendar.MONTH, month);
} else {
return calendar;
}
// Day
if (check(st, "-") && (st.hasMoreTokens())) {
int day = Integer.parseInt(st.nextToken());
calendar.set(Calendar.DAY_OF_MONTH, day);
} else {
return calendar;
}
if (!st.hasMoreTokens()) {
return calendar;
}
String timeSeparator;
// Hour
if (st.hasMoreTokens() && ((timeSeparator=st.nextToken()).equals("T") || timeSeparator.equals(" "))) {
int hour = Integer.parseInt(st.nextToken());
calendar.set(Calendar.HOUR_OF_DAY, hour);
} else {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar;
}
// Minutes
if (check(st, ":") && (st.hasMoreTokens())) {
int minutes = Integer.parseInt(st.nextToken());
calendar.set(Calendar.MINUTE, minutes);
} else {
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar;
}
//
// Not mandatory now
//
// Secondes
if (!st.hasMoreTokens()) {
return calendar;
}
String tok = st.nextToken();
if (tok.equals(":")) { // seconds
if (st.hasMoreTokens()) {
int secondes = Integer.parseInt(st.nextToken());
calendar.set(Calendar.SECOND, secondes);
if (!st.hasMoreTokens()) {
return calendar;
}
// frac sec
tok = st.nextToken();
if (tok.equals(".") || tok.equals(",")) {
String nt = st.nextToken();
while (nt.length() < 3) {
nt += "0";
}
nt = nt.substring(0, 3); // Cut trailing chars..
int millisec = Integer.parseInt(nt);
// int millisec = Integer.parseInt(st.nextToken()) * 10;
calendar.set(Calendar.MILLISECOND, millisec);
if (!st.hasMoreTokens()) {
return calendar;
}
tok = st.nextToken();
} else {
calendar.set(Calendar.MILLISECOND, 0);
}
} else {
throw new InvalidDateException("No seconds specified");
}
} else {
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
}
// Timezone
if (tok.equals("Z")) { // UTC
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
} else { // offset from UTC
if (!(tok.equals("+") || tok.equals("-"))) {
throw new InvalidDateException("only Z, + or - allowed");
}
boolean plus = tok.equals("+");
if (!st.hasMoreTokens()) {
throw new InvalidDateException("Missing timezone hour field");
}
String tzToken = st.nextToken();
int tzhour;
int tzmin;
if (tzToken.length() > 2) {
tzhour = Integer.parseInt(tzToken.substring(0, 2));
tzmin = Integer.parseInt(tzToken.substring(2));
} else {
tzhour = Integer.parseInt(tzToken);
tzmin = 0;
if (check(st, ":") && (st.hasMoreTokens())) {
tzmin = Integer.parseInt(st.nextToken());
} else {
throw new InvalidDateException("Missing timezone minute field");
}
}
TimeZone tz;
if (plus) {
tz = new SimpleTimeZone(3600000*tzhour+60000*tzmin, "+"+(100*tzhour)+tzmin);
} else {
tz = new SimpleTimeZone(-3600000*tzhour-60000*tzmin, "-"+(100*tzhour)+tzmin);
}
calendar.setTimeZone(tz);
}
} catch (NumberFormatException ex) {
throw new InvalidDateException("[" + ex.getMessage()
+ "] is not an integer");
}
return calendar;
}
/**
* Parse the given string in ISO 8601 format and build a Date object.
*
* @param isodate
* the date in ISO 8601 format
* @return a Date instance
* @exception InvalidDateException
* if the date is not valid
*/
public static Date parse(String isodate) throws InvalidDateException {
Calendar calendar = getCalendar(isodate);
return calendar.getTime();
}
private static String twoDigit(int i) {
if (i >= 0 && i < 10) {
return "0" + String.valueOf(i);
}
return String.valueOf(i);
}
/**
* Generate a ISO 8601 date
*
* @param date
* a Date instance
* @return a string representing the date in the ISO 8601 format
*/
public static String getIsoDate(Date date) {
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
StringBuffer buffer = new StringBuffer(getIsoDateNoHours(date));
buffer.append("T");
buffer.append(twoDigit(calendar.get(Calendar.HOUR_OF_DAY)));
buffer.append(":");
buffer.append(twoDigit(calendar.get(Calendar.MINUTE)));
buffer.append(":");
buffer.append(twoDigit(calendar.get(Calendar.SECOND)));
buffer.append(".");
buffer.append(twoDigit(calendar.get(Calendar.MILLISECOND) / 10));
buffer.append("Z");
return buffer.toString();
}
/**
* Generate a ISO 8601 date
*
* @param date
* a Date instance
* @return a string representing the date in the ISO 8601 format
*/
public static String getIsoDateNoMillis(Date date) {
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
StringBuffer buffer = new StringBuffer(getIsoDateNoHours(date));
buffer.append("T");
buffer.append(twoDigit(calendar.get(Calendar.HOUR_OF_DAY)));
buffer.append(":");
buffer.append(twoDigit(calendar.get(Calendar.MINUTE)));
buffer.append(":");
buffer.append(twoDigit(calendar.get(Calendar.SECOND)));
buffer.append("Z");
return buffer.toString();
}
public static String getIsoDateNoHours(Date date) {
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
StringBuffer buffer = new StringBuffer();
buffer.append(calendar.get(Calendar.YEAR));
buffer.append("-");
buffer.append(twoDigit(calendar.get(Calendar.MONTH) + 1));
buffer.append("-");
buffer.append(twoDigit(calendar.get(Calendar.DAY_OF_MONTH)));
return buffer.toString();
}
public static void test(String isodate) {
System.out.println("----------------------------------");
try {
Date date = parse(isodate);
System.out.println(">> " + isodate);
System.out.println(">> " + date.toString() + " [" + date.getTime()
+ "]");
System.out.println(">> " + getIsoDate(date));
} catch (InvalidDateException ex) {
System.err.println(isodate + " is invalid");
System.err.println(ex.getMessage());
}
System.out.println("----------------------------------");
}
public static void test(Date date) {
String isodate = null;
System.out.println("----------------------------------");
try {
System.out.println(">> " + date.toString() + " [" + date.getTime()
+ "]");
isodate = getIsoDate(date);
System.out.println(">> " + isodate);
date = parse(isodate);
System.out.println(">> " + date.toString() + " [" + date.getTime()
+ "]");
} catch (InvalidDateException ex) {
System.err.println(isodate + " is invalid");
System.err.println(ex.getMessage());
}
System.out.println("----------------------------------");
}
public static void main(String args[]) {
test("1997-07-16T19:20:30.45-02:00");
test("1997-07-16T19:20:30+01:00");
test("1997-07-16T19:20:30+01:00");
test("1997-07-16T19:20");
test("1997-07-16");
test("1997-07");
test("1997");
test(new Date());
}
}