package fr.cedrik.util; import java.text.DateFormat; import java.text.Format; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.TimeZone; import org.apache.commons.lang3.time.FastDateFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Cédrik LIME */ public abstract class DateUtils { private static final TimeZone UTC = TimeZone.getTimeZone("UTC");// TimeZone.GMT_ID private static final Logger logger = LoggerFactory.getLogger(DateUtils.class); /** * RFC 5322 datetime format: {@value} * @see <a href="http://www.ietf.org/rfc/rfc5322.txt">RFC 5322</a> */ public static final String RFC2822_DATE_TIME = "EEE, d MMM yyyy HH:mm:ss Z";//$NON-NLS-1$ public static final Format RFC2822_DATE_TIME_FORMAT = FastDateFormat.getInstance(RFC2822_DATE_TIME, Locale.US); /** * C asctime / ctime: "Tue May 21 13:46:22 1991" "Sat Jan 3 01:05:34 1996" */ public static final String MBOX_DATE_TIME = "EEE MMM dd HH:mm:ss yyyy";//$NON-NLS-1$ public static final Format MBOX_DATE_TIME_FORMAT = FastDateFormat.getInstance(MBOX_DATE_TIME, Locale.US); /** * Default ISO 8601 datetime format: {@value} * @see <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601 DateTime</a> * @see <a href="http://www.ietf.org/rfc/rfc3339.txt">RFC 3399</a> */ public static final String ISO8601_DATE_TIME = "yyyy-MM-dd'T'HH:mm:ssZZ";//$NON-NLS-1$ public static final Format ISO8601_DATE_TIME_FORMAT = FastDateFormat.getInstance(ISO8601_DATE_TIME); public static final String ISO8601_DATE = "yyyy-MM-dd";//$NON-NLS-1$ public static final String ISO8601_TIME = "HH:mm:ssZ";//$NON-NLS-1$ private DateUtils() { super(); } public static Date parseLotusXMLDate(String dateStr) throws ParseException { DateFormat df = new SimpleDateFormat("yyyyMMdd'T'HHmmss','SS'Z'");//$NON-NLS-1$ df.setTimeZone(UTC); return df.parse(dateStr); } /** * fix Lotus Notes broken date pattern: 29-Oct-2012 19:23:20 CET 10-Oct-2012 11:25:11 CEDT */ public static String fixLotusMIMEDateHeader(String line) { if (line.startsWith("Date: ") && line.contains("-")) {//$NON-NLS-1$//$NON-NLS-2$ final DateFormat LOTUS_NOTES_BROKEN_DATE_FORMAT = new SimpleDateFormat("d-MMM-yyyy HH:mm:ss z", Locale.US);//$NON-NLS-1$ LOTUS_NOTES_BROKEN_DATE_FORMAT.setLenient(false); String lineToParse = line; try { int minutesToAdd = 0; // TimeZones not recognized by SimpleDateFormat for (Map.Entry<String, Integer> tz : LOTUS_TZ.entrySet()) { if (lineToParse.endsWith(tz.getKey())) { lineToParse = line.substring(0, line.length() - tz.getKey().length()) + ' ' + GMT_ID; minutesToAdd = - tz.getValue().intValue(); } } Date date = LOTUS_NOTES_BROKEN_DATE_FORMAT.parse(lineToParse.substring("Date: ".length()).trim());//$NON-NLS-1$ if (minutesToAdd != 0) { date.setTime(date.getTime() + minutesToAdd * org.apache.commons.lang3.time.DateUtils.MILLIS_PER_MINUTE); } String rfcLine = "Date: " + RFC2822_DATE_TIME_FORMAT.format(date);//$NON-NLS-1$ logger.debug("Fixing broken Lotus Date header; before: {}\tafter: {}", line, rfcLine); line = rfcLine; } catch (ParseException notAnError) { logger.debug("Date header OK: {}", line); } } return line; } private static final String GMT_ID = "GMT";// TimeZone.GMT_ID private static final Map<String, Integer> LOTUS_TZ = new HashMap<String, Integer>(); // see http://www.ibm.com/developerworks/lotus/library/ls-keeping_time/side1.html // see http://tools.ietf.org/html/rfc5322#section-4.3 static { // LOTUS_TZ.put(" GMT", Integer.valueOf(0*60)); // Greenwich Mean Time LOTUS_TZ.put(" GDT", Integer.valueOf((0+1)*60)); LOTUS_TZ.put(" ZW1", Integer.valueOf(-1*60)); LOTUS_TZ.put(" YW1", Integer.valueOf((-1+1)*60)); LOTUS_TZ.put(" ZW1", Integer.valueOf(-2*60)); LOTUS_TZ.put(" YW2", Integer.valueOf((-2+1)*60)); LOTUS_TZ.put(" ZW3", Integer.valueOf(-3*60)); LOTUS_TZ.put(" YW3", Integer.valueOf((-3+1)*60)); LOTUS_TZ.put(" NST", Integer.valueOf(-3*60-30)); // Newfoundland LOTUS_TZ.put(" NDT", Integer.valueOf((-3+1)*60-30)); LOTUS_TZ.put(" AST", Integer.valueOf(-4*60)); // Atlantic Standard Time LOTUS_TZ.put(" ADT", Integer.valueOf((-4+1)*60)); LOTUS_TZ.put(" EST", Integer.valueOf(-5*60)); // Eastern Standard Time LOTUS_TZ.put(" EDT", Integer.valueOf((-5+1)*60)); LOTUS_TZ.put(" CST", Integer.valueOf(-6*60)); // Central Standard Time LOTUS_TZ.put(" CDT", Integer.valueOf((-6+1)*60)); LOTUS_TZ.put(" MST", Integer.valueOf(-7*60)); // Mountain Standard Time LOTUS_TZ.put(" MDT", Integer.valueOf((-7+1)*60)); LOTUS_TZ.put(" PST", Integer.valueOf(-8*60)); // Pacific Standard Time LOTUS_TZ.put(" PDT", Integer.valueOf((-8+1)*60)); LOTUS_TZ.put(" YST", Integer.valueOf(-9*60)); // Alaska Standard Time LOTUS_TZ.put(" YDT", Integer.valueOf((-9+1)*60)); LOTUS_TZ.put(" ZW9B", Integer.valueOf(-9*60-30)); LOTUS_TZ.put(" HST", Integer.valueOf(-10*60)); // Hawaii-Aleutian Standard Time LOTUS_TZ.put(" HDT", Integer.valueOf((-10+1)*60)); LOTUS_TZ.put(" BST", Integer.valueOf(-11*60)); // Bering Standard Time LOTUS_TZ.put(" BDT", Integer.valueOf((-11+1)*60)); LOTUS_TZ.put(" ZW12", Integer.valueOf(-12*60)); LOTUS_TZ.put(" ZE12C", Integer.valueOf(12*60+45)); LOTUS_TZ.put(" ZE12", Integer.valueOf(12*60)); LOTUS_TZ.put(" ZE11B", Integer.valueOf(11*60+30)); LOTUS_TZ.put(" ZE11", Integer.valueOf(11*60)); LOTUS_TZ.put(" ZE10B", Integer.valueOf(10*60+30)); LOTUS_TZ.put(" ZE10", Integer.valueOf(10*60)); LOTUS_TZ.put(" ZE9B", Integer.valueOf(9*60+30)); LOTUS_TZ.put(" ZE9", Integer.valueOf(9*60)); LOTUS_TZ.put(" ZE8", Integer.valueOf(8*60)); LOTUS_TZ.put(" ZE7", Integer.valueOf(7*60)); LOTUS_TZ.put(" ZE6B", Integer.valueOf(6*60+30)); LOTUS_TZ.put(" ZE6", Integer.valueOf(6*60)); LOTUS_TZ.put(" ZE5C", Integer.valueOf(5*60+45)); LOTUS_TZ.put(" ZE5B", Integer.valueOf(5*60+30)); LOTUS_TZ.put(" ZE5", Integer.valueOf(5*60)); LOTUS_TZ.put(" ZE4B", Integer.valueOf(4*60+30)); LOTUS_TZ.put(" ZE4", Integer.valueOf(4*60)); LOTUS_TZ.put(" ZE3B", Integer.valueOf(3*60+30)); LOTUS_TZ.put(" ZE3", Integer.valueOf(3*60)); LOTUS_TZ.put(" ZE2", Integer.valueOf(2*60)); LOTUS_TZ.put(" CET", Integer.valueOf(1*60)); // Central European Time LOTUS_TZ.put(" CEDT", Integer.valueOf((1+1)*60)); // remove JVM-known TZ entries Iterator<Map.Entry<String, Integer>> iterator = LOTUS_TZ.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Integer> lotus = iterator.next(); TimeZone tz = TimeZone.getTimeZone(lotus.getKey().trim()); if (tz != null && ! GMT_ID.equals(tz.getID())) { // logger.debug("Removing existing TZ: {}", lotus.getKey()); iterator.remove(); } } } }