/*
* ====================================================================
* ======== The Apache Software License, Version 1.1
* ==================
* ==========================================================
* Copyright (C) 2002 The Apache Software Foundation. All rights
* reserved. Redistribution and use in source and binary forms, with
* or without modifica- tion, are permitted provided that the
* following conditions are met: 1. Redistributions of source code
* must retain the above copyright notice, this list of conditions and
* the following disclaimer. 2. Redistributions in binary form must
* reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. The end-user
* documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes
* software developed by SuperBonBon Industries
* (http://www.sbbi.net/)." Alternately, this acknowledgment may
* appear in the software itself, if and wherever such third-party
* acknowledgments normally appear. 4. The names "UPNPLib" and
* "SuperBonBon Industries" must not be used to endorse or promote
* products derived from this software without prior written
* permission. For written permission, please contact info@sbbi.net.
* 5. Products derived from this software may not be called
* "SuperBonBon Industries", nor may "SBBI" appear in their name,
* without prior written permission of SuperBonBon Industries. THIS
* SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. This software consists of voluntary contributions made
* by many individuals on behalf of SuperBonBon Industries. For more
* information on SuperBonBon Industries, please see
* <http://www.sbbi.net/>.
*/
package net.tomp2p.upnp;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.TimeZone;
/**
* ISO8601 Date implementation taken from org.w3c package and modified to work
* with UPNP date types
*
* @author <a href="mailto:superbonbon@sbbi.net">SuperBonBon</a>
* @version 1.0
*/
public class ISO8601Date {
private static boolean check(StringTokenizer st, String token) throws NumberFormatException {
try {
if (st.nextToken().equals(token)) {
return true;
} else {
throw new NumberFormatException("Missing [" + token + "]");
}
} catch (NoSuchElementException ex) {
return false;
}
}
private static Calendar getCalendar(String isodate) throws NumberFormatException {
// YYYY-MM-DDThh:mm:ss.sTZD or hh:mm:ss.sTZD
// does it contains a date ?
boolean isATime = isodate.indexOf(':') != -1;
boolean isADate = isodate.indexOf('-') != -1 || isodate.length() == 4 && !isATime;
if (isATime && !isADate) {
if (!isodate.toUpperCase().startsWith("T")) {
isodate = "T" + isodate;
}
}
StringTokenizer st = new StringTokenizer(isodate, "-T:.+Z", true);
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.clear();
if (isADate) {
// 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 NumberFormatException("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 NumberFormatException("only Z, + or - allowed");
}
boolean plus = tok.equals("+");
if (!st.hasMoreTokens()) {
throw new NumberFormatException("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 NumberFormatException("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);
}
}
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 NumberFormatException
* if the date is not valid
*/
public static Date parse(String isodate) throws NumberFormatException {
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);
StringBuilder buffer = new StringBuilder();
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();
}
/**
* Generate a ISO 8601 date time without timezone
*
* @param date
* a Date instance
* @return a string representing the date in the ISO 8601 format
*/
public static String getIsoDateTime(Date date) {
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
StringBuilder buffer = new StringBuilder();
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));
return buffer.toString();
}
/**
* Generate a ISO 8601 date time with timezone
*
* @param date
* a Date instance
* @return a string representing the date in the ISO 8601 format
*/
public static String getIsoDateTimeZone(Date date) {
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.setTime(date);
StringBuilder buffer = new StringBuilder();
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 time
*
* @param date
* a Date instance
* @return a string representing the date in the ISO 8601 format
*/
public static String getIsoTime(Date date) {
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
StringBuilder buffer = new StringBuilder();
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));
return buffer.toString();
}
/**
* Generate a ISO 8601 time
*
* @param date
* a Date instance
* @return a string representing the date in the ISO 8601 format
*/
public static String getIsoTimeZone(Date date) {
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.setTime(date);
StringBuilder buffer = new StringBuilder();
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();
}
}