001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   License, or (at your option) any later version.
009
010   This library is distributed in the hope that it will be useful,
011   but WITHOUT ANY WARRANTY; without even the implied warranty of
012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: DateFormatter.java,v $
023   Revision 1.5  2004/05/05 22:47:37  markl
024   comment block updates
025
026   Revision 1.4  2003/01/19 09:34:27  markl
027   Javadoc & comment header updates.
028
029   Revision 1.3  2001/03/12 02:18:28  markl
030   Source code cleanup.
031
032   Revision 1.2  1999/01/10 03:37:18  markl
033   added GPL header & RCS tag
034   ----------------------------------------------------------------------------
035*/
036
037package kiwi.text;
038
039import java.text.*;
040import java.util.*;
041
042/** This class represents a high-level date parser/formatter that is almost
043  * fully format-string-compatible with the UNIX <b>strftime(3)</b> function.
044  * Date formats are specified by formatting directives; these directives are
045  * enumerated in the table below:
046  * <p>
047  * <center><table border=1 cellspacing=0 cellpadding=2>
048  * <tr><th>Directive</th><th align=left>Meaning</th></tr>
049  * <tr><td>%a</td>     <td>Abbreviated weekday name (3 characters).</td></tr>
050  * <tr><td>%A</td>     <td>Full weekday name.</td></tr>
051  * <tr><td>%b</td>     <td>Abbreviated month name (3 characters).</td></tr>
052  * <tr><td>%B</td>     <td>Full month name.</td></tr>
053  * <tr><td>%d</td>     <td>Day of month (01-31).</td></tr>
054  * <tr><td>%e</td>     <td>Day of month (no leading zero).</td></tr>
055  * <tr><td>%H</td>     <td>24-hour clock hour (00-23).</td></tr>
056  * <tr><td>%I</td>     <td>12-hour clock hour (01-12).</td></tr>
057  * <tr><td>%j</td>     <td>Day in year (001-366).</td></tr>
058  * <tr><td>%m</td>     <td>Month in year (01-12).</td></tr>
059  * <tr><td>%M</td>     <td>Minutes (00-59).</td></tr>
060  * <tr><td>%N</td>     <td>Era name.</td></tr>
061  * <tr><td>%p</td>     <td>AM/PM character.</td></tr>
062  * <tr><td>%r</td>     <td>Equivalent to %I:%M:%S %p.</td></tr>
063  * <tr><td>%R</td>     <td>Equivalent to %H:%M.</td></tr>
064  * <tr><td>%s</td>     <td>Milliseconds (000-999).</td></tr>
065  * <tr><td>%S</td>     <td>Seconds (00-59).</td></tr>
066  * <tr><td>%t</td>     <td>Tab character.</td></tr>
067  * <tr><td>%T</td>     <td>Equivalent to %H:%M%:S.</td></tr>
068  * <tr><td>%u</td>     <td>Equivalent to %a.</td></tr>
069  * <tr><td>%U</td>     <td>Week of year.</td></tr>
070  * <tr><td>%y</td>     <td>Year (2 digits).</td></tr>
071  * <tr><td>%Y</td> <td>Year (4 digits).</td></tr>
072  * <tr><td>%Z</td> <td>Time zone name (4 characters).</td></tr>
073  * <tr><td>%%</td> <td>The % character.</td></tr>
074  * <tr><td>. : / - , ;</td> <td>These characters are interpreted literally.
075  * </td></tr>
076  * </table></center>
077  *
078  * @author Mark Lindner
079  */
080
081public class DateFormatter
082  {
083  private SimpleDateFormat fmt;
084  private String pattern;
085
086  /** Construct a new <code>DateFormatter</code>. See the table of formatting
087    * directives above.
088    *
089    * @param pattern The pattern to be used by this formatter.
090    * @exception java.lang.IllegalArgumentException If the pattern contains
091    * unrecognized formatting directives.
092    */
093
094  public DateFormatter(String pattern) throws IllegalArgumentException
095    {
096    fmt = new SimpleDateFormat(constructPattern(pattern));
097    fmt.setTimeZone(TimeZone.getDefault());
098    }
099
100  /** Parse a date, returning a <code>Date</code> object.
101    *
102    * @param text The text to parse.
103    * @return A <code>Date</code> object corresponding to the parsed date.
104    * @exception ParseException If a parsing error occurred.
105    * @see #format
106    */
107
108  public Date parse(String text) throws ParseException
109    {
110    return(fmt.parse(text));
111    }
112
113  /** Format a <code>Calendar</code> object. The date is formatted according
114    * to the pattern specified in this object's constructor.
115    *
116    * @param date The <code>Date</code> to format.
117    * @return The date formatted as a string.
118    * @see #parse
119    */
120
121  public String format(Calendar date)
122    {
123    return(format(date.getTime()));
124    }
125
126  /** Format the current date. The date is formatted according to the pattern
127    * specified in this object's constructor.
128    *
129    * @return The date formatted as a string.
130    * @see #parse
131    */
132
133  public String format()
134    {
135    return(format(new Date()));
136    }
137  
138  /** Format a date from a <code>Date</code> object. The date is formatted
139    * according to the pattern specified in this object's constructor.
140    *
141    * @param date The <code>Date</code> to format.
142    * @return The date formatted as a string.
143    * @see #parse
144    */
145
146  public String format(Date date)
147    {
148    return(fmt.format(date));
149    }
150
151  /* pattern translator */
152
153  private String constructPattern(String text) throws IllegalArgumentException
154    {
155    StringBuffer sb = new StringBuffer();
156    boolean escaped = false;
157
158    for(int i = 0; i < text.length(); i++)
159      {
160      char c = text.charAt(i);
161
162      if(!escaped)
163        {
164        switch(c)
165          {
166          case ':':
167          case ';':
168          case '/':
169          case '.':
170          case ',':
171          case '-':
172          case ' ':
173          case '\t':
174          case '(':
175          case ')':
176            sb.append(c);
177            escaped = false;
178            break;
179
180          case '%':
181            if(escaped)
182              {
183              sb.append(c);
184              escaped = false;
185              }
186            else escaped = true;
187            break;
188
189          default:
190            throw(new IllegalArgumentException("Unknown format character :"
191                                               + c));
192          }
193        }
194      else
195        {
196        switch(c)
197          {
198          case 'a':
199            sb.append("EE");
200            break;
201          case 'A':
202            sb.append("EEEE");
203            break;
204          case 'b':
205            sb.append("MMM");
206            break;
207          case 'B':
208            sb.append("MMMM");
209            break;
210          case 'd':
211            sb.append("dd");
212            break;
213          case 'e':
214            sb.append('d');
215            break;
216          case 'H':
217            sb.append("HH");
218            break;
219          case 'I':
220            sb.append("hh");
221            break;
222          case 'j':
223            sb.append("DDD");
224            break;
225          case 'm':
226            sb.append("MM");
227            break;
228          case 'M':
229            sb.append("mm");
230            break;
231          case 'N':
232            sb.append('G');
233            break;
234          case 'p':
235            sb.append('a');
236            break;
237          case 'r':
238            sb.append(constructPattern("%I:%M:%S %p"));
239            break;
240          case 'R':
241            sb.append(constructPattern("%H:%M"));
242            break;
243          case 'S':
244            sb.append("ss");
245            break;
246          case 't':
247            sb.append('\t');
248            break;
249          case 'T':
250            sb.append(constructPattern("%H:%M:%S"));
251            break;
252          case 'u':
253            sb.append("EE");
254            break;
255          case 'U':
256            sb.append("ww");
257            break;
258          case 's':
259            sb.append("SSS");
260            break;
261          case 'y':
262            sb.append("yy");
263            break;
264          case 'Y':
265            sb.append("yyyy");
266            break;
267          case 'Z':
268            sb.append("zzzz");
269            break;
270          default:
271            throw(new IllegalArgumentException("Unknown escape sequence: %"
272                                               + c));
273          }
274        escaped = false;
275        }
276      }
277    return(sb.toString());
278    }
279  
280  }
281
282/* end of source file */