mirror of https://github.com/apache/jclouds.git
Java SimpleDateFormat cannot handle valid ISO8601 time zone strings, fixed
This commit is contained in:
parent
241a33b5c8
commit
3623918de5
|
@ -27,14 +27,15 @@ import java.util.regex.Pattern;
|
||||||
*/
|
*/
|
||||||
public class DateUtils {
|
public class DateUtils {
|
||||||
|
|
||||||
public static final Pattern MILLIS_PATTERN = Pattern.compile("(.*\\.[0-9][0-9][0-9])[0-9]*Z?");
|
public static final Pattern MILLIS_PATTERN = Pattern.compile("(.*\\.[0-9][0-9][0-9])[0-9]*");
|
||||||
|
|
||||||
public static final Pattern TZ_PATTERN = Pattern.compile("(.*)[+-][0-9][0-9]:?[0-9][0-9]Z?");
|
// This regexp will match all TZ forms that are valid is ISO 8601
|
||||||
|
public static final Pattern TZ_PATTERN = Pattern.compile("(.*)([+-][0-9][0-9](:?[0-9][0-9])?|Z)");
|
||||||
|
|
||||||
public static String trimToMillis(String toParse) {
|
public static String trimToMillis(String toParse) {
|
||||||
Matcher matcher = MILLIS_PATTERN.matcher(toParse);
|
Matcher matcher = MILLIS_PATTERN.matcher(toParse);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
toParse = matcher.group(1) + 'Z';
|
toParse = matcher.group(1);
|
||||||
}
|
}
|
||||||
return toParse;
|
return toParse;
|
||||||
}
|
}
|
||||||
|
@ -44,11 +45,25 @@ public class DateUtils {
|
||||||
public static String trimTZ(String toParse) {
|
public static String trimTZ(String toParse) {
|
||||||
Matcher matcher = TZ_PATTERN.matcher(toParse);
|
Matcher matcher = TZ_PATTERN.matcher(toParse);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
toParse = matcher.group(1) + 'Z';
|
toParse = matcher.group(1);
|
||||||
}
|
}
|
||||||
|
// TODO explain why this check is here
|
||||||
if (toParse.length() == 25 && SECOND_PATTERN.matcher(toParse).matches())
|
if (toParse.length() == 25 && SECOND_PATTERN.matcher(toParse).matches())
|
||||||
toParse = toParse.substring(0, toParse.length() - 6) + 'Z';
|
toParse = toParse.substring(0, toParse.length() - 6);
|
||||||
return toParse;
|
return toParse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String findTZ(String toParse) {
|
||||||
|
Matcher matcher = TZ_PATTERN.matcher(toParse);
|
||||||
|
if (matcher.find()) {
|
||||||
|
// Remove ':' from the TZ string, as SimpleDateFormat can't handle it
|
||||||
|
String tz = matcher.group(2).replace(":", "");
|
||||||
|
// Append '00; if we only have a two digit TZ, as SimpleDateFormat
|
||||||
|
if (tz.length() == 2) tz += "00";
|
||||||
|
return tz;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -17,8 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
package org.jclouds.date.internal;
|
package org.jclouds.date.internal;
|
||||||
import static org.jclouds.date.internal.DateUtils.trimToMillis;
|
import static org.jclouds.date.internal.DateUtils.*;
|
||||||
import static org.jclouds.date.internal.DateUtils.trimTZ;
|
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
@ -42,20 +41,16 @@ public class SimpleDateFormatDateService implements DateService {
|
||||||
* guard against the lack of thread safety.
|
* guard against the lack of thread safety.
|
||||||
*/
|
*/
|
||||||
// @GuardedBy("this")
|
// @GuardedBy("this")
|
||||||
private static final SimpleDateFormat iso8601SecondsSimpleDateFormat = new SimpleDateFormat(
|
private static final SimpleDateFormat iso8601SecondsSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
|
||||||
"yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
|
||||||
|
|
||||||
// @GuardedBy("this")
|
// @GuardedBy("this")
|
||||||
private static final SimpleDateFormat iso8601SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
|
private static final SimpleDateFormat iso8601SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
|
||||||
Locale.US);
|
|
||||||
|
|
||||||
// @GuardedBy("this")
|
// @GuardedBy("this")
|
||||||
private static final SimpleDateFormat rfc822SimpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z",
|
private static final SimpleDateFormat rfc822SimpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
|
||||||
Locale.US);
|
|
||||||
|
|
||||||
// @GuardedBy("this")
|
// @GuardedBy("this")
|
||||||
private static final SimpleDateFormat cSimpleDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss '+0000' yyyy",
|
private static final SimpleDateFormat cSimpleDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss '+0000' yyyy", Locale.US);
|
||||||
Locale.US);
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
iso8601SimpleDateFormat.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
iso8601SimpleDateFormat.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||||
|
@ -64,83 +59,99 @@ public class SimpleDateFormatDateService implements DateService {
|
||||||
cSimpleDateFormat.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
cSimpleDateFormat.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final Date fromSeconds(long seconds) {
|
public final Date fromSeconds(long seconds) {
|
||||||
return new Date(seconds * 1000);
|
return new Date(seconds * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final String cDateFormat(Date date) {
|
public final String cDateFormat(Date date) {
|
||||||
synchronized (cSimpleDateFormat) {
|
synchronized (cSimpleDateFormat) {
|
||||||
return cSimpleDateFormat.format(date);
|
return cSimpleDateFormat.format(date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final String cDateFormat() {
|
public final String cDateFormat() {
|
||||||
return cDateFormat(new Date());
|
return cDateFormat(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final Date cDateParse(String toParse) {
|
public final Date cDateParse(String toParse) {
|
||||||
synchronized (cSimpleDateFormat) {
|
synchronized (cSimpleDateFormat) {
|
||||||
try {
|
try {
|
||||||
return cSimpleDateFormat.parse(toParse);
|
return cSimpleDateFormat.parse(toParse);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException pe) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException("Error parsing data at " + pe.getErrorOffset(), pe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final String rfc822DateFormat(Date date) {
|
public final String rfc822DateFormat(Date date) {
|
||||||
synchronized (rfc822SimpleDateFormat) {
|
synchronized (rfc822SimpleDateFormat) {
|
||||||
return rfc822SimpleDateFormat.format(date);
|
return rfc822SimpleDateFormat.format(date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final String rfc822DateFormat() {
|
public final String rfc822DateFormat() {
|
||||||
return rfc822DateFormat(new Date());
|
return rfc822DateFormat(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final Date rfc822DateParse(String toParse) {
|
public final Date rfc822DateParse(String toParse) {
|
||||||
synchronized (rfc822SimpleDateFormat) {
|
synchronized (rfc822SimpleDateFormat) {
|
||||||
try {
|
try {
|
||||||
return rfc822SimpleDateFormat.parse(toParse);
|
return rfc822SimpleDateFormat.parse(toParse);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException pe) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException("Error parsing data at " + pe.getErrorOffset(), pe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final String iso8601SecondsDateFormat() {
|
public final String iso8601SecondsDateFormat() {
|
||||||
return iso8601SecondsDateFormat(new Date());
|
return iso8601SecondsDateFormat(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final String iso8601DateFormat(Date date) {
|
public final String iso8601DateFormat(Date date) {
|
||||||
synchronized (iso8601SimpleDateFormat) {
|
synchronized (iso8601SimpleDateFormat) {
|
||||||
return iso8601SimpleDateFormat.format(date);
|
return iso8601SimpleDateFormat.format(date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final String iso8601DateFormat() {
|
public final String iso8601DateFormat() {
|
||||||
return iso8601DateFormat(new Date());
|
return iso8601DateFormat(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final Date iso8601DateParse(String toParse) {
|
public final Date iso8601DateParse(String toParse) {
|
||||||
|
String tz = findTZ(toParse);
|
||||||
toParse = trimTZ(toParse);
|
toParse = trimTZ(toParse);
|
||||||
toParse = trimToMillis(toParse);
|
toParse = trimToMillis(toParse);
|
||||||
|
toParse += tz; // Usable TZ added back
|
||||||
synchronized (iso8601SimpleDateFormat) {
|
synchronized (iso8601SimpleDateFormat) {
|
||||||
try {
|
try {
|
||||||
return iso8601SimpleDateFormat.parse(toParse);
|
return iso8601SimpleDateFormat.parse(toParse);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException pe) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException("Error parsing data at " + pe.getErrorOffset(), pe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final Date iso8601SecondsDateParse(String toParse) {
|
public final Date iso8601SecondsDateParse(String toParse) {
|
||||||
|
String tz = findTZ(toParse);
|
||||||
toParse = trimTZ(toParse);
|
toParse = trimTZ(toParse);
|
||||||
|
toParse += tz; // Usable TZ added back
|
||||||
synchronized (iso8601SecondsSimpleDateFormat) {
|
synchronized (iso8601SecondsSimpleDateFormat) {
|
||||||
try {
|
try {
|
||||||
return iso8601SecondsSimpleDateFormat.parse(toParse);
|
return iso8601SecondsSimpleDateFormat.parse(toParse);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException pe) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException("Error parsing data at " + pe.getErrorOffset(), pe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue