/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ package org.apache.catalina.util; import java.util.Date; import java.text.DateFormat; import java.text.FieldPosition; import java.text.ParsePosition; import java.text.SimpleDateFormat; /** * Fast date formatter that caches recently formatted date information * and uses it to avoid too-frequent calls to the underlying * formatter. Note: breaks fieldPosition param of format(Date, * StringBuffer, FieldPosition). If you care about the field * position, call the underlying DateFormat directly. * * @author Stan Bailes * @author Alex Chaffee **/ public class FastDateFormat extends DateFormat { DateFormat df; long lastSec = -1; StringBuffer sb = new StringBuffer(); FieldPosition fp = new FieldPosition(DateFormat.MILLISECOND_FIELD); public FastDateFormat(DateFormat df) { this.df = df; } public Date parse(String text, ParsePosition pos) { return df.parse(text, pos); } /** * Note: breaks functionality of fieldPosition param. Also: * there's a bug in SimpleDateFormat with "S" and "SS", use "SSS" * instead if you want a msec field. **/ public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { long dt = date.getTime(); long ds = dt / 1000; if (ds != lastSec) { sb.setLength(0); df.format(date, sb, fp); lastSec = ds; } else { // munge current msec into existing string int ms = (int)(dt % 1000); int pos = fp.getEndIndex(); int begin = fp.getBeginIndex(); if (pos > 0) { if (pos > begin) sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); ms /= 10; if (pos > begin) sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); ms /= 10; if (pos > begin) sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); } } toAppendTo.append(sb.toString()); return toAppendTo; } public static void main(String[] args) { String format = "yyyy-MM-dd HH:mm:ss.SSS"; if (args.length > 0) format = args[0]; SimpleDateFormat sdf = new SimpleDateFormat(format); FastDateFormat fdf = new FastDateFormat(sdf); Date d = new Date(); d.setTime(1); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); d.setTime(20); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); d.setTime(500); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); d.setTime(543); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); d.setTime(999); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); d.setTime(1050); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); d.setTime(2543); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); d.setTime(12345); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); d.setTime(12340); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); final int reps = 100000; { long start = System.currentTimeMillis(); for (int i = 0; i < reps; i++) { d.setTime(System.currentTimeMillis()); fdf.format(d); } long elap = System.currentTimeMillis() - start; System.out.println("fast: " + elap + " elapsed"); System.out.println(fdf.format(d)); } { long start = System.currentTimeMillis(); for (int i = 0; i < reps; i++) { d.setTime(System.currentTimeMillis()); sdf.format(d); } long elap = System.currentTimeMillis() - start; System.out.println("slow: " + elap + " elapsed"); System.out.println(sdf.format(d)); } } }