Java tutorial
/* * Funambol is a mobile platform developed by Funambol, Inc. * Copyright (C) 2003 - 2007 Funambol, Inc. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License version 3 as published by * the Free Software Foundation with the addition of the following permission * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, see http://www.gnu.org/licenses or write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA. * * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License version 3. * * In accordance with Section 7(b) of the GNU Affero General Public License * version 3, these Appropriate Legal Notices must retain the display of the * "Powered by Funambol" logo. If the display of the logo is not reasonably * feasible for technical reasons, the Appropriate Legal Notices must display * the words "Powered by Funambol". */ import java.util.Calendar; import java.util.Date; import java.util.Hashtable; /** * A utility class providing methods to convert date information contained in * <code>Date</code> objects into RFC2822 and UTC ('Zulu') strings, and to * build <code>Date</code> objects starting from string representations of * dates in RFC2822 and UTC format */ public class MailDateFormatter { /** Format date as: MM/DD */ public static final int FORMAT_MONTH_DAY = 0; /** Format date as: MM/DD/YYYY */ public static final int FORMAT_MONTH_DAY_YEAR = 1; /** Format date as: hh:mm */ public static final int FORMAT_HOURS_MINUTES = 2; /** Format date as: hh:mm:ss */ public static final int FORMAT_HOURS_MINUTES_SECONDS = 3; /** Format date as: DD/MM */ public static final int FORMAT_DAY_MONTH = 4; /** Format date as: DD/MM/YYYY */ public static final int FORMAT_DAY_MONTH_YEAR = 5; /** Device offset, as string */ private static String deviceOffset = "+0000"; /** Device offset, in millis */ private static long millisDeviceOffset = 0; /** Names of the months */ private static String[] monthNames = new String[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /** * Transforms data contained in a <code>Date</code> object (expressed in * UTC) in a string formatted as per RFC2822 in local time (par. 3.3) * * @return A string representing the date contained in the passed * <code>Date</code> object formatted as per RFC 2822 and in local * time */ public static String dateToRfc2822(Date date) { Calendar deviceTime = Calendar.getInstance(); deviceTime.setTime(date); String dayweek = ""; int dayOfWeek = deviceTime.get(deviceTime.DAY_OF_WEEK); switch (dayOfWeek) { case 1: dayweek = "Sun"; break; case 2: dayweek = "Mon"; break; case 3: dayweek = "Tue"; break; case 4: dayweek = "Wed"; break; case 5: dayweek = "Thu"; break; case 6: dayweek = "Fri"; break; case 7: dayweek = "Sat"; break; } int dayOfMonth = deviceTime.get(deviceTime.DAY_OF_MONTH); String monthInYear = getMonthName(deviceTime.get(deviceTime.MONTH)); int year = deviceTime.get(deviceTime.YEAR); int hourOfDay = deviceTime.get(deviceTime.HOUR_OF_DAY); int minutes = deviceTime.get(deviceTime.MINUTE); int seconds = deviceTime.get(deviceTime.SECOND); String rfc = dayweek + ", " + // Tue dayOfMonth + " " + // 7 monthInYear + " " + // Nov year + " " + // 2006 hourOfDay + ":" + minutes + ":" + seconds + " " + // 14:13:26 deviceOffset; //+0200 return rfc; } /** * Converts a <code>Date</code> object into a string in 'Zulu' format * * @param d * A <code>Date</code> object to be converted into a string in * 'Zulu' format * @return A string representing the date contained in the passed * <code>Date</code> object in 'Zulu' format (e.g. * yyyyMMDDThhmmssZ) */ public static String dateToUTC(Date d) { StringBuffer date = new StringBuffer(); Calendar cal = Calendar.getInstance(); cal.setTime(d); date.append(cal.get(Calendar.YEAR)); date.append(printTwoDigits(cal.get(Calendar.MONTH) + 1)).append(printTwoDigits(cal.get(Calendar.DATE))) .append("T"); date.append(printTwoDigits(cal.get(Calendar.HOUR_OF_DAY))).append(printTwoDigits(cal.get(Calendar.MINUTE))) .append(printTwoDigits(cal.get(Calendar.SECOND))).append("Z"); return date.toString(); } /** * A method that returns a string rapresenting a date. * * @param date the date * * @param format the format as one of * FORMAT_MONTH_DAY, * FORMAT_MONTH_DAY_YEAR, * FORMAT_HOURS_MINUTES, * FORMAT_HOURS_MINUTES_SECONDS * FORMAT_DAY_MONTH * FORMAT_DAY_MONTH_YEAR * constants * * @param separator the separator to be used */ public static String getFormattedStringFromDate(Date date, int format, String separator) { Calendar cal = Calendar.getInstance(); cal.setTime(date); StringBuffer ret = new StringBuffer(); switch (format) { case FORMAT_HOURS_MINUTES: //if pm and hour == 0 we want to write 12, not 0 if (cal.get(Calendar.AM_PM) == Calendar.PM && cal.get(Calendar.HOUR) == 0) { ret.append("12"); } else { ret.append(cal.get(Calendar.HOUR)); } ret.append(separator).append(printTwoDigits(cal.get(Calendar.MINUTE))).append(getAMPM(cal)); break; case FORMAT_HOURS_MINUTES_SECONDS: //if pm and hour == 0 we want to write 12, not 0 if (cal.get(Calendar.AM_PM) == Calendar.PM && cal.get(Calendar.HOUR) == 0) { ret.append("12"); } else { ret.append(cal.get(Calendar.HOUR)); } ret.append(separator).append(printTwoDigits(cal.get(Calendar.MINUTE))).append(separator) .append(cal.get(Calendar.SECOND)).append(getAMPM(cal)); break; case FORMAT_MONTH_DAY: ret.append(cal.get(Calendar.MONTH) + 1).append(separator).append(cal.get(Calendar.DAY_OF_MONTH)); break; case FORMAT_DAY_MONTH: ret.append(cal.get(Calendar.DAY_OF_MONTH)).append(separator).append(cal.get(Calendar.MONTH) + 1); break; case FORMAT_MONTH_DAY_YEAR: ret.append(cal.get(Calendar.MONTH) + 1).append(separator).append(cal.get(Calendar.DAY_OF_MONTH)) .append(separator).append(cal.get(Calendar.YEAR)); break; case FORMAT_DAY_MONTH_YEAR: ret.append(cal.get(Calendar.DAY_OF_MONTH)).append(separator).append(cal.get(Calendar.MONTH) + 1) .append(separator).append(cal.get(Calendar.YEAR)); break; default: // Log.error("getFormattedStringFromDate: invalid format ("+ // format+")"); } return ret.toString(); } /** * Returns a localized string representation of Date. */ public static String formatLocalTime(Date d) { int dateFormat = FORMAT_MONTH_DAY_YEAR; int timeFormat = FORMAT_HOURS_MINUTES; if (!System.getProperty("microedition.locale").equals("en")) { dateFormat = FORMAT_DAY_MONTH_YEAR; } return getFormattedStringFromDate(d, FORMAT_MONTH_DAY_YEAR, "/") + " " + getFormattedStringFromDate(d, FORMAT_HOURS_MINUTES, ":"); } /** * Parses the string in RFC 2822 format and return a <code>Date</code> * object. <p> * Parse strings like: * Thu, 03 May 2007 14:45:38 GMT * Thu, 03 May 2007 14:45:38 GMT+0200 * Thu, 1 Feb 2007 03:57:01 -0800 * Fri, 04 May 2007 13:40:17 PDT * * @param d the date representation to parse * @return a date, if valid, or null on error * */ public static Date parseRfc2822Date(String stringDate) { if (stringDate == null) { return null; } long hourOffset = 0; long minOffset = 0; Calendar cal = Calendar.getInstance(); try { // We use the ' ' as separator and we expect only one space. We // clean the string to remove extra spaces StringBuffer cleanedDate = new StringBuffer(); char previous = 'a'; for (int i = 0; i < stringDate.length(); ++i) { char ch = stringDate.charAt(i); if (ch != ' ' || previous != ' ') { cleanedDate.append(ch); } previous = ch; } stringDate = cleanedDate.toString(); // Log.debug("Cleaned date: " + stringDate); // Just skip the weekday if present int start = stringDate.indexOf(','); //put start after ", " start = (start == -1) ? 0 : start + 2; stringDate = stringDate.substring(start).trim(); start = 0; // Get day of month int end = stringDate.indexOf(' ', start); //4 Nov 2008 10:30:05 -0400 int day = 1; try { day = Integer.parseInt(stringDate.substring(start, end)); } catch (NumberFormatException ex) { day = Integer.parseInt(stringDate.substring(start + 3, end)); } cal.set(Calendar.DAY_OF_MONTH, day); // Get month start = end + 1; end = stringDate.indexOf(' ', start); cal.set(Calendar.MONTH, getMonthNumber(stringDate.substring(start, end))); // Get year start = end + 1; end = stringDate.indexOf(' ', start); cal.set(Calendar.YEAR, Integer.parseInt(stringDate.substring(start, end))); // Get hour start = end + 1; end = stringDate.indexOf(':', start); cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(stringDate.substring(start, end).trim())); // Get min start = end + 1; end = stringDate.indexOf(':', start); cal.set(Calendar.MINUTE, Integer.parseInt(stringDate.substring(start, end))); // Get sec start = end + 1; end = stringDate.indexOf(' ', start); cal.set(Calendar.SECOND, Integer.parseInt(stringDate.substring(start, end))); // Get OFFSET start = end + 1; end = stringDate.indexOf('\r', start); // Process Timezone, checking first for the actual RFC2822 format, // and then for nthe obsolete syntax. char sign = '+'; String hourDiff = "0"; String minDiff = "0"; String offset = stringDate.substring(start).trim(); if (offset.startsWith("+") || offset.startsWith("-")) { if (offset.length() >= 5) { sign = offset.charAt(0); hourDiff = offset.substring(1, 3); minDiff = offset.substring(3, 5); } else if (offset.length() == 3) { sign = offset.charAt(0); hourDiff = offset.substring(1); minDiff = "00"; } // Convert offset to int hourOffset = Long.parseLong(hourDiff); minOffset = Long.parseLong(minDiff); if (sign == '-') { hourOffset = -hourOffset; } } else if (offset.equals("EDT")) { hourOffset = -4; } else if (offset.equals("EST") || offset.equals("CDT")) { hourOffset = -5; } else if (offset.equals("CST") || offset.equals("MDT")) { hourOffset = -6; } else if (offset.equals("PDT") || offset.equals("MST")) { hourOffset = -7; } else if (offset.equals("PST")) { hourOffset = -8; } else if (offset.equals("GMT") || offset.equals("UT")) { hourOffset = 0; } else if (offset.substring(0, 3).equals("GMT") && offset.length() > 3) { sign = offset.charAt(3); hourDiff = offset.substring(4, 6); minDiff = offset.substring(6, 8); } long millisOffset = (hourOffset * 3600000) + (minOffset * 60000); Date gmtDate = cal.getTime(); long millisDate = gmtDate.getTime(); millisDate -= millisOffset; gmtDate.setTime(millisDate); return gmtDate; } catch (Exception e) { e.printStackTrace(); return null; } } /** * Convert the given date (GMT) into the local date. * NOTE: changes the original date too! * Should we change it to a void toLocalDate(Date) that changes the * input date only? */ public static Date getDeviceLocalDate(Date gmtDate) { if (null != gmtDate) { /*long dateInMillis = gmtDate.getTime(); Date deviceDate = new Date(); deviceDate.setTime(dateInMillis+millisDeviceOffset); return deviceDate; **/ gmtDate.setTime(gmtDate.getTime() + millisDeviceOffset); return gmtDate; } else { return null; } } /** * Gets a <code>Date</code> object from a string representing a date in * 'Zulu' format (yyyyMMddTHHmmssZ) * * @param utc * date in 'Zulu' format (yyyyMMddTHHmmssZ) * @return A <code>Date</code> object obtained starting from a time in * milliseconds from the Epoch */ public static Date parseUTCDate(String utc) { int day = 0; int month = 0; int year = 0; int hour = 0; int minute = 0; int second = 0; Calendar calendar = null; day = Integer.parseInt(utc.substring(6, 8)); month = Integer.parseInt(utc.substring(4, 6)); year = Integer.parseInt(utc.substring(0, 4)); hour = Integer.parseInt(utc.substring(9, 11)); minute = Integer.parseInt(utc.substring(11, 13)); second = Integer.parseInt(utc.substring(13, 15)); calendar = Calendar.getInstance(); calendar.set(Calendar.DAY_OF_MONTH, day); calendar.set(Calendar.MONTH, month - 1); calendar.set(Calendar.YEAR, year); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); calendar.set(Calendar.SECOND, second); Date date = calendar.getTime(); long dateInMillis = date.getTime(); date.setTime(dateInMillis + millisDeviceOffset); return date; } public static void setTimeZone(String timeZone) { if (timeZone == null || timeZone.length() < 5) { // Log.error("setTimeZone: invalid timezone " + timeZone); } try { deviceOffset = timeZone; String hstmz = deviceOffset.substring(1, 3); String mstmz = deviceOffset.substring(3, 5); long hhtmz = Long.parseLong(hstmz); long mmtmz = Long.parseLong(mstmz); millisDeviceOffset = (hhtmz * 3600000) + (mmtmz * 60000); if (deviceOffset.charAt(0) == '-') { millisDeviceOffset *= -1; } } catch (Exception e) { e.printStackTrace(); } } /** * returns a date with string representation of the month * @param date input date in the format MM/DD/YYYY HH:MMp/a * @return a representation of the date in the format <MonthName> DD, YYYY HH:MM */ public static String getReplyDateString(String date) { StringBuffer ret = new StringBuffer(); //Replace the month number with the month name String monthName = getMonthName(Integer.parseInt(date.substring(0, date.indexOf('/'))) - 1); String day = date.substring(date.indexOf('/') + 1, date.lastIndexOf('/')); String yearAndTime = date.substring(date.lastIndexOf('/') + 1); ret.append(monthName).append(" ").append(day).append(", ").append(yearAndTime); //Replace the slash char between DD and YYYY with ", " return ret.toString(); } //------------------------------------------------------------- Private methods /** * Get the number of the month, given the name. */ private static int getMonthNumber(String name) { for (int i = 0, l = monthNames.length; i < l; i++) { if (monthNames[i].equals(name)) { return i; } } return -1; } /** * Get the name of the month, given the number. */ private static String getMonthName(int number) { if (number >= 0 && number < monthNames.length) { return monthNames[number]; } else return null; } private static String getAMPM(Calendar cal) { return (cal.get(Calendar.AM_PM) == Calendar.AM) ? "a" : "p"; } /** * Returns a string representation of number with at least 2 digits */ private static String printTwoDigits(int number) { if (number > 9) { return String.valueOf(number); } else { return "0" + number; } } }