Mega Code Archive

 
Categories / Java / Development Class
 

Date Format Cache

//  // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // 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.DateFormatSymbols; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; /* ------------------------------------------------------------ */ /**  * Date Format Cache. Computes String representations of Dates and caches the  * results so that subsequent requests within the same minute will be fast.  *   * Only format strings that contain either "ss" or "ss.SSS" are handled.  *   * The timezone of the date may be included as an ID with the "zzz" format  * string or as an offset with the "ZZZ" format string.  *   * If consecutive calls are frequently very different, then this may be a little  * slower than a normal DateFormat.  *   * @author Kent Johnson <KJohnson@transparent.com>  * @author Greg Wilkins (gregw)  */ public class DateCache {   private static long __hitWindow = 60 * 60;   private static long __MaxMisses = 10;   private String _formatString;   private String _tzFormatString;   private SimpleDateFormat _tzFormat;   private String _minFormatString;   private SimpleDateFormat _minFormat;   private String _secFormatString;   private String _secFormatString0;   private String _secFormatString1;   private boolean _millis = false;   private long _misses = 0;   private long _lastMinutes = -1;   private long _lastSeconds = -1;   private String _lastResult = null;   private Locale _locale = null;   private DateFormatSymbols _dfs = null;   /* ------------------------------------------------------------ */   /**    * Constructor. Make a DateCache that will use a default format. The default    * format generates the same results as Date.toString().    */   public DateCache() {     this("EEE MMM dd HH:mm:ss zzz yyyy");     getFormat().setTimeZone(TimeZone.getDefault());   }   /* ------------------------------------------------------------ */   /**    * Constructor. Make a DateCache that will use the given format    */   public DateCache(String format) {     _formatString = format;     setTimeZone(TimeZone.getDefault());   }   /* ------------------------------------------------------------ */   public DateCache(String format, Locale l) {     _formatString = format;     _locale = l;     setTimeZone(TimeZone.getDefault());   }   /* ------------------------------------------------------------ */   public DateCache(String format, DateFormatSymbols s) {     _formatString = format;     _dfs = s;     setTimeZone(TimeZone.getDefault());   }   /* ------------------------------------------------------------ */   /**    * Set the timezone.    *     * @param tz    *          TimeZone    */   public void setTimeZone(TimeZone tz) {     setTzFormatString(tz);     if (_locale != null) {       _tzFormat = new SimpleDateFormat(_tzFormatString, _locale);       _minFormat = new SimpleDateFormat(_minFormatString, _locale);     } else if (_dfs != null) {       _tzFormat = new SimpleDateFormat(_tzFormatString, _dfs);       _minFormat = new SimpleDateFormat(_minFormatString, _dfs);     } else {       _tzFormat = new SimpleDateFormat(_tzFormatString);       _minFormat = new SimpleDateFormat(_minFormatString);     }     _tzFormat.setTimeZone(tz);     _minFormat.setTimeZone(tz);     _lastSeconds = -1;     _lastMinutes = -1;   }   /* ------------------------------------------------------------ */   public TimeZone getTimeZone() {     return _tzFormat.getTimeZone();   }   /* ------------------------------------------------------------ */   /**    * Set the timezone.    *     * @param timeZoneId    *          TimeZoneId the ID of the zone as used by TimeZone.getTimeZone(id)    */   public void setTimeZoneID(String timeZoneId) {     setTimeZone(TimeZone.getTimeZone(timeZoneId));   }   /* ------------------------------------------------------------ */   private void setTzFormatString(final TimeZone tz) {     int zIndex = _formatString.indexOf("ZZZ");     if (zIndex >= 0) {       String ss1 = _formatString.substring(0, zIndex);       String ss2 = _formatString.substring(zIndex + 3);       int tzOffset = tz.getRawOffset();       StringBuffer sb = new StringBuffer(_formatString.length() + 10);       sb.append(ss1);       sb.append("'");       if (tzOffset >= 0)         sb.append('+');       else {         tzOffset = -tzOffset;         sb.append('-');       }       int raw = tzOffset / (1000 * 60); // Convert to seconds       int hr = raw / 60;       int min = raw % 60;       if (hr < 10)         sb.append('0');       sb.append(hr);       if (min < 10)         sb.append('0');       sb.append(min);       sb.append('\'');       sb.append(ss2);       _tzFormatString = sb.toString();     } else       _tzFormatString = _formatString;     setMinFormatString();   }   /* ------------------------------------------------------------ */   private void setMinFormatString() {     int i = _tzFormatString.indexOf("ss.SSS");     int l = 6;     if (i >= 0)       _millis = true;     else {       i = _tzFormatString.indexOf("ss");       l = 2;     }     // Build a formatter that formats a second format string     // Have to replace @ with ' later due to bug in SimpleDateFormat     String ss1 = _tzFormatString.substring(0, i);     String ss2 = _tzFormatString.substring(i + l);     _minFormatString = ss1 + (_millis ? "'ss.SSS'" : "'ss'") + ss2;   }   /* ------------------------------------------------------------ */   /**    * Format a date according to our stored formatter.    *     * @param inDate    * @return Formatted date    */   public synchronized String format(Date inDate) {     return format(inDate.getTime());   }   /* ------------------------------------------------------------ */   /**    * Format a date according to our stored formatter.    *     * @param inDate    * @return Formatted date    */   public synchronized String format(long inDate) {     long seconds = inDate / 1000;     // Is it not suitable to cache?     if (seconds < _lastSeconds || _lastSeconds > 0 && seconds > _lastSeconds + __hitWindow) {       // It's a cache miss       _misses++;       if (_misses < __MaxMisses) {         Date d = new Date(inDate);         return _tzFormat.format(d);       }     } else if (_misses > 0)       _misses--;     // Check if we are in the same second     // and don't care about millis     if (_lastSeconds == seconds && !_millis)       return _lastResult;     Date d = new Date(inDate);     // Check if we need a new format string     long minutes = seconds / 60;     if (_lastMinutes != minutes) {       _lastMinutes = minutes;       _secFormatString = _minFormat.format(d);       int i;       int l;       if (_millis) {         i = _secFormatString.indexOf("ss.SSS");         l = 6;       } else {         i = _secFormatString.indexOf("ss");         l = 2;       }       _secFormatString0 = _secFormatString.substring(0, i);       _secFormatString1 = _secFormatString.substring(i + l);     }     // Always format if we get here     _lastSeconds = seconds;     StringBuffer sb = new StringBuffer(_secFormatString.length());     synchronized (sb) {       sb.append(_secFormatString0);       int s = (int) (seconds % 60);       if (s < 10)         sb.append('0');       sb.append(s);       if (_millis) {         long millis = inDate % 1000;         if (millis < 10)           sb.append(".00");         else if (millis < 100)           sb.append(".0");         else           sb.append('.');         sb.append(millis);       }       sb.append(_secFormatString1);       _lastResult = sb.toString();     }     return _lastResult;   }   /* ------------------------------------------------------------ */   /**    * Format to string buffer.    *     * @param inDate    *          Date the format    * @param buffer    *          StringBuffer    */   public void format(long inDate, StringBuffer buffer) {     buffer.append(format(inDate));   }   /* ------------------------------------------------------------ */   /**    * Get the format.    */   public SimpleDateFormat getFormat() {     return _minFormat;   }   /* ------------------------------------------------------------ */   public String getFormatString() {     return _formatString;   }   /* ------------------------------------------------------------ */   public String now() {     return format(System.currentTimeMillis());   } }