001: /*
002: * Strftime.java
003: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/util/Strftime.java,v 1.2 2002/05/11 05:43:56 billbarker Exp $
004: * $Revision: 1.2 $
005: * $Date: 2002/05/11 05:43:56 $
006: *
007: * ====================================================================
008: *
009: * The Apache Software License, Version 1.1
010: *
011: * Copyright (c) 1999 The Apache Software Foundation. All rights
012: * reserved.
013: *
014: * Redistribution and use in source and binary forms, with or without
015: * modification, are permitted provided that the following conditions
016: * are met:
017: *
018: * 1. Redistributions of source code must retain the above copyright
019: * notice, this list of conditions and the following disclaimer.
020: *
021: * 2. Redistributions in binary form must reproduce the above copyright
022: * notice, this list of conditions and the following disclaimer in
023: * the documentation and/or other materials provided with the
024: * distribution.
025: *
026: * 3. The end-user documentation included with the redistribution, if
027: * any, must include the following acknowlegement:
028: * "This product includes software developed by the
029: * Apache Software Foundation (http://www.apache.org/)."
030: * Alternately, this acknowlegement may appear in the software itself,
031: * if and wherever such third-party acknowlegements normally appear.
032: *
033: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
034: * Foundation" must not be used to endorse or promote products derived
035: * from this software without prior written permission. For written
036: * permission, please contact apache@apache.org.
037: *
038: * 5. Products derived from this software may not be called "Apache"
039: * nor may "Apache" appear in their names without prior written
040: * permission of the Apache Group.
041: *
042: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
043: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
044: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
045: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
046: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
047: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
048: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
049: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
050: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
051: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
052: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
053: * SUCH DAMAGE.
054: * ====================================================================
055: *
056: * This software consists of voluntary contributions made by many
057: * individuals on behalf of the Apache Software Foundation. For more
058: * information on the Apache Software Foundation, please see
059: * <http://www.apache.org/>.
060: *
061: * [Additional notices, if required by prior licensing conditions]
062: *
063: */
064:
065: package org.apache.catalina.util;
066:
067: import java.text.SimpleDateFormat;
068: import java.util.Properties;
069: import java.util.Date;
070: import java.util.Locale;
071: import java.util.TimeZone;
072:
073: /**
074: * Converts dates to strings using the same format specifiers as strftime
075: *
076: * Note: This does not mimic strftime perfectly. Certain strftime commands,
077: * are not supported, and will convert as if they were literals.
078: *
079: * Certain complicated commands, like those dealing with the week of the year
080: * probably don't have exactly the same behavior as strftime.
081: *
082: * These limitations are due to use SimpleDateTime. If the conversion was done
083: * manually, all these limitations could be eliminated.
084: *
085: * The interface looks like a subset of DateFormat. Maybe someday someone will make this class
086: * extend DateFormat.
087: *
088: * @author Bip Thelin
089: * @author Dan Sandberg
090: * @version $Revision: 1.2 $, $Date: 2002/05/11 05:43:56 $
091: */
092: public class Strftime {
093: protected static Properties translate;
094: protected SimpleDateFormat simpleDateFormat;
095:
096: /**
097: * Initialize our pattern translation
098: */
099: static {
100: translate = new Properties();
101: translate.put("a", "EEE");
102: translate.put("A", "EEEE");
103: translate.put("b", "MMM");
104: translate.put("B", "MMMM");
105: translate.put("c", "EEE MMM d HH:mm:ss yyyy");
106:
107: //There's no way to specify the century in SimpleDateFormat. We don't want to hard-code
108: //20 since this could be wrong for the pre-2000 files.
109: //translate.put("C", "20");
110: translate.put("d", "dd");
111: translate.put("D", "MM/dd/yy");
112: translate.put("e", "dd"); //will show as '03' instead of ' 3'
113: translate.put("F", "yyyy-MM-dd");
114: translate.put("g", "yy");
115: translate.put("G", "yyyy");
116: translate.put("H", "HH");
117: translate.put("h", "MMM");
118: translate.put("I", "hh");
119: translate.put("j", "DDD");
120: translate.put("k", "HH"); //will show as '07' instead of ' 7'
121: translate.put("l", "hh"); //will show as '07' instead of ' 7'
122: translate.put("m", "MM");
123: translate.put("M", "mm");
124: translate.put("n", "\n");
125: translate.put("p", "a");
126: translate.put("P", "a"); //will show as pm instead of PM
127: translate.put("r", "hh:mm:ss a");
128: translate.put("R", "HH:mm");
129: //There's no way to specify this with SimpleDateFormat
130: //translate.put("s","seconds since ecpoch");
131: translate.put("S", "ss");
132: translate.put("t", "\t");
133: translate.put("T", "HH:mm:ss");
134: //There's no way to specify this with SimpleDateFormat
135: //translate.put("u","day of week ( 1-7 )");
136:
137: //There's no way to specify this with SimpleDateFormat
138: //translate.put("U","week in year with first sunday as first day...");
139:
140: translate.put("V", "ww"); //I'm not sure this is always exactly the same
141:
142: //There's no way to specify this with SimpleDateFormat
143: //translate.put("W","week in year with first monday as first day...");
144:
145: //There's no way to specify this with SimpleDateFormat
146: //translate.put("w","E");
147: translate.put("X", "HH:mm:ss");
148: translate.put("x", "MM/dd/yy");
149: translate.put("y", "yy");
150: translate.put("Y", "yyyy");
151: translate.put("Z", "z");
152: translate.put("z", "Z");
153: translate.put("%", "%");
154: }
155:
156: /**
157: * Create an instance of this date formatting class
158: *
159: * @see #Strftime( String, Locale )
160: */
161: public Strftime(String origFormat) {
162: String convertedFormat = convertDateFormat(origFormat);
163: simpleDateFormat = new SimpleDateFormat(convertedFormat);
164: }
165:
166: /**
167: * Create an instance of this date formatting class
168: *
169: * @param origFormat the strftime-style formatting string
170: * @param the locale to use for locale-specific conversions
171: */
172: public Strftime(String origFormat, Locale locale) {
173: String convertedFormat = convertDateFormat(origFormat);
174: simpleDateFormat = new SimpleDateFormat(convertedFormat, locale);
175: }
176:
177: /**
178: * Format the date according to the strftime-style string given in the constructor.
179: *
180: * @param date the date to format
181: * @return the formatted date
182: */
183: public String format(Date date) {
184: return simpleDateFormat.format(date);
185: }
186:
187: /**
188: * Get the timezone used for formatting conversions
189: *
190: * @return the timezone
191: */
192: public TimeZone getTimeZone() {
193: return simpleDateFormat.getTimeZone();
194: }
195:
196: /**
197: * Change the timezone used to format dates
198: *
199: * @see java.util.TimeZone#setTimeZone
200: */
201: public void setTimeZone(TimeZone timeZone) {
202: simpleDateFormat.setTimeZone(timeZone);
203: }
204:
205: /**
206: * Search the provided pattern and get the C standard
207: * Date/Time formatting rules and convert them to the
208: * Java equivalent.
209: *
210: * @param pattern The pattern to search
211: * @return The modified pattern
212: */
213: protected String convertDateFormat(String pattern) {
214: boolean inside = false;
215: boolean mark = false;
216: boolean modifiedCommand = false;
217:
218: StringBuffer buf = new StringBuffer();
219:
220: for (int i = 0; i < pattern.length(); i++) {
221: char c = pattern.charAt(i);
222:
223: if (c == '%' && !mark) {
224: mark = true;
225: } else {
226: if (mark) {
227: if (modifiedCommand) {
228: //don't do anything--we just wanted to skip a char
229: modifiedCommand = false;
230: mark = false;
231: } else {
232: inside = translateCommand(buf, pattern, i,
233: inside);
234: //It's a modifier code
235: if (c == 'O' || c == 'E') {
236: modifiedCommand = true;
237: } else {
238: mark = false;
239: }
240: }
241: } else {
242: if (!inside && c != ' ') {
243: //We start a literal, which we need to quote
244: buf.append("'");
245: inside = true;
246: }
247:
248: buf.append(c);
249: }
250: }
251: }
252:
253: if (buf.length() > 0) {
254: char lastChar = buf.charAt(buf.length() - 1);
255:
256: if (lastChar != '\'' && inside) {
257: buf.append('\'');
258: }
259: }
260: return buf.toString();
261: }
262:
263: protected String quote(String str, boolean insideQuotes) {
264: String retVal = str;
265: if (!insideQuotes) {
266: retVal = '\'' + retVal + '\'';
267: }
268: return retVal;
269: }
270:
271: /**
272: * try to get the Java Date/Time formating associated with
273: * the C standard provided
274: *
275: * @param c The C equivalent to translate
276: * @return The Java formatting rule to use
277: */
278: protected boolean translateCommand(StringBuffer buf,
279: String pattern, int index, boolean oldInside) {
280: char firstChar = pattern.charAt(index);
281: boolean newInside = oldInside;
282:
283: //O and E are modifiers, they mean to present an alternative representation of the next char
284: //we just handle the next char as if the O or E wasn't there
285: if (firstChar == 'O' || firstChar == 'E') {
286: if (index + 1 < pattern.length()) {
287: newInside = translateCommand(buf, pattern, index + 1,
288: oldInside);
289: } else {
290: buf.append(quote("%" + firstChar, oldInside));
291: }
292: } else {
293: String command = translate.getProperty(String
294: .valueOf(firstChar));
295:
296: //If we don't find a format, treat it as a literal--That's what apache does
297: if (command == null) {
298: buf.append(quote("%" + firstChar, oldInside));
299: } else {
300: //If we were inside quotes, close the quotes
301: if (oldInside) {
302: buf.append('\'');
303: }
304: buf.append(command);
305: newInside = false;
306: }
307: }
308: return newInside;
309: }
310: }
|