]> WPIA git - gigi.git/blobdiff - lib/jetty/org/eclipse/jetty/util/DateCache.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / util / DateCache.java
diff --git a/lib/jetty/org/eclipse/jetty/util/DateCache.java b/lib/jetty/org/eclipse/jetty/util/DateCache.java
new file mode 100644 (file)
index 0000000..31097ee
--- /dev/null
@@ -0,0 +1,268 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+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 second
+ * will be fast.
+ *
+ * Only format strings that contain either "ss".  Sub second formatting is 
+ * not 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.
+ *
+ */
+
+public class DateCache
+{
+    public static final String DEFAULT_FORMAT="EEE MMM dd HH:mm:ss zzz yyyy";
+    
+    private final String _formatString;
+    private final String _tzFormatString;
+    private final SimpleDateFormat _tzFormat;
+    private final Locale _locale ;
+    
+    private volatile Tick _tick;
+
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    public static class Tick
+    {
+        final long _seconds;
+        final String _string;
+        public Tick(long seconds, String string)
+        {
+            _seconds = seconds;
+            _string = string;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Constructor.
+     * Make a DateCache that will use a default format. The default format
+     * generates the same results as Date.toString().
+     */
+    public DateCache()
+    {
+        this(DEFAULT_FORMAT);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Constructor.
+     * Make a DateCache that will use the given format
+     */
+    public DateCache(String format)
+    {
+        this(format,null,TimeZone.getDefault());
+    }
+    
+    /* ------------------------------------------------------------ */
+    public DateCache(String format,Locale l)
+    {
+        this(format,l,TimeZone.getDefault());
+    }
+
+    /* ------------------------------------------------------------ */
+    public DateCache(String format,Locale l,String tz)
+    {
+        this(format,l,TimeZone.getTimeZone(tz));
+    }
+    
+    /* ------------------------------------------------------------ */
+    public DateCache(String format,Locale l,TimeZone tz)
+    {
+        _formatString=format;
+        _locale = l;
+        
+
+        int zIndex = _formatString.indexOf( "ZZZ" );
+        if( zIndex >= 0 )
+        {
+            String ss1 = _formatString.substring( 0, zIndex );
+            String ss2 = _formatString.substring( zIndex+3 );
+            int tzOffset = tz.getRawOffset();
+            
+            StringBuilder sb = new StringBuilder(_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;
+   
+        if( _locale != null ) 
+        {
+            _tzFormat=new SimpleDateFormat(_tzFormatString,_locale);
+        }
+        else 
+        {
+            _tzFormat=new SimpleDateFormat(_tzFormatString);
+        }
+        _tzFormat.setTimeZone(tz);
+        
+        _tick=null;
+    }
+    
+
+    /* ------------------------------------------------------------ */
+    public TimeZone getTimeZone()
+    {
+        return _tzFormat.getTimeZone();
+    }
+
+
+    /* ------------------------------------------------------------ */
+    /** Format a date according to our stored formatter.
+     * @param inDate 
+     * @return Formatted date
+     */
+    public String format(Date inDate)
+    {
+        long seconds = inDate.getTime() / 1000;
+
+        Tick tick=_tick;
+        
+        // Is this the cached time
+        if (tick==null || seconds!=tick._seconds)
+        {
+            // It's a cache miss
+            synchronized (this)
+            {
+                return _tzFormat.format(inDate);
+            }
+        }
+        
+        return tick._string;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Format a date according to our stored formatter.
+     * If it happens to be in the same second as the last formatNow
+     * call, then the format is reused.
+     * @param inDate 
+     * @return Formatted date
+     */
+    public String format(long inDate)
+    {
+        long seconds = inDate / 1000;
+
+        Tick tick=_tick;
+        
+        // Is this the cached time
+        if (tick==null || seconds!=tick._seconds)
+        {
+            // It's a cache miss
+            Date d = new Date(inDate);
+            synchronized (this)
+            {
+                return _tzFormat.format(d);
+            }
+        }
+        
+        return tick._string;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Format a date according to our stored formatter.
+     * The passed time is expected to be close to the current time, so it is 
+     * compared to the last value passed and if it is within the same second,
+     * the format is reused.  Otherwise a new cached format is created.
+     * @param now 
+     * @return Formatted date
+     */
+    public String formatNow(long now)
+    {
+        long seconds = now / 1000;
+
+        Tick tick=_tick;
+        
+        // Is this the cached time
+        if (tick!=null && tick._seconds==seconds)
+            return tick._string;
+        return formatTick(now)._string;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public String now()
+    {
+        return formatNow(System.currentTimeMillis());
+    }
+    
+    /* ------------------------------------------------------------ */
+    public Tick tick()
+    {
+        return formatTick(System.currentTimeMillis());
+    }
+    
+    /* ------------------------------------------------------------ */
+    protected Tick formatTick(long now)
+    {
+        long seconds = now / 1000;
+
+        // Synchronize to protect _tzFormat
+        synchronized (this)
+        {
+            // recheck the tick, to save multiple formats
+            if (_tick==null || _tick._seconds!=seconds)
+            {
+                String s= _tzFormat.format(new Date(now));
+                return _tick=new Tick(seconds,s);
+            }
+            return _tick;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getFormatString()
+    {
+        return _formatString;
+    }    
+}