Skip to content

Instantly share code, notes, and snippets.

@mraccola
Last active August 10, 2021 23:29
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save mraccola/702330625fad8eebe7d3 to your computer and use it in GitHub Desktop.
Save mraccola/702330625fad8eebe7d3 to your computer and use it in GitHub Desktop.
Android DateUtils for RFC 1123 dates and ISO 8601 dates
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
}
}
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