View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.util;
15  
16  import java.text.DateFormatSymbols;
17  import java.text.SimpleDateFormat;
18  import java.util.Date;
19  import java.util.Locale;
20  import java.util.TimeZone;
21  
22  /* ------------------------------------------------------------ */
23  /**  Date Format Cache.
24   * Computes String representations of Dates and caches
25   * the results so that subsequent requests within the same minute
26   * will be fast.
27   *
28   * Only format strings that contain either "ss" or "ss.SSS" are
29   * handled.
30   *
31   * The timezone of the date may be included as an ID with the "zzz"
32   * format string or as an offset with the "ZZZ" format string.
33   *
34   * If consecutive calls are frequently very different, then this
35   * may be a little slower than a normal DateFormat.
36   *
37   * 
38   * 
39   */
40  
41  public class DateCache  
42  {
43      public static String DEFAULT_FORMAT="EEE MMM dd HH:mm:ss zzz yyyy";
44      private static long __hitWindow=60*60;
45      
46      private String _formatString;
47      private String _tzFormatString;
48      private SimpleDateFormat _tzFormat;
49      
50      private String _minFormatString;
51      private SimpleDateFormat _minFormat;
52  
53      private String _secFormatString;
54      private String _secFormatString0;
55      private String _secFormatString1;
56  
57      private long _lastMinutes = -1;
58      private long _lastSeconds = -1;
59      private int _lastMs = -1;
60      private String _lastResult = null;
61  
62      private Locale _locale	= null;
63      private DateFormatSymbols	_dfs	= null;
64  
65      /* ------------------------------------------------------------ */
66      /** Constructor.
67       * Make a DateCache that will use a default format. The default format
68       * generates the same results as Date.toString().
69       */
70      public DateCache()
71      {
72          this(DEFAULT_FORMAT);
73          getFormat().setTimeZone(TimeZone.getDefault());
74      }
75      
76      /* ------------------------------------------------------------ */
77      /** Constructor.
78       * Make a DateCache that will use the given format
79       */
80      public DateCache(String format)
81      {
82          _formatString=format;
83          setTimeZone(TimeZone.getDefault());
84          
85      }
86      
87      /* ------------------------------------------------------------ */
88      public DateCache(String format,Locale l)
89      {
90          _formatString=format;
91          _locale = l;
92          setTimeZone(TimeZone.getDefault());       
93      }
94      
95      /* ------------------------------------------------------------ */
96      public DateCache(String format,DateFormatSymbols s)
97      {
98          _formatString=format;
99          _dfs = s;
100         setTimeZone(TimeZone.getDefault());
101     }
102 
103     /* ------------------------------------------------------------ */
104     /** Set the timezone.
105      * @param tz TimeZone
106      */
107     public void setTimeZone(TimeZone tz)
108     {
109         setTzFormatString(tz);        
110         if( _locale != null ) 
111         {
112             _tzFormat=new SimpleDateFormat(_tzFormatString,_locale);
113             _minFormat=new SimpleDateFormat(_minFormatString,_locale);
114         }
115         else if( _dfs != null ) 
116         {
117             _tzFormat=new SimpleDateFormat(_tzFormatString,_dfs);
118             _minFormat=new SimpleDateFormat(_minFormatString,_dfs);
119         }
120         else 
121         {
122             _tzFormat=new SimpleDateFormat(_tzFormatString);
123             _minFormat=new SimpleDateFormat(_minFormatString);
124         }
125         _tzFormat.setTimeZone(tz);
126         _minFormat.setTimeZone(tz);
127         _lastSeconds=-1;
128         _lastMinutes=-1;        
129     }
130 
131     /* ------------------------------------------------------------ */
132     public TimeZone getTimeZone()
133     {
134         return _tzFormat.getTimeZone();
135     }
136     
137     /* ------------------------------------------------------------ */
138     /** Set the timezone.
139      * @param timeZoneId TimeZoneId the ID of the zone as used by
140      * TimeZone.getTimeZone(id)
141      */
142     public void setTimeZoneID(String timeZoneId)
143     {
144         setTimeZone(TimeZone.getTimeZone(timeZoneId));
145     }
146     
147     /* ------------------------------------------------------------ */
148     private void setTzFormatString(final  TimeZone tz )
149     {
150         int zIndex = _formatString.indexOf( "ZZZ" );
151         if( zIndex >= 0 )
152         {
153             String ss1 = _formatString.substring( 0, zIndex );
154             String ss2 = _formatString.substring( zIndex+3 );
155             int tzOffset = tz.getRawOffset();
156             
157             StringBuilder sb = new StringBuilder(_formatString.length()+10);
158             sb.append(ss1);
159             sb.append("'");
160             if( tzOffset >= 0 )
161                 sb.append( '+' );
162             else
163             {
164                 tzOffset = -tzOffset;
165                 sb.append( '-' );
166             }
167             
168             int raw = tzOffset / (1000*60);		// Convert to seconds
169             int hr = raw / 60;
170             int min = raw % 60;
171             
172             if( hr < 10 )
173                 sb.append( '0' );
174             sb.append( hr );
175             if( min < 10 )
176                 sb.append( '0' );
177             sb.append( min );
178             sb.append( '\'' );
179             
180             sb.append(ss2);
181             _tzFormatString=sb.toString();            
182         }
183         else
184             _tzFormatString=_formatString;
185         setMinFormatString();
186     }
187 
188     
189     /* ------------------------------------------------------------ */
190     private void setMinFormatString()
191     {
192         int i = _tzFormatString.indexOf("ss.SSS");
193         int l = 6;
194         if (i>=0)
195             throw new IllegalStateException("ms not supported");
196         i = _tzFormatString.indexOf("ss");
197         l=2;
198         
199         // Build a formatter that formats a second format string
200         String ss1=_tzFormatString.substring(0,i);
201         String ss2=_tzFormatString.substring(i+l);
202         _minFormatString =ss1+"'ss'"+ss2;
203     }
204 
205     /* ------------------------------------------------------------ */
206     /** Format a date according to our stored formatter.
207      * @param inDate 
208      * @return Formatted date
209      */
210     public synchronized String format(Date inDate)
211     {
212         return format(inDate.getTime());
213     }
214     
215     /* ------------------------------------------------------------ */
216     /** Format a date according to our stored formatter.
217      * @param inDate 
218      * @return Formatted date
219      */
220     public synchronized String format(long inDate)
221     {
222         long seconds = inDate / 1000;
223 
224         // Is it not suitable to cache?
225         if (seconds<_lastSeconds ||
226             _lastSeconds>0 && seconds>_lastSeconds+__hitWindow)
227         {
228             // It's a cache miss
229             Date d = new Date(inDate);
230             return _tzFormat.format(d);
231             
232         }
233                                           
234         // Check if we are in the same second
235         // and don't care about millis
236         if (_lastSeconds==seconds )
237             return _lastResult;
238 
239         Date d = new Date(inDate);
240         
241         // Check if we need a new format string
242         long minutes = seconds/60;
243         if (_lastMinutes != minutes)
244         {
245             _lastMinutes = minutes;
246             _secFormatString=_minFormat.format(d);
247 
248             int i=_secFormatString.indexOf("ss");
249             int l=2;
250             _secFormatString0=_secFormatString.substring(0,i);
251             _secFormatString1=_secFormatString.substring(i+l);
252         }
253 
254         // Always format if we get here
255         _lastSeconds = seconds;
256         StringBuilder sb=new StringBuilder(_secFormatString.length());
257         sb.append(_secFormatString0);
258         int s=(int)(seconds%60);
259         if (s<10)
260             sb.append('0');
261         sb.append(s);
262         sb.append(_secFormatString1);
263         _lastResult=sb.toString();
264 
265                 
266         return _lastResult;
267     }
268 
269     /* ------------------------------------------------------------ */
270     /** Format to string buffer. 
271      * @param inDate Date the format
272      * @param buffer StringBuilder
273      */
274     public void format(long inDate, StringBuilder buffer)
275     {
276         buffer.append(format(inDate));
277     }
278     
279     /* ------------------------------------------------------------ */
280     /** Get the format.
281      */
282     public SimpleDateFormat getFormat()
283     {
284         return _minFormat;
285     }
286 
287     /* ------------------------------------------------------------ */
288     public String getFormatString()
289     {
290         return _formatString;
291     }    
292 
293     /* ------------------------------------------------------------ */
294     public String now()
295     {
296         long now=System.currentTimeMillis();
297         _lastMs=(int)(now%1000);
298         return format(now);
299     }
300 
301     /* ------------------------------------------------------------ */
302     public int lastMs()
303     {
304         return _lastMs;
305     }
306 }