package net.i2p.router.news;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import net.i2p.util.SystemVersion;
/**
* Adapted from net.i2p.router.util.RFC822Date.
* This only supports parsing of the dates specified by Atom (RFC 4287)
* and a couple of others.
* In particular, 'T' is required, and either 'Z' or a numeric timezone offset is required,
* unless there's no time fields at all.
*
* The full variety of RFC 3339 (ISO 8601) dates is not supported by the parser,
* but they could be added in the future.
*
* See also: http://stackoverflow.com/questions/6038136/how-do-i-parse-rfc-3339-datetimes-with-java
*
* @since 0.9.17
*/
public abstract class RFC3339Date {
// SimpleDateFormat is not thread-safe, methods must be synchronized
private static final SimpleDateFormat OUTPUT_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
private static final String TZF1, TZF2;
static {
// Android's SimpleDateFormat doesn't support XXX at any API
if (SystemVersion.isJava7() && !SystemVersion.isAndroid()) {
// ISO 8601
// These handle timezones like +1000, +10, and +10:00
TZF1 = "yyyy-MM-dd'T'HH:mm:ssXXX";
TZF2 = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
} else {
// These handle timezones like +1000
// These do NOT handle timezones like +10:00
// This is fixed below
TZF1 = "yyyy-MM-dd'T'HH:mm:ssZZZZZ";
TZF2 = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ";
}
}
/**
* This only supports parsing of the dates specified by Atom, RFC 4287,
* together with the date only.
*/
private static final SimpleDateFormat rfc3339DateFormats[] = new SimpleDateFormat[] {
OUTPUT_FORMAT,
// .S or .SS will get the milliseconds wrong,
// e.g. .1 will become 1 ms, .11 will become 11 ms
// This is NOT fixed below
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US),
new SimpleDateFormat(TZF1, Locale.US),
new SimpleDateFormat(TZF2, Locale.US),
new SimpleDateFormat("yyyy-MM-dd", Locale.US),
// old school for backward compatibility
new SimpleDateFormat("yyyy/MM/dd", Locale.US)
};
//
// The router JVM is forced to UTC but do this just in case
//
static {
TimeZone utc = TimeZone.getTimeZone("GMT");
for (int i = 0; i < rfc3339DateFormats.length; i++) {
rfc3339DateFormats[i].setTimeZone(utc);
}
}
/**
* Parse the date
*
* @param s non-null
* @return -1 on failure
*/
public synchronized static long parse3339Date(String s) {
s = s.trim();
// strip the ':' out of the time zone, if present,
// for Java 6 where we don't have the 'X' format
int len = s.length();
if ((!SystemVersion.isJava7() || SystemVersion.isAndroid()) &&
s.charAt(len - 1) != 'Z' &&
s.charAt(len - 3) == ':' &&
(s.charAt(len - 6) == '+' || s.charAt(len - 6) == '-')) {
s = s.substring(0, len - 3) + s.substring(len - 2);
}
for (int i = 0; i < rfc3339DateFormats.length; i++) {
try {
Date date = rfc3339DateFormats[i].parse(s);
if (date != null)
return date.getTime();
} catch (ParseException pe) {}
}
return -1;
}
/**
* Format is "yyyy-MM-ddTHH:mm:ssZ"
*/
public synchronized static String to3339Date(long t) {
return OUTPUT_FORMAT.format(new Date(t));
}
/****
public static void main(String[] args) {
if (args.length == 1) {
try {
System.out.println(to3339Date(Long.parseLong(args[0])));
} catch (NumberFormatException nfe) {
System.out.println(parse3339Date(args[0]));
}
} else {
System.out.println("Usage: RFC3339Date numericDate|stringDate");
}
}
****/
}