/**
*
*/
package com.trendrr.oss;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.TimeZone;
/*
* ISO 8601 date time formatting.
* http://www.w3.org/TR/NOTE-datetime
* http://en.wikipedia.org/wiki/ISO_8601
* http://www.probabilityof.com/ISO8601.shtml
* <pre>
* YYYY-MM-DDThh:mm:ss.fTZD (eg 1997-07-16T19:20:30.45+01:00)
* f can be one f to ffffffff (fraction of seconds)
* 1994-11-05T13:15:30Z (Z stands for UTC==GMT)
* </pre>
* If no time zone information is given with a time, the time zone is assumed to be in some conventional local timezone.
* <br />
* Note that the "T" appears literally in the string, to indicate the beginning of the time element, as specified in ISO 8601.
* <br />
* The standard allows the replacement of T with a space if no misunderstanding arises.
* @return The ISO 8601 UTC-time string, precision is currently millis (three fraction digits)
* "2006-02-21 14:05:51.703+0000"
*/
/**
* Date parser for ISO 8601 format
* http://www.w3.org/TR/1998/NOTE-datetime-19980827
* @version $Revision: 1.5 $
* @author Beno�t Mah� (bmahe@w3.org)
* @author Yves Lafon (ylafon@w3.org)
*/
/**
*
*
* @author Dustin Norlander
* @created Nov 30, 2010
*
*/
public class IsoDateUtil {
public static void main(String args[]) {
// test("1997-07-16T19:20:30.45-02:00");
// test("1997-07-16T19:20:30.678Z");
// test("2006-07-16T21:20:30.450+00:00");
// //test("2006-07-16T21:20:30.450+0000"); invalid
//
// test("1997-07-16 19:20:30.45-02:00");
// test("1997-07-16 19:20:30.678Z");
// test("2006-07-16 21:20:30.450+00:00");
//
// test("1997-07-16T19:20:30+01:00");
// test("1997-07-16T19:20:30+01:00");
// test("1997-07-16T12:20:30-06:00");
// test("1997-07-16T12:20:30-0600");
//
//
// test("1997-07-16T19:20");
// test("1997-07-16");
// test("1997-07");
// test("1997");
// test(new Date());
// test("2011-05-06T00:00:00-0400");
// test("2011-05-16T23:10:44.420000+00:00");
// test("2011-05-18T18:43:30.834000 00:00");
// System.out.println(getCurrentUTCTimestamp());
System.out.println(IsoDateUtil.parse("2013-05-19T06:00:00-0400 "));
}
public final static SimpleDateFormat utcFmt;
// public final static SimpleDateFormat utcFmtT;
static {
// Creates 2006-07-16 21:20:30.450+0000: illegal , must be +00:00
//utcFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SZ", Locale.US);
utcFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
utcFmt.setTimeZone(TimeZone.getTimeZone("GMT"));
// utcFmtT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S", Locale.US);
// utcFmtT.setTimeZone(TimeZone.getTimeZone("GMT"));
//Calendar utcCal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
}
/**
* @return The ISO 8601 UTC-time string, precision is currently millis (three fraction digits)
* "2006-02-21 14:05:51.703Z"
*/
public static String getCurrentUTCTimestamp() {
return getUTCTimestamp(new Date());
}
public static String getUTCTimestamp(Date date) {
synchronized (utcFmt) {
return utcFmt.format(date)+"Z";
}
}
public static String getUTCTimestamp(long millis) {
return getUTCTimestamp(new Date(millis));
}
// /**
// * @return The ISO 8601 UTC-time string, precision is currently millis (three fraction digits)
// * "2006-02-21T14:05:51.703Z"
// */
// public static String getCurrentUTCTimestampT() {
// return getUTCTimestampT(new Date());
// }
// public static String getUTCTimestampT(Date date) {
// synchronized (utcFmtT) {
// return utcFmtT.format(date)+"Z";
// }
// }
private static boolean check(StringTokenizer st, String token)
throws IllegalArgumentException
{
try {
if (st.nextToken().equals(token)) {
return true;
} else {
throw new IllegalArgumentException("Missing ["+token+"]");
}
} catch (NoSuchElementException ex) {
return false;
}
}
private static Calendar getCalendar(String isodate)
throws IllegalArgumentException
{
isodate = isodate.trim();
// YYYY-MM-DDThh:mm:ss.sTZD
// Marcel: Added ' ' to T replacement (ISO allows blanks)
int index = isodate.indexOf(' ');
if (index > 0)
isodate = isodate.substring(0, index) + "T" + isodate.substring(index+1);
// fix for timezones in the form +0700
String timezoneFix = Regex.matchFirst(isodate, "[\\+\\-]{1}[0-9]{3,4}$", false);
if (timezoneFix != null) {
int insertColonHere = isodate.length()-2;
isodate = isodate.substring(0,insertColonHere) + ":" + isodate.substring(insertColonHere);
}
//fix for timezone with space (as url + is treated as space)
isodate = isodate.replaceFirst("[T\\s]([0-9\\:]+)$", "+$1");
StringTokenizer st = new StringTokenizer(isodate, "-T:.+Z", true);
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
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;
}
// Hour
if (check(st, "T") && (st.hasMoreTokens())) {
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(":")) { // secondes
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(".")) {
// bug fixed, thx to Martin Bottcher
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 IllegalArgumentException("No secondes specified");
}
} else {
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
}
// Timezone
if (! tok.equals("Z")) { // UTC
if (! (tok.equals("+") || tok.equals("-"))) {
throw new IllegalArgumentException("only Z, + or - allowed");
}
boolean plus = tok.equals("+");
if (! st.hasMoreTokens()) {
throw new IllegalArgumentException("Missing hour field");
}
int tzhour = Integer.parseInt(st.nextToken());
int tzmin = 0;
if (check(st, ":") && (st.hasMoreTokens())) {
tzmin = Integer.parseInt(st.nextToken());
} else {
throw new IllegalArgumentException("Missing minute field");
}
if (plus) {
calendar.add(Calendar.HOUR, -tzhour);
calendar.add(Calendar.MINUTE, -tzmin);
} else {
calendar.add(Calendar.HOUR, tzhour);
calendar.add(Calendar.MINUTE, tzmin);
}
}
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("["+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 IllegalArgumentException if the date is not valid
*/
public static Date parse(String isodate)
throws IllegalArgumentException
{
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(TimeZone.getTimeZone("UTC"));
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)));
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(TimeZone.getTimeZone("UTC"));
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)));
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 void test(String isodate) {
System.out.println("----------------------------------");
try {
Date date = parse(isodate);
System.out.println("GIVEN >> "+isodate);
System.out.println("LOCAL >> "+date.toString()+" ["+date.getTime()+"]");
System.out.println("UTC >> "+ getUTCTimestamp(date));
// System.out.println("UTCT >> "+ getUTCTimestampT(date));
System.out.println("ISO >> "+getIsoDate(date));
} catch (IllegalArgumentException 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("GIVEN >> "+date.toString()+" ["+date.getTime()+"]");
isodate = getIsoDate(date);
System.out.println("ISO >> "+isodate);
date = parse(isodate);
System.out.println("PARSED>> "+date.toString()+" ["+date.getTime()+"]");
} catch (IllegalArgumentException ex) {
System.err.println(isodate+" is invalid");
System.err.println(ex.getMessage());
}
System.out.println("----------------------------------");
}
}