/* * 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.log4j.pattern; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; import java.text.SimpleDateFormat; import java.text.DateFormat; import java.text.FieldPosition; import java.text.ParsePosition; import java.util.Date; import java.util.TimeZone; /** * Convert and format the event's date in a StringBuffer. * * @author Ceki Gülcü */ public final class DatePatternConverter extends LoggingEventPatternConverter { /** * ABSOLUTE string literal. */ private static final String ABSOLUTE_FORMAT = "ABSOLUTE"; /** * SimpleTimePattern for ABSOLUTE. */ private static final String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS"; /** * DATE string literal. */ private static final String DATE_AND_TIME_FORMAT = "DATE"; /** * SimpleTimePattern for DATE. */ private static final String DATE_AND_TIME_PATTERN = "dd MMM yyyy HH:mm:ss,SSS"; /** * ISO8601 string literal. */ private static final String ISO8601_FORMAT = "ISO8601"; /** * SimpleTimePattern for ISO8601. */ private static final String ISO8601_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS"; /** * Date format. */ private final CachedDateFormat df; /** * This class wraps a DateFormat and forces the time zone to the * default time zone before each format and parse request. */ private static class DefaultZoneDateFormat extends DateFormat { /** * Serialization version ID. */ private static final long serialVersionUID = 1; /** * Wrapped instance of DateFormat. */ private final DateFormat dateFormat; /** * Construct new instance. * @param format format, may not be null. */ public DefaultZoneDateFormat(final DateFormat format) { dateFormat = format; } /** * @{inheritDoc} */ public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { dateFormat.setTimeZone(TimeZone.getDefault()); return dateFormat.format(date, toAppendTo, fieldPosition); } /** * @{inheritDoc} */ public Date parse(String source, ParsePosition pos) { dateFormat.setTimeZone(TimeZone.getDefault()); return dateFormat.parse(source, pos); } } /** * Private constructor. * @param options options, may be null. */ private DatePatternConverter(final String[] options) { super("Date", "date"); String patternOption; if ((options == null) || (options.length == 0)) { // the branch could be optimized, but here we are making explicit // that null values for patternOption are allowed. patternOption = null; } else { patternOption = options[0]; } String pattern; if ( (patternOption == null) || patternOption.equalsIgnoreCase(ISO8601_FORMAT)) { pattern = ISO8601_PATTERN; } else if (patternOption.equalsIgnoreCase(ABSOLUTE_FORMAT)) { pattern = ABSOLUTE_TIME_PATTERN; } else if (patternOption.equalsIgnoreCase(DATE_AND_TIME_FORMAT)) { pattern = DATE_AND_TIME_PATTERN; } else { pattern = patternOption; } int maximumCacheValidity = 1000; DateFormat simpleFormat = null; try { simpleFormat = new SimpleDateFormat(pattern); maximumCacheValidity = CachedDateFormat.getMaximumCacheValidity(pattern); } catch (IllegalArgumentException e) { LogLog.warn( "Could not instantiate SimpleDateFormat with pattern " + patternOption, e); // default to the ISO8601 format simpleFormat = new SimpleDateFormat(ISO8601_PATTERN); } // if the option list contains a TZ option, then set it. if ((options != null) && (options.length > 1)) { TimeZone tz = TimeZone.getTimeZone((String) options[1]); simpleFormat.setTimeZone(tz); } else { simpleFormat = new DefaultZoneDateFormat(simpleFormat); } df = new CachedDateFormat(simpleFormat, maximumCacheValidity); } /** * Obtains an instance of pattern converter. * @param options options, may be null. * @return instance of pattern converter. */ public static DatePatternConverter newInstance( final String[] options) { return new DatePatternConverter(options); } /** * {@inheritDoc} */ public void format(final LoggingEvent event, final StringBuffer output) { synchronized(this) { df.format(event.timeStamp, output); } } /** * {@inheritDoc} */ public void format(final Object obj, final StringBuffer output) { if (obj instanceof Date) { format((Date) obj, output); } super.format(obj, output); } /** * Append formatted date to string buffer. * @param date date * @param toAppendTo buffer to which formatted date is appended. */ public void format(final Date date, final StringBuffer toAppendTo) { synchronized(this) { df.format(date.getTime(), toAppendTo); } } }