From e0e92eca7636927965c7f668e79820f4a4cea58b Mon Sep 17 00:00:00 2001 From: rcollier Date: Wed, 6 Feb 2013 03:38:11 +0000 Subject: [PATCH] SMACK-407 Time zones now parse correctly. git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@13442 b35dd754-fafc-0310-a699-88a17e54d16e --- .../smack/util/DateFormatType.java | 8 +- .../jivesoftware/smack/util/StringUtils.java | 34 ++++++- .../smack/util/StringUtilsTest.java | 93 +++++++++++++++++-- 3 files changed, 120 insertions(+), 15 deletions(-) diff --git a/source/org/jivesoftware/smack/util/DateFormatType.java b/source/org/jivesoftware/smack/util/DateFormatType.java index 2ecef756f..e1eb83896 100644 --- a/source/org/jivesoftware/smack/util/DateFormatType.java +++ b/source/org/jivesoftware/smack/util/DateFormatType.java @@ -10,12 +10,12 @@ import java.text.SimpleDateFormat; public enum DateFormatType { XEP_0082_DATE_PROFILE("yyyy-MM-dd"), - XEP_0082_DATETIME_PROFILE("yyyy-MM-dd'T'HH:mm:ss'Z'"), - XEP_0082_DATETIME_MILLIS_PROFILE("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"), + XEP_0082_DATETIME_PROFILE("yyyy-MM-dd'T'HH:mm:ssZ"), + XEP_0082_DATETIME_MILLIS_PROFILE("yyyy-MM-dd'T'HH:mm:ss.SSSZ"), XEP_0082_TIME_PROFILE("hh:mm:ss"), - XEP_0082_TIME_ZONE_PROFILE("hh:mm:ss'Z'"), + XEP_0082_TIME_ZONE_PROFILE("hh:mm:ssZ"), XEP_0082_TIME_MILLIS_PROFILE("hh:mm:ss.SSS"), - XEP_0082_TIME_MILLIS_ZONE_PROFILE("hh:mm:ss.SSS'Z'"), + XEP_0082_TIME_MILLIS_ZONE_PROFILE("hh:mm:ss.SSSZ"), XEP_0091_DATETIME("yyyyMMdd'T'HH:mm:ss"); private String formatString; diff --git a/source/org/jivesoftware/smack/util/StringUtils.java b/source/org/jivesoftware/smack/util/StringUtils.java index ceba26b38..39bc54945 100644 --- a/source/org/jivesoftware/smack/util/StringUtils.java +++ b/source/org/jivesoftware/smack/util/StringUtils.java @@ -71,7 +71,7 @@ public class StringUtils { private static final DateFormat dateTimeFormatter = DateFormatType.XEP_0082_DATETIME_MILLIS_PROFILE.createFormatter(); private static final Pattern dateTimePattern = Pattern.compile("^\\d+(-\\d+){2}+T(\\d+:){2}\\d+.\\d+(Z|([+-](\\d+:\\d+)))?$"); - private static final DateFormat dateTimeNoMillisFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + private static final DateFormat dateTimeNoMillisFormatter = DateFormatType.XEP_0082_DATETIME_PROFILE.createFormatter(); private static final Pattern dateTimeNoMillisPattern = Pattern.compile("^\\d+(-\\d+){2}+T(\\d+:){2}\\d+(Z|([+-](\\d+:\\d+)))?$"); private static final DateFormat xep0091Formatter = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss"); @@ -101,11 +101,11 @@ public class StringUtils { xep0091Date7Digit2MonthFormatter.setLenient(false); couplings.add(new PatternCouplings(datePattern, dateFormatter)); - couplings.add(new PatternCouplings(dateTimePattern, dateTimeFormatter)); - couplings.add(new PatternCouplings(dateTimeNoMillisPattern, dateTimeNoMillisFormatter)); - couplings.add(new PatternCouplings(timePattern, timeFormatter)); + couplings.add(new PatternCouplings(dateTimePattern, dateTimeFormatter, true)); + couplings.add(new PatternCouplings(dateTimeNoMillisPattern, dateTimeNoMillisFormatter, true)); + couplings.add(new PatternCouplings(timePattern, timeFormatter, true)); couplings.add(new PatternCouplings(timeNoZonePattern, timeNoZoneFormatter)); - couplings.add(new PatternCouplings(timeNoMillisPattern, timeNoMillisFormatter)); + couplings.add(new PatternCouplings(timeNoMillisPattern, timeNoMillisFormatter, true)); couplings.add(new PatternCouplings(timeNoMillisNoZonePattern, timeNoMillisNoZoneFormatter)); } @@ -165,6 +165,10 @@ public class StringUtils { if (matcher.matches()) { + if (coupling.needToConvertTimeZone) { + dateString = coupling.convertTime(dateString); + } + synchronized (coupling.formatter) { return coupling.formatter.parse(dateString); } @@ -752,11 +756,31 @@ public class StringUtils { private static class PatternCouplings { Pattern pattern; DateFormat formatter; + boolean needToConvertTimeZone = false; public PatternCouplings(Pattern datePattern, DateFormat dateFormat) { pattern = datePattern; formatter = dateFormat; } + + public PatternCouplings(Pattern datePattern, DateFormat dateFormat, boolean shouldConvertToRFC822) { + pattern = datePattern; + formatter = dateFormat; + needToConvertTimeZone = shouldConvertToRFC822; + } + + public String convertTime(String dateString) { + if (dateString.charAt(dateString.length() - 1) == 'Z') { + return 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 + return dateString.replaceAll("([\\+\\-]\\d\\d):(\\d\\d)","$1$2"); + } + } } } diff --git a/test-unit/org/jivesoftware/smack/util/StringUtilsTest.java b/test-unit/org/jivesoftware/smack/util/StringUtilsTest.java index c2f892fdc..5564918b8 100644 --- a/test-unit/org/jivesoftware/smack/util/StringUtilsTest.java +++ b/test-unit/org/jivesoftware/smack/util/StringUtilsTest.java @@ -253,7 +253,7 @@ public class StringUtilsTest { } @Test - public void parseXep0082DateProfile() throws Exception + public void parseXep0082Date() throws Exception { Date date = StringUtils.parseDate("1971-07-21"); Calendar cal = Calendar.getInstance(); @@ -265,7 +265,7 @@ public class StringUtilsTest { } @Test - public void parseXep0082TimeProfile() throws Exception + public void parseXep0082Time() throws Exception { Date date = StringUtils.parseDate("02:56:15"); Calendar cal = Calendar.getInstance(); @@ -277,7 +277,31 @@ public class StringUtilsTest { } @Test - public void parseXep0082TimeWithMillisProfile() throws Exception + public void parseXep0082TimeUTC() throws Exception + { + Date date = StringUtils.parseDate("02:56:15Z"); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.setTimeZone(TimeZone.getTimeZone("GMT")); + assertEquals(2, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(56, cal.get(Calendar.MINUTE)); + assertEquals(15, cal.get(Calendar.SECOND)); + } + + @Test + public void parseXep0082TimeWithZone() throws Exception + { + Date date = StringUtils.parseDate("04:40:15+02:30"); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.setTimeZone(TimeZone.getTimeZone("GMT")); + assertEquals(2, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(10, cal.get(Calendar.MINUTE)); + assertEquals(15, cal.get(Calendar.SECOND)); + } + + @Test + public void parseXep0082TimeWithMillis() throws Exception { Date date = StringUtils.parseDate("02:56:15.123"); Calendar cal = Calendar.getInstance(); @@ -290,7 +314,33 @@ public class StringUtilsTest { } @Test - public void parseXep0082DateTimeProfile() throws Exception + public void parseXep0082TimeWithMillisUTC() throws Exception + { + Date date = StringUtils.parseDate("02:56:15.123Z"); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.setTimeZone(TimeZone.getTimeZone("GMT")); + assertEquals(2, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(56, cal.get(Calendar.MINUTE)); + assertEquals(15, cal.get(Calendar.SECOND)); + assertEquals(123, cal.get(Calendar.MILLISECOND)); + } + + @Test + public void parseXep0082TimeWithMillisZone() throws Exception + { + Date date = StringUtils.parseDate("02:56:15.123+01:00"); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.setTimeZone(TimeZone.getTimeZone("GMT")); + assertEquals(1, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(56, cal.get(Calendar.MINUTE)); + assertEquals(15, cal.get(Calendar.SECOND)); + assertEquals(123, cal.get(Calendar.MILLISECOND)); + } + + @Test + public void parseXep0082DateTimeUTC() throws Exception { Date date = StringUtils.parseDate("1971-07-21T02:56:15Z"); Calendar cal = Calendar.getInstance(); @@ -303,9 +353,24 @@ public class StringUtilsTest { assertEquals(56, cal.get(Calendar.MINUTE)); assertEquals(15, cal.get(Calendar.SECOND)); } - + @Test - public void parseXep0082DateTimeProfileWithMillis() throws Exception + public void parseXep0082DateTimeZone() throws Exception + { + Date date = StringUtils.parseDate("1971-07-21T02:56:15-01:00"); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.setTimeZone(TimeZone.getTimeZone("GMT")); + assertEquals(1971, cal.get(Calendar.YEAR)); + assertEquals(6, cal.get(Calendar.MONTH)); + assertEquals(21, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(3, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(56, cal.get(Calendar.MINUTE)); + assertEquals(15, cal.get(Calendar.SECOND)); + } + + @Test + public void parseXep0082DateTimeWithMillisUTC() throws Exception { Date date = StringUtils.parseDate("1971-07-21T02:56:15.123Z"); Calendar cal = Calendar.getInstance(); @@ -320,6 +385,22 @@ public class StringUtilsTest { assertEquals(123, cal.get(Calendar.MILLISECOND)); } + @Test + public void parseXep0082DateTimeWithMillisZone() throws Exception + { + Date date = StringUtils.parseDate("1971-07-21T02:56:15.123-01:00"); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.setTimeZone(TimeZone.getTimeZone("GMT")); + assertEquals(1971, cal.get(Calendar.YEAR)); + assertEquals(6, cal.get(Calendar.MONTH)); + assertEquals(21, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(3, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(56, cal.get(Calendar.MINUTE)); + assertEquals(15, cal.get(Calendar.SECOND)); + assertEquals(123, cal.get(Calendar.MILLISECOND)); + } + @Test public void parseXep0091() throws Exception {