Java tutorial
/** * Copyright 2007 University Of Southern California * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Create a common interface to handle obtaining string timestamps. * The difficult part is to allow for an ISO 8601 date formatting. * * @author Jens-S. Vckler * @author Yong Zhao * @version $Revision: 379 $ * * @see java.util.Date * @see java.text.SimpleDateFormat */ public class Currently { /** * This is used to format the time stamp. */ private SimpleDateFormat m_formatter = null; /** * Default time format, which is compact and has a timezone */ public static final String DEFAULT_FORMAT = "yyyy.MM.dd HH:mm:ss zzz"; /** * Default ctor: Create a new instance with a default formatting * string for timestamps. */ public Currently() { m_formatter = new SimpleDateFormat(DEFAULT_FORMAT); } /** * Ctor: Create a new instance with a formatting string for time stamps. * @param formatString complies to {@link java.text.SimpleDateFormat}. */ public Currently(String formatString) { m_formatter = new SimpleDateFormat(formatString); } /** * Ctor: Create a new instance with a formatting string for time stamps. * @param format is a description of the simple date format to use. */ public Currently(SimpleDateFormat format) { m_formatter = (SimpleDateFormat) format.clone(); } /** * Accessor: Obtains the default timestamp format for all queues. * * @return the currently active timestamp prefix format. * @see #setDateFormat( String ) * @see #setDateFormat( SimpleDateFormat ) */ public SimpleDateFormat getDateFormat() { return m_formatter; } /** * Accessor: Sets the default timestamp format for all queues. * * @param format is the new timestamp prefix format. * @see #setDateFormat( SimpleDateFormat ) * @see #getDateFormat() */ public void setDateFormat(SimpleDateFormat format) { if (format != null) { m_formatter = format; } } /** * Accessor: Sets the default timestamp format for all queues. * * @param format is the new timestamp prefix format as a string. * @see #setDateFormat( String ) * @see #getDateFormat() */ public void setDateFormat(String format) { if (format != null) { m_formatter = new SimpleDateFormat(format); } } /** * Obtains the current time as formatted string according to * the format option. * @return the current time as formatted string. * @see #now( Date ) */ public String now() { return this.now(new Date()); } /** * Obtains the current time as formatted string according to * the format option. * @param then is a timestamp expressed as Date. * @return the current time as formatted string. * @see #now() */ public String now(Date then) { return this.m_formatter.format(then); } /** * Store the regular expressions necessary to parse ISO timestamps. */ private static final String c_expression[] = { "([12][0-9]{3})-([01][0-9])-([0123][0-9])(T([012][0-9]):([0-6][0-9]):([0-6][0-9])?(\\.[0-9]+)?)?(Z|[-+][01][0-9]:?[0-6][0-9])?", "([12][0-9]{3})([01][0-9])([0123][0-9])(T?([012][0-9])([0-6][0-9])([0-6][0-9])?(\\.[0-9]+)?)?(Z|[-+][01][0-9]:?[0-6][0-9])?" }; /** * Stores compiled patterns at first use, quasi-Singleton. */ private static Pattern c_pattern[] = null; /** * Parses one of the ISO 8601 that it produces. Note, it will not * parse the full range of ISO timestamps. * * @param stamp is the textual timestamp representation. * @return a time or <code>null</code>, if unparsable. */ public static Date parse(String stamp) { // initialize the compiled expressions once if (c_pattern == null) { c_pattern = new Pattern[c_expression.length]; for (int i = 0; i < c_expression.length; ++i) { c_pattern[i] = Pattern.compile(c_expression[i]); } } // match against pattern for (int i = 0; i < c_expression.length; ++i) { Matcher m = c_pattern[i].matcher(stamp); if (m.matches()) { Calendar c = Calendar.getInstance(); TimeZone z = TimeZone.getDefault(); if (m.group(9) != null && m.group(9).length() > 0) { boolean utc = (Character.toUpperCase(m.group(9).charAt(0)) == 'Z'); if (utc) { z = TimeZone.getTimeZone("GMT+0"); } else { z = TimeZone.getTimeZone("GMT" + m.group(9)); } } c.setTimeZone(z); c.set(Calendar.YEAR, Integer.parseInt(m.group(1))); c.set(Calendar.MONTH, Integer.parseInt(m.group(2)) + (Calendar.JANUARY - 1)); c.set(Calendar.DAY_OF_MONTH, Integer.parseInt(m.group(3))); if (m.group(4).length() > 0) { c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(5))); c.set(Calendar.MINUTE, Integer.parseInt(m.group(6))); if (m.group(7) != null && m.group(7).length() > 0) { c.set(Calendar.SECOND, Integer.parseInt(m.group(7))); } if (m.group(8) != null && m.group(8).length() > 1) { String millis = m.group(8).substring(1); while (millis.length() < 3) { millis += "0"; } millis = millis.substring(0, 3); c.set(Calendar.MILLISECOND, Integer.parseInt(millis)); } } return c.getTime(); } } // not found return null; } /** * Ignores any internal date format, and tries to show a complete * date/timp stamp of the current time in extended ISO 8601 format. * UTC time (Zulu time) or a local timezone will be used. A sample for * UTC output is 2002-04-23T02:49:58Z A sample for local zone * (CDT) is 2002-04-22T21:49:58-05:00 * * @param zuluTime returns a UTC formatted stamp, if true. Otherwise * the time will be formatted according to the local zone. * @return an ISO 8601 formatted date and time representation for the * current time in extended format without millisecond resolution * @see #iso8601( boolean, boolean, boolean, Date ) */ public static String iso8601(boolean zuluTime) { return Currently.iso8601(zuluTime, true, false, new Date()); } /** * Ignores any internal date format, and tries to show a complete * date/timp stamp in extended ISO 8601 format. UTC time (Zulu time) * or a local timezone will be used.<p> * * <table border=1> * <tr><th>zone</th><th>format</th><th>fraction</td><th>example</th></tr> * <tr><td>local</td><td>basic</td><td>integral</td><td>20020523T140427-0500</td></tr> * <tr><td>UTC</td><td>basic</td><td>integral</td><td>20020523190427Z</td></tr> * <tr><td>local</td><td>extd.</td><td>integral</td><td>2002-05-23T14:04:27-05:00</td></tr> * <tr><td>UTC</td><td>extd.</td><td>integral</td><td>2002-05-23T19:04:27Z</td></tr> * <tr><td>local</td><td>basic</td><td>millis</td><td>20020523T140427.166-0500</td></tr> * <tr><td>UTC</td><td>basic</td><td>millis</td><td>20020523190427.166Z</td></tr> * <tr><td>local</td><td>extd.</td><td>millis</td><td>2002-05-23T14:04:27.166-05:00</td></tr> * <tr><td>UTC</td><td>extd.</td><td>millis</td><td>2002-05-23T19:04:27.166Z</td></tr> * </table><p> * * @param zuluTime returns a UTC formatted stamp, if true. Otherwise * the time will be formatted according to the local zone. Local time * should be prefixed with the 'T'. * @param extendedFormat will use the extended ISO 8601 format which * separates the different timestamp items. If false, the basic * format will be used. In UTC and basic format, the 'T' separator * will be omitted. * @param withMillis will put the millisecond extension into the timestamp. * If false, the time will be without millisecond fraction. The separator * is taken from {@link java.text.DecimalFormatSymbols#getMinusSign()}, * which usually is a period or a comma. * @param now is a time stamp as Date. * @return an ISO 8601 formatted date and time representation for * the given point in time. */ public static String iso8601(boolean zuluTime, boolean extendedFormat, boolean withMillis, Date now) { Calendar c = Calendar.getInstance(zuluTime ? TimeZone.getTimeZone("UTC") : TimeZone.getDefault()); c.setTime(now); // set up formattting options DecimalFormat nf2 = new DecimalFormat("##00"); DecimalFormat nf3 = new DecimalFormat("###000"); DecimalFormat nf4 = new DecimalFormat("####0000"); DecimalFormatSymbols dfs = nf2.getDecimalFormatSymbols(); // allocate result string buffer int size = extendedFormat ? (zuluTime ? 25 : 30) : (zuluTime ? 21 : 25); if (!withMillis) { size -= 4; } StringBuffer result = new StringBuffer(size); result.append(nf4.format(c.get(Calendar.YEAR))); if (extendedFormat) { result.append('-'); // position 5 } result.append(nf2.format(c.get(Calendar.MONTH) + 1)); if (extendedFormat) { result.append('-'); // position 8 } result.append(nf2.format(c.get(Calendar.DAY_OF_MONTH))); // generating UTC in basic format may leave out the 'T' separator if (extendedFormat || !zuluTime) { result.append('T'); // position 11 } result.append(nf2.format(c.get(Calendar.HOUR_OF_DAY))); if (extendedFormat) { result.append(':'); // position 14 } result.append(nf2.format(c.get(Calendar.MINUTE))); if (extendedFormat) { result.append(':'); // position 17 } result.append(nf2.format(c.get(Calendar.SECOND))); if (withMillis) { // Though there is no explicit spec which allows a complete // timestamp with milliseconds, it is implied through two // levels, sigh. 5.3.4.2 allows decimal fractions with // time-only stamps that have a timezone. The intro of 5.4.2 // allows 5.3.1.3. result.append(dfs.getDecimalSeparator()); // position 20 result.append(nf3.format(c.get(Calendar.MILLISECOND))); } if (zuluTime) { // this is easy result.append('Z'); } else { // time zone calculations int zone_offset = c.get(Calendar.ZONE_OFFSET) / 1000; int save_offset = c.get(Calendar.DST_OFFSET) / 1000; int diff = (zone_offset + save_offset) / 60; result.append(diff < 0 ? dfs.getMinusSign() : '+'); // position 24 if (diff < 0) { diff = Math.abs(diff); } result.append(nf2.format(diff / 60)); if (extendedFormat) { result.append(':'); } result.append(nf2.format(diff % 60)); } return result.toString(); } }