package de.danoeh.antennapod.core.util; import android.content.Context; import android.util.Log; import org.apache.commons.lang3.StringUtils; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; /** * Parses several date formats. */ public class DateUtils { private DateUtils(){} private static final String TAG = "DateUtils"; private static final TimeZone defaultTimezone = TimeZone.getTimeZone("GMT"); public static Date parse(final String input) { if(input == null) { throw new IllegalArgumentException("Date must not be null"); } String date = input.trim().replace('/', '-').replaceAll("( ){2,}+", " "); // if datetime is more precise than seconds, make sure the value is in ms if(date.contains(".")) { int start = date.indexOf('.'); int current = start+1; while(current < date.length() && Character.isDigit(date.charAt(current))) { current++; } // even more precise than microseconds: discard further decimal places if(current - start > 4) { if(current < date.length()-1) { date = date.substring(0, start + 4) + date.substring(current); } else { date = date.substring(0, start + 4); } // less than 4 decimal places: pad to have a consistent format for the parser } else if(current - start < 4) { if(current < date.length()-1) { date = date.substring(0, current) + StringUtils.repeat("0", 4-(current-start)) + date.substring(current); } else { date = date.substring(0, current) + StringUtils.repeat("0", 4-(current-start)); } } } String[] patterns = { "dd MMM yy HH:mm:ss Z", "dd MMM yy HH:mm Z", "EEE, dd MMM yyyy HH:mm:ss Z", "EEE, dd MMM yyyy HH:mm:ss", "EEE, dd MMMM yyyy HH:mm:ss Z", "EEE, dd MMMM yyyy HH:mm:ss", "EEEE, dd MMM yyyy HH:mm:ss Z", "EEEE, dd MMM yy HH:mm:ss Z", "EEEE, dd MMM yyyy HH:mm:ss", "EEEE, dd MMM yy HH:mm:ss", "EEE MMM d HH:mm:ss yyyy", "EEE, dd MMM yyyy HH:mm Z", "EEE, dd MMM yyyy HH:mm", "EEE, dd MMMM yyyy HH:mm Z", "EEE, dd MMMM yyyy HH:mm", "EEEE, dd MMM yyyy HH:mm Z", "EEEE, dd MMM yy HH:mm Z", "EEEE, dd MMM yyyy HH:mm", "EEEE, dd MMM yy HH:mm", "EEE MMM d HH:mm yyyy", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ss.SSS Z", "yyyy-MM-dd'T'HH:mm:ss.SSS", "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss'Z'", "yyyy-MM-ddZ", "yyyy-MM-dd" }; SimpleDateFormat parser = new SimpleDateFormat("", Locale.US); parser.setLenient(false); parser.setTimeZone(defaultTimezone); ParsePosition pos = new ParsePosition(0); for(String pattern : patterns) { parser.applyPattern(pattern); pos.setIndex(0); try { Date result = parser.parse(date, pos); if (result != null && pos.getIndex() == date.length()) { return result; } } catch(Exception e) { Log.e(TAG, Log.getStackTraceString(e)); } } Log.d(TAG, "Could not parse date string \"" + input + "\" [" + date + "]"); return null; } /** * Takes a string of the form [HH:]MM:SS[.mmm] and converts it to * milliseconds. * * @throws java.lang.NumberFormatException if the number segments contain invalid numbers. */ public static long parseTimeString(final String time) { String[] parts = time.split(":"); long result = 0; int idx = 0; if (parts.length == 3) { // string has hours result += Integer.parseInt(parts[idx]) * 3600000L; idx++; } if (parts.length >= 2) { result += Integer.parseInt(parts[idx]) * 60000L; idx++; result += (Float.parseFloat(parts[idx])) * 1000L; } return result; } public static String formatRFC822Date(Date date) { SimpleDateFormat format = new SimpleDateFormat("dd MMM yy HH:mm:ss Z", Locale.US); return format.format(date); } public static String formatRFC3339Local(Date date) { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US); return format.format(date); } public static String formatRFC3339UTC(Date date) { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); format.setTimeZone(defaultTimezone); return format.format(date); } public static String formatAbbrev(final Context context, final Date date) { if(date == null) { return ""; } GregorianCalendar cal = new GregorianCalendar(); cal.add(GregorianCalendar.YEAR, -1); // some padding, because no one really remembers what day of the month it is cal.add(GregorianCalendar.DAY_OF_MONTH, 10); boolean withinLastYear = date.after(cal.getTime()); int format = android.text.format.DateUtils.FORMAT_ABBREV_ALL; if(withinLastYear) { format |= android.text.format.DateUtils.FORMAT_NO_YEAR; } return android.text.format.DateUtils.formatDateTime(context, date.getTime(), format); } }