Author: ngn
Date: Sun Sep 13 21:25:29 2009
New Revision: 814386
URL: http://svn.apache.org/viewvc?rev=814386&view=rev
Log:
Rewrote date time parsing into using Calendar as it makes it much easier to
reason about time zones. Also switched from using SimpleDateFormat for parsing,
to a regexp based implementation.
Modified:
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/datetime/DateTimeProfile.java
mina/sandbox/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/datetime/DateTimeProfileTestCase.java
Modified:
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/datetime/DateTimeProfile.java
URL:
http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/datetime/DateTimeProfile.java?rev=814386&r1=814385&r2=814386&view=diff
==============================================================================
---
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/datetime/DateTimeProfile.java
(original)
+++
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/datetime/DateTimeProfile.java
Sun Sep 13 21:25:29 2009
@@ -1,20 +1,19 @@
package org.apache.vysper.xmpp.datetime;
-import org.apache.vysper.compliance.SpecCompliant;
import static
org.apache.vysper.compliance.SpecCompliant.ComplianceCoverage.COMPLETE;
import static
org.apache.vysper.compliance.SpecCompliant.ComplianceStatus.IN_PROGRESS;
+import java.text.SimpleDateFormat;
import java.util.Calendar;
-import java.util.TimeZone;
import java.util.Date;
+import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
+
+import org.apache.vysper.compliance.SpecCompliant;
/**
- * provides dates and times in XMPP conform formats
+ * provides dates and times in XMPP conformant formats
*/
@SpecCompliant(spec = "XEP-0082", status = IN_PROGRESS, coverage = COMPLETE)
public class DateTimeProfile {
@@ -25,10 +24,17 @@
protected static final SimpleDateFormat utcDateTimeFormatter;
protected static final SimpleDateFormat utcTimeFormatter;
- protected static final SimpleDateFormat utcDateParser;
- protected static final SimpleDateFormat utcDateTimeParser;
- protected static final SimpleDateFormat utcTimeParser;
-
+ private static final String DATE_PATTERN_VALUE =
"(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)";
+ private static final String TIME_PATTERN_VALUE =
"(\\d\\d):(\\d\\d):(\\d\\d)";
+ private static final String TZ_PATTERN_VALUE =
"(([+-]\\d\\d:\\d\\d)|Z)";
+
+ // time zone is required for date times
+ private static final Pattern DATE_TIME_PATTERN = Pattern.compile("^" +
DATE_PATTERN_VALUE + "T"
+ + TIME_PATTERN_VALUE + TZ_PATTERN_VALUE + "$");
+ private static final Pattern DATE_PATTERN = Pattern.compile("^" +
DATE_PATTERN_VALUE + "$");
+
+ // time zone is optional for times
+ private static final Pattern TIME_PATTERN = Pattern.compile("^" +
TIME_PATTERN_VALUE + TZ_PATTERN_VALUE + "?$");
static {
TIME_ZONE_UTC = TimeZone.getTimeZone("UTC");
@@ -38,10 +44,6 @@
utcDateFormatter.setTimeZone(TIME_ZONE_UTC); // convert to UTC
utcTimeFormatter = new SimpleDateFormat("HH:mm:ss'Z'");
utcTimeFormatter.setTimeZone(TIME_ZONE_UTC); // convert to UTC
-
- utcDateTimeParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
- utcDateParser = new SimpleDateFormat("yyyy-MM-dd");
- utcTimeParser = new SimpleDateFormat("HH:mm:ss");
}
private final static DateTimeProfile SINGLETON = new DateTimeProfile();
@@ -66,58 +68,93 @@
return utcTimeFormatter.format(time);
}
- public Date fromDateTime(String time) throws ParseException {
- return parseWithTz(utcDateTimeParser, time, false);
- }
-
- public Date fromTime(String time) throws ParseException {
- return parseWithTz(utcTimeParser, time, true);
+ /**
+ * Parses a date time compliant with ISO-8601 and XEP-0082.
+ * @param time The date time string
+ * @return A {...@link Calendar} representing the date time, in the
+ * time zone specified by the input string
+ * @throws IllegalArgumentException If the input string is not a valid
date time
+ * e.g. the time zone is missing
+ */
+ public Calendar fromDateTime(String time) {
+ Matcher matcher = DATE_TIME_PATTERN.matcher(time);
+
+ if(matcher.find()) {
+ int year = Integer.valueOf(matcher.group(1));
+ int month = Integer.valueOf(matcher.group(2));
+ int day = Integer.valueOf(matcher.group(3));
+ int hour = Integer.valueOf(matcher.group(4));
+ int minute = Integer.valueOf(matcher.group(5));
+ int second = Integer.valueOf(matcher.group(6));
+ String tzValue = matcher.group(7);
+ TimeZone tz;
+ if(tzValue.equals("Z")) {
+ tz = TIME_ZONE_UTC;
+ } else {
+ tz = TimeZone.getTimeZone("GMT" + tzValue);
+ }
+ Calendar calendar = Calendar.getInstance(tz);
+ calendar.clear();
+ calendar.set(year, month - 1, day, hour, minute, second);
+ return calendar;
+ } else {
+ throw new IllegalArgumentException("Invalid date time: " + time);
+ }
}
- public Date fromDate(String time) throws ParseException {
- return utcDateParser.parse(time);
+ /**
+ * Parses a time, compliant with ISO-8601 and XEP-0082.
+ * @param time The time string
+ * @return A {...@link Calendar} representing the time, in the
+ * time zone specified by the input string. If a time zone is not
specified
+ * in the input string, the returned {...@link Calendar} will be in the
UTC time zone
+ * @throws IllegalArgumentException If the input string is not a valid time
+ */
+ public Calendar fromTime(String time) {
+ Matcher matcher = TIME_PATTERN.matcher(time);
+
+ if(matcher.find()) {
+ int hour = Integer.valueOf(matcher.group(1));
+ int minute = Integer.valueOf(matcher.group(2));
+ int second = Integer.valueOf(matcher.group(3));
+ String tzValue = matcher.group(4);
+ TimeZone tz;
+ if(tzValue == null || tzValue.equals("Z")) {
+ tz = TIME_ZONE_UTC;
+ } else {
+ tz = TimeZone.getTimeZone("GMT" + tzValue);
+ }
+ Calendar calendar = Calendar.getInstance(tz);
+ calendar.clear();
+ calendar.set(Calendar.HOUR_OF_DAY, hour);
+ calendar.set(Calendar.MINUTE, minute);
+ calendar.set(Calendar.SECOND, second);
+ return calendar;
+ } else {
+ throw new IllegalArgumentException("Invalid date time: " + time);
+ }
}
-
- private Date parseWithTz(DateFormat format, String time, boolean
optionalTz) throws ParseException {
- int tzOffset;
- String timeWithoutTz;
- // tz is required for datetimes and optional for times by XEP-0082
- if(time.endsWith("Z")) {
- timeWithoutTz = time.substring(0, time.length() - 1);
- tzOffset = 0;
+ /**
+ * Parses a date, compliant with ISO-8601 and XEP-0082.
+ * @param time The date string
+ * @return A {...@link Calendar} representing the date
+ * @throws IllegalArgumentException If the input string is not a valid date
+ */
+ public Calendar fromDate(String time) {
+ Matcher matcher = DATE_PATTERN.matcher(time);
+
+ if(matcher.find()) {
+ int year = Integer.valueOf(matcher.group(1));
+ int month = Integer.valueOf(matcher.group(2));
+ int day = Integer.valueOf(matcher.group(3));
+
+ Calendar calendar = Calendar.getInstance(TIME_ZONE_UTC);
+ calendar.clear();
+ calendar.set(year, month -1, day);
+ return calendar;
} else {
- Pattern tzPattern = Pattern.compile("([+-])(\\d\\d):(\\d\\d)$");
-
- Matcher matcher = tzPattern.matcher(time);
-
- if(matcher.find()) {
- timeWithoutTz = time.substring(0, time.length() - 6);
-
- String sign = matcher.group(1);
- int hours = Integer.parseInt(matcher.group(2));
- int min = Integer.parseInt(matcher.group(3));
-
- tzOffset = hours * 60 + min;
- if(sign.equals("-")) tzOffset = -tzOffset;
- } else {
- if(optionalTz) {
- timeWithoutTz = time;
- tzOffset = 0;
- } else {
- throw new IllegalArgumentException("Time zone required for
date time: " + time);
- }
- }
+ throw new IllegalArgumentException("Invalid date time: " + time);
}
-
- // parse without time zone
- Date actual = format.parse(timeWithoutTz);
-
- // correct for time zone
- Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- cal.setTime(actual);
- cal.add(Calendar.MINUTE, tzOffset);
- return cal.getTime();
-
}
}
Modified:
mina/sandbox/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/datetime/DateTimeProfileTestCase.java
URL:
http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/datetime/DateTimeProfileTestCase.java?rev=814386&r1=814385&r2=814386&view=diff
==============================================================================
---
mina/sandbox/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/datetime/DateTimeProfileTestCase.java
(original)
+++
mina/sandbox/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/datetime/DateTimeProfileTestCase.java
Sun Sep 13 21:25:29 2009
@@ -20,7 +20,6 @@
package org.apache.vysper.xmpp.datetime;
import java.util.Calendar;
-import java.util.Date;
import java.util.TimeZone;
import junit.framework.TestCase;
@@ -58,14 +57,18 @@
public void testParseDateTimeWithTz() throws Exception {
- Date actual = dt.fromDateTime("2009-09-11T11:12:13-01:30");
- Date expected = new Date(109, 8, 11, 9, 42, 13);
+ Calendar actual = dt.fromDateTime("2009-09-11T11:12:13-01:30");
+ Calendar expected =
Calendar.getInstance(TimeZone.getTimeZone("GMT-01:30"));
+ expected.clear();
+ expected.set(2009, 8, 11, 11, 12, 13);
assertEquals(expected, actual);
}
public void testParseDateTimeWithUTCTz() throws Exception {
- Date actual = dt.fromDateTime("2009-09-11T11:12:13Z");
- Date expected = new Date(109, 8, 11, 11, 12, 13);
+ Calendar actual = dt.fromDateTime("2009-09-11T11:12:13Z");
+ Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ expected.clear();
+ expected.set(2009, 8, 11, 11, 12, 13);
assertEquals(expected, actual);
}
@@ -79,26 +82,41 @@
}
public void testParseTimeWithTz() throws Exception {
- Date actual = dt.fromTime("11:12:13-01:30");
- Date expected = new Date(70, 0, 1, 9, 42, 13);
+ Calendar actual = dt.fromTime("11:12:13-01:30");
+ Calendar expected =
Calendar.getInstance(TimeZone.getTimeZone("GMT-01:30"));
+ expected.clear();
+ expected.set(Calendar.HOUR_OF_DAY, 11);
+ expected.set(Calendar.MINUTE, 12);
+ expected.set(Calendar.SECOND, 13);
+
assertEquals(expected, actual);
}
public void testParseTimeWithUTCTz() throws Exception {
- Date actual = dt.fromTime("11:12:13Z");
- Date expected = new Date(70, 0, 1, 11, 12, 13);
+ Calendar actual = dt.fromTime("11:12:13Z");
+ Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ expected.clear();
+ expected.set(Calendar.HOUR_OF_DAY, 11);
+ expected.set(Calendar.MINUTE, 12);
+ expected.set(Calendar.SECOND, 13);
assertEquals(expected, actual);
}
public void testParseTimeWithoutTz() throws Exception {
- Date actual = dt.fromTime("11:12:13");
- Date expected = new Date(70, 0, 1, 11, 12, 13);
+ Calendar actual = dt.fromTime("11:12:13");
+ Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ expected.clear();
+ expected.set(Calendar.HOUR_OF_DAY, 11);
+ expected.set(Calendar.MINUTE, 12);
+ expected.set(Calendar.SECOND, 13);
assertEquals(expected, actual);
}
public void testParseDate() throws Exception {
- Date actual = dt.fromDate("2009-09-11");
- Date expected = new Date(109, 8, 11);
+ Calendar actual = dt.fromDate("2009-09-11");
+ Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ expected.clear();
+ expected.set(2009, 8, 11);
assertEquals(expected, actual);
}