Last active
August 10, 2021 23:29
-
-
Save mraccola/702330625fad8eebe7d3 to your computer and use it in GitHub Desktop.
Android DateUtils for RFC 1123 dates and ISO 8601 dates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.wta.util; | |
import java.text.ParseException; | |
import java.text.SimpleDateFormat; | |
import java.util.Date; | |
import java.util.Locale; | |
import java.util.TimeZone; | |
public final class DateUtils { | |
// RFC 1123 constants | |
private static final String RFC_1123_DATE_TIME = "EEE, dd MMM yyyy HH:mm:ss z"; | |
// ISO 8601 constants | |
private static final String ISO_8601_PATTERN_1 = "yyyy-MM-dd'T'HH:mm:ssZ"; | |
private static final String ISO_8601_PATTERN_2 = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; | |
private static final String[] SUPPORTED_ISO_8601_PATTERNS = new String[]{ISO_8601_PATTERN_1, | |
ISO_8601_PATTERN_2}; | |
private static final int TICK_MARK_COUNT = 2; | |
private static final int COLON_PREFIX_COUNT = "+00".length(); | |
private static final int COLON_INDEX = 22; | |
/** | |
* Parses a date from the specified RFC 1123-compliant string. | |
* | |
* @param string the string to parse | |
* @return the {@link Date} resulting from the parsing, or null if the string could not be | |
* parsed | |
*/ | |
public static Date parseRfc1123DateTime(String string) { | |
try { | |
return new SimpleDateFormat(RFC_1123_DATE_TIME, Locale.US).parse(string); | |
} catch (ParseException e) { | |
return null; | |
} | |
} | |
/** | |
* Formats the specified date to an RFC 1123-compliant string. | |
* | |
* @param date the date to format | |
* @param timeZone the {@link TimeZone} to use when formatting the date | |
* @return the formatted string | |
*/ | |
public static String formatRfc1123DateTime(Date date, TimeZone timeZone) { | |
SimpleDateFormat dateFormat = new SimpleDateFormat(RFC_1123_DATE_TIME, Locale.US); | |
if (timeZone != null) { | |
dateFormat.setTimeZone(timeZone); | |
} | |
return dateFormat.format(date); | |
} | |
/** | |
* Parses a date from the specified ISO 8601-compliant string. | |
* | |
* @param string the string to parse | |
* @return the {@link Date} resulting from the parsing, or null if the string could not be | |
* parsed | |
*/ | |
public static Date parseIso8601DateTime(String string) { | |
if (string == null) { | |
return null; | |
} | |
String s = string.replace("Z", "+00:00"); | |
for (String pattern : SUPPORTED_ISO_8601_PATTERNS) { | |
String str = s; | |
int colonPosition = pattern.lastIndexOf('Z') - TICK_MARK_COUNT + COLON_PREFIX_COUNT; | |
if (str.length() > colonPosition) { | |
str = str.substring(0, colonPosition) + str.substring(colonPosition + 1); | |
} | |
try { | |
return new SimpleDateFormat(pattern, Locale.US).parse(str); | |
} catch (final ParseException e) { | |
// try the next one | |
} | |
} | |
return null; | |
} | |
/** | |
* Formats the specified date to an ISO 8601-compliant string. | |
* | |
* @param date the date to format | |
* @param timeZone the {@link TimeZone} to use when formatting the date | |
* @return the formatted string | |
*/ | |
public static String formatIso8601DateTime(Date date, TimeZone timeZone) { | |
SimpleDateFormat dateFormat = new SimpleDateFormat(ISO_8601_PATTERN_1, Locale.US); | |
if (timeZone != null) { | |
dateFormat.setTimeZone(timeZone); | |
} | |
String formatted = dateFormat.format(date); | |
if (formatted != null && formatted.length() > COLON_INDEX) { | |
formatted = formatted.substring(0, 22) + ":" + formatted.substring(22); | |
} | |
return formatted; | |
} | |
private DateUtils() { | |
// hide constructor | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.wta.util; | |
import org.junit.Test; | |
import java.util.Calendar; | |
import java.util.Date; | |
import java.util.TimeZone; | |
import static junit.framework.Assert.assertEquals; | |
import static junit.framework.Assert.assertNull; | |
public class DateUtilsTest { | |
@Test | |
public void testParseRfc1123DateTime() throws Exception { | |
Calendar cal = Calendar.getInstance(); | |
cal.clear(); | |
cal.setTimeZone(TimeZone.getTimeZone("GMT")); | |
cal.set(Calendar.YEAR, 2015); | |
cal.set(Calendar.MONTH, Calendar.JUNE); | |
cal.set(Calendar.DATE, 20); | |
cal.set(Calendar.HOUR, 2); | |
cal.set(Calendar.MINUTE, 37); | |
cal.set(Calendar.SECOND, 14); | |
Date expected = cal.getTime(); | |
assertEquals(expected, DateUtils.parseRfc1123DateTime("Sat, 20 Jun 2015 02:37:14 GMT")); | |
assertNull(DateUtils.parseRfc1123DateTime("Sat, 20 Jun 2015 02:37:14")); | |
assertNull(DateUtils.parseRfc1123DateTime("Sat, 20 Jun 2015")); | |
} | |
@Test | |
public void testFormatRfc1123DateTime() throws Exception { | |
Calendar cal = Calendar.getInstance(); | |
cal.clear(); | |
cal.setTimeZone(TimeZone.getTimeZone("GMT+1")); | |
cal.set(Calendar.YEAR, 2015); | |
cal.set(Calendar.MONTH, Calendar.JUNE); | |
cal.set(Calendar.DATE, 20); | |
cal.set(Calendar.HOUR, 2); | |
cal.set(Calendar.MINUTE, 37); | |
cal.set(Calendar.SECOND, 14); | |
Date date = cal.getTime(); | |
TimeZone tz = TimeZone.getTimeZone("GMT"); | |
assertEquals("Sat, 20 Jun 2015 01:37:14 GMT", DateUtils.formatRfc1123DateTime(date, tz)); | |
} | |
@Test | |
public void testParseIso8601DateTime() throws Exception { | |
Calendar cal = Calendar.getInstance(); | |
cal.clear(); | |
cal.setTimeZone(TimeZone.getTimeZone("GMT")); | |
cal.set(Calendar.YEAR, 1997); | |
cal.set(Calendar.MONTH, Calendar.JULY); | |
cal.set(Calendar.DATE, 16); | |
cal.set(Calendar.HOUR, 18); | |
cal.set(Calendar.MINUTE, 20); | |
cal.set(Calendar.SECOND, 30); | |
Date expected = cal.getTime(); | |
// dates without times or time zones are not supported | |
assertNull(DateUtils.parseIso8601DateTime("1997")); | |
assertNull(DateUtils.parseIso8601DateTime("1997-07")); | |
assertNull(DateUtils.parseIso8601DateTime("1997-07-16")); | |
// dates without seconds are not supported | |
assertNull(DateUtils.parseIso8601DateTime("1997-07-16T19:20+01:00")); | |
// dates with fractional seconds containing less that 3 digits are not supported | |
assertNull(DateUtils.parseIso8601DateTime("1997-07-16T19:20:30.45+01:00")); | |
assertEquals(expected, DateUtils.parseIso8601DateTime("1997-07-16T19:20:30+01:00")); | |
assertEquals(expected, DateUtils.parseIso8601DateTime("1997-07-16T18:20:30Z")); | |
cal.set(Calendar.MILLISECOND, 235); | |
expected = cal.getTime(); | |
assertEquals(expected, DateUtils.parseIso8601DateTime("1997-07-16T19:20:30.235+01:00")); | |
assertEquals(expected, DateUtils.parseIso8601DateTime("1997-07-16T18:20:30.235Z")); | |
} | |
@Test | |
public void testFormatIso8601DateTime() throws Exception { | |
Calendar cal = Calendar.getInstance(); | |
cal.clear(); | |
cal.setTimeZone(TimeZone.getTimeZone("GMT+1")); | |
cal.set(Calendar.YEAR, 1997); | |
cal.set(Calendar.MONTH, Calendar.JULY); | |
cal.set(Calendar.DATE, 16); | |
cal.set(Calendar.HOUR, 19); | |
cal.set(Calendar.MINUTE, 20); | |
cal.set(Calendar.SECOND, 30); | |
Date date = cal.getTime(); | |
TimeZone tz = TimeZone.getTimeZone("GMT"); | |
assertEquals("1997-07-16T18:20:30+00:00", DateUtils.formatIso8601DateTime(date, tz)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment