org.jivesoftware.util.XMPPDateTimeFormat Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2013 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//import net.jcip.annotations.ThreadSafe;
/**
* Utility class for date/time format conversions as specified in
* XEP-0082 and
* XEP-0090 and
* For Date -> String converstion FastDateFormat is used
*
*/
//@ThreadSafe
public class XMPPDateTimeFormat {
/**
* Date/time format for use by SimpleDateFormat. The format conforms to
* XEP-0082, which defines
* a unified date/time format for XMPP.
*/
public static final String XMPP_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
public static final String XMPP_DATETIME_FORMAT_WO_TIMEZONE = "yyyy-MM-dd'T'HH:mm:ss.SSS";
public static final String XMPP_DATETIME_FORMAT_WO_MILLIS_WO_TIMEZONE = "yyyy-MM-dd'T'HH:mm:ss";
public static final String XMPP_DATE_FORMAT = "yyyy-MM-dd";
public static final String XMPP_TIME_FORMAT = "HH:mm:ss.SSS";
public static final String XMPP_TIME_FORMAT_WO_MILLIS = "HH:mm:ss";
/**
* Date/time format for use by SimpleDateFormat. The format conforms to the format
* defined in XEP-0091,
* a specialized date format for historical XMPP usage.
*/
public static final String XMPP_DELAY_DATETIME_FORMAT = "yyyyMMdd'T'HH:mm:ss";
// matches CCYY-MM-DDThh:mm:ss.SSS(Z|(+|-)hh:mm))
private static final Pattern xep80DateTimePattern = Pattern.compile("^\\d+(-\\d+){2}+T(\\d+:){2}\\d+.\\d+(Z|([+-](\\d+:\\d+)))?$");
// matches CCYY-MM-DDThh:mm:ss(Z|(+|-)hh:mm))
private static final Pattern xep80DateTimeWoMillisPattern = Pattern.compile("^\\d+(-\\d+){2}+T(\\d+:){2}\\d+(Z|([+-](\\d+:\\d+)))?$");
// matches CCYYMMDDThh:mm:ss
@SuppressWarnings("unused")
private static final Pattern xep91Pattern = Pattern.compile("^\\d+T\\d+:\\d+:\\d+$");
private static final FastDateFormat FAST_FORMAT = FastDateFormat.getInstance(
XMPP_DATETIME_FORMAT, TimeZone.getTimeZone("UTC"));
private final DateFormat dateTimeFormat = new SimpleDateFormat(XMPP_DATETIME_FORMAT_WO_TIMEZONE + 'Z');
private final DateFormat dateTimeFormatWoMillies = new SimpleDateFormat(XMPP_DATETIME_FORMAT_WO_MILLIS_WO_TIMEZONE + 'Z');
/**
* Create a new thread-safe instance of this utility class
*/
public XMPPDateTimeFormat() {
TimeZone utc = TimeZone.getTimeZone("UTC");
dateTimeFormat.setTimeZone(utc);
dateTimeFormatWoMillies.setTimeZone(utc);
}
/**
* Tries to convert a given string to a Date object.
* This method supports the format types defined by XEP-0082 and the format defined in legacy protocols
* XEP-0082: CCYY-MM-DDThh:mm:ss[.sss]TZD
* legacy: CCYYMMDDThh:mm:ss
*
* This method either returns a Date instance as result or it will return null or throw a ParseException
* in case the String couldn't be parsed.
*
* @param dateString the String that should be parsed
* @return the parsed date or null if the String could not be parsed
* @throws ParseException
*/
public Date parseString(String dateString) throws ParseException {
Matcher xep82WoMillisMatcher = xep80DateTimeWoMillisPattern.matcher(dateString);
Matcher xep82Matcher = xep80DateTimePattern.matcher(dateString);
if (xep82WoMillisMatcher.matches() || xep82Matcher.matches()) {
String rfc822Date;
// Convert the ISO 8601 time zone string to a RFC822 compatible format
// since SimpleDateFormat supports ISO8601 only with Java7 or higher
if (dateString.charAt(dateString.length() - 1) == 'Z') {
rfc822Date = dateString.replace("Z", "+0000");
} else {
// If the time zone wasn't specified with 'Z', then it's in
// ISO8601 format (i.e. '(+|-)HH:mm')
// RFC822 needs a similar format just without the colon (i.e.
// '(+|-)HHmm)'), so remove it
int lastColon = dateString.lastIndexOf(':');
rfc822Date = dateString.substring(0, lastColon) + dateString.substring(lastColon + 1);
}
if (xep82WoMillisMatcher.matches()) {
synchronized (dateTimeFormatWoMillies) {
return dateTimeFormatWoMillies.parse(rfc822Date);
}
} else {
// OF-898: Replace any number of millisecond-characters with at most three of them.
rfc822Date = rfc822Date.replaceAll("(\\.[0-9]{3})[0-9]*", "$1");
synchronized (dateTimeFormat) {
return dateTimeFormat.parse(rfc822Date);
}
}
}
throw new ParseException("Date String could not be parsed", 0);
}
/**
* Formats a Date object to String as defined in XEP-0082.
*
* The resulting String will have the timezone set to UTC ('Z') and includes milliseconds:
* CCYY-MM-DDThh:mm:ss.sssZ
*
* @param date
* @return String
*/
public static String format(Date date) {
return FAST_FORMAT.format(date);
}
}