Added RFC3339 utility
Project: http://git-wip-us.apache.org/repos/asf/incubator-streams/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-streams/commit/361fea93 Tree: http://git-wip-us.apache.org/repos/asf/incubator-streams/tree/361fea93 Diff: http://git-wip-us.apache.org/repos/asf/incubator-streams/diff/361fea93 Branch: refs/heads/master Commit: 361fea93d448393f81585eaf9665a5d1365f13ab Parents: eb6f46a Author: mfranklin <[email protected]> Authored: Mon Mar 31 22:59:53 2014 -0400 Committer: mfranklin <[email protected]> Committed: Mon Mar 31 22:59:53 2014 -0400 ---------------------------------------------------------------------- .../apache/streams/data/util/RFC3339Utils.java | 94 ++++++++++++ .../data/data/util/RFC3339UtilsTest.java | 147 +++++++++++++++++++ 2 files changed, 241 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/361fea93/streams-pojo/src/main/java/org/apache/streams/data/util/RFC3339Utils.java ---------------------------------------------------------------------- diff --git a/streams-pojo/src/main/java/org/apache/streams/data/util/RFC3339Utils.java b/streams-pojo/src/main/java/org/apache/streams/data/util/RFC3339Utils.java new file mode 100644 index 0000000..9b8339e --- /dev/null +++ b/streams-pojo/src/main/java/org/apache/streams/data/util/RFC3339Utils.java @@ -0,0 +1,94 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* +* 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.apache.streams.data.util; + +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; + +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Parses and formats Joda Time {@link org.joda.time.DateTime} dates to and from RFC3339 compatible Strings + */ +public class RFC3339Utils { + private static final String BASE = "^[0-9]{4}\\-[0-9]{2}\\-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}"; + private static final String TZ = "[+-][0-9]{2}:?[0-9]{2}$"; + private static final String SUB_SECOND = "\\.([0-9]*)"; + private static final String UTC = "Z$"; + + private static final Pattern MILLIS = Pattern.compile("^[0-9]*$"); + private static final Pattern UTC_STANDARD = Pattern.compile(BASE + UTC); + private static final Pattern UTC_SUB_SECOND = Pattern.compile(BASE + SUB_SECOND + UTC); + private static final Pattern LOCAL_STANDARD = Pattern.compile(BASE + TZ); + private static final Pattern LOCAL_SUB_SECOND = Pattern.compile(BASE + SUB_SECOND + TZ); + + private static final String BASE_FMT = "yyyy-MM-dd'T'HH:mm:ss"; + private static final DateTimeFormatter UTC_STANDARD_FMT = DateTimeFormat.forPattern(BASE_FMT + "'Z'").withZoneUTC(); + private static final DateTimeFormatter LOCAL_STANDARD_FMT = DateTimeFormat.forPattern(BASE_FMT + "Z").withZoneUTC(); + + + private RFC3339Utils() {} + + public static DateTime parseUTC(String toParse) { + if(MILLIS.matcher(toParse).matches()) { + return new DateTime(Long.valueOf(toParse)); + } + if(UTC_STANDARD.matcher(toParse).matches()) { + return parseUTC(UTC_STANDARD_FMT, toParse); + } + Matcher utc = UTC_SUB_SECOND.matcher(toParse); + if(utc.matches()) { + return parseUTC(getSubSecondFormat(utc.group(1), "'Z'"), toParse); + } + if(LOCAL_STANDARD.matcher(toParse).matches()) { + return parseUTC(LOCAL_STANDARD_FMT, toParse); + } + Matcher local = LOCAL_SUB_SECOND.matcher(toParse); + if(local.matches()) { + return parseUTC(getSubSecondFormat(local.group(1), "Z"), toParse); + } + throw new IllegalArgumentException(String.format("Failed to parse date %s. Ensure format is RFC3339 Compliant", toParse)); + } + + public static String format(DateTime toFormat) { + return UTC_STANDARD_FMT.print(toFormat.getMillis()); + } + + public static String format(DateTime toFormat, Locale locale) { + return LOCAL_STANDARD_FMT.withLocale(locale).print(toFormat.getMillis()); + } + + private static DateTime parseUTC(DateTimeFormatter formatter, String toParse) { + return formatter.parseDateTime(toParse); + } + + private static DateTimeFormatter getSubSecondFormat(String sub, String suffix) { + StringBuilder pattern = new StringBuilder(); + pattern.append(BASE_FMT); + pattern.append("."); + for(int i=0; i<sub.length(); i++) { + pattern.append("S"); + } + pattern.append(suffix); + return DateTimeFormat.forPattern(pattern.toString()).withZoneUTC(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/361fea93/streams-pojo/src/test/java/org/apache/streams/data/data/util/RFC3339UtilsTest.java ---------------------------------------------------------------------- diff --git a/streams-pojo/src/test/java/org/apache/streams/data/data/util/RFC3339UtilsTest.java b/streams-pojo/src/test/java/org/apache/streams/data/data/util/RFC3339UtilsTest.java new file mode 100644 index 0000000..0471d2b --- /dev/null +++ b/streams-pojo/src/test/java/org/apache/streams/data/data/util/RFC3339UtilsTest.java @@ -0,0 +1,147 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* +* 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.apache.streams.data.data.util; + + +import org.joda.time.DateTime; +import org.junit.Test; + +import static org.apache.streams.data.util.RFC3339Utils.parseUTC; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +public class RFC3339UtilsTest { + + @Test + public void validUTC() { + DateTime parsed = parseUTC("2014-12-25T12:00:00Z"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(12))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + } + + @Test + public void validUTCSubSecond() { + DateTime parsed = parseUTC("2014-12-25T12:00:00.7Z"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(12))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + assertThat(parsed.millisOfSecond().get(), is(equalTo(700))); + } + + @Test + public void validUTCSubSecondMultiDigit() { + DateTime parsed = parseUTC("2014-12-25T12:00:00.7343Z"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(12))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + assertThat(parsed.millisOfSecond().get(), is(equalTo(734))); + } + + @Test + public void validEST() { + DateTime parsed = parseUTC("2014-12-25T12:00:00-05:00"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(17))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + } + + @Test + public void validESTSubSecond() { + DateTime parsed = parseUTC("2014-12-25T12:00:00.7-05:00"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(17))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + assertThat(parsed.millisOfSecond().get(), is(equalTo(700))); + } + + @Test + public void validESTSubSecondMultiDigit() { + DateTime parsed = parseUTC("2014-12-25T12:00:00.7343-05:00"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(17))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + assertThat(parsed.millisOfSecond().get(), is(equalTo(734))); + } + + @Test + public void validESTNoSeparator() { + DateTime parsed = parseUTC("2014-12-25T12:00:00-0500"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(17))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + } + + @Test + public void validESTSubSecondNoSeparator() { + DateTime parsed = parseUTC("2014-12-25T12:00:00.7-0500"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(17))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + assertThat(parsed.millisOfSecond().get(), is(equalTo(700))); + } + + @Test + public void validESTSubSecondMultiDigitNoSeparator() { + DateTime parsed = parseUTC("2014-12-25T12:00:00.7343-0500"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(17))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + assertThat(parsed.millisOfSecond().get(), is(equalTo(734))); + } + + @Test + public void validCET() { + DateTime parsed = parseUTC("2014-12-25T12:00:00+01:00"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(11))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + } + + @Test + public void validCETSubSecond() { + DateTime parsed = parseUTC("2014-12-25T12:00:00.7+01:00"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(11))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + assertThat(parsed.millisOfSecond().get(), is(equalTo(700))); + } + + @Test + public void validCETSubSecondMultidigit() { + DateTime parsed = parseUTC("2014-12-25T12:00:00.7343+01:00"); + assertThat(parsed.minuteOfHour().get(), is(equalTo(0))); + assertThat(parsed.hourOfDay().get(), is(equalTo(11))); + assertThat(parsed.dayOfMonth().get(), is(equalTo(25))); + assertThat(parsed.monthOfYear().get(), is(equalTo(12))); + assertThat(parsed.millisOfSecond().get(), is(equalTo(734))); + System.out.println(parsed.getMillis()); + } +}
