Source Code Cross Referenced for FastDateFormat.java in  » Library » Apache-common-lang » org » apache » commons » lang » time » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache common lang » org.apache.commons.lang.time 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         * 
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         * 
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:        package org.apache.commons.lang.time;
0018:
0019:        import java.io.IOException;
0020:        import java.io.ObjectInputStream;
0021:
0022:        import java.text.DateFormat;
0023:        import java.text.DateFormatSymbols;
0024:        import java.text.FieldPosition;
0025:        import java.text.Format;
0026:        import java.text.ParsePosition;
0027:        import java.text.SimpleDateFormat;
0028:        import java.util.ArrayList;
0029:        import java.util.Calendar;
0030:        import java.util.Date;
0031:        import java.util.GregorianCalendar;
0032:        import java.util.HashMap;
0033:        import java.util.List;
0034:        import java.util.Locale;
0035:        import java.util.Map;
0036:        import java.util.TimeZone;
0037:
0038:        import org.apache.commons.lang.Validate;
0039:
0040:        /**
0041:         * <p>FastDateFormat is a fast and thread-safe version of
0042:         * {@link java.text.SimpleDateFormat}.</p>
0043:         * 
0044:         * <p>This class can be used as a direct replacement to
0045:         * <code>SimpleDateFormat</code> in most formatting situations.
0046:         * This class is especially useful in multi-threaded server environments.
0047:         * <code>SimpleDateFormat</code> is not thread-safe in any JDK version,
0048:         * nor will it be as Sun have closed the bug/RFE.
0049:         * </p>
0050:         *
0051:         * <p>Only formatting is supported, but all patterns are compatible with
0052:         * SimpleDateFormat (except time zones - see below).</p>
0053:         *
0054:         * <p>Java 1.4 introduced a new pattern letter, <code>'Z'</code>, to represent
0055:         * time zones in RFC822 format (eg. <code>+0800</code> or <code>-1100</code>).
0056:         * This pattern letter can be used here (on all JDK versions).</p>
0057:         *
0058:         * <p>In addition, the pattern <code>'ZZ'</code> has been made to represent
0059:         * ISO8601 full format time zones (eg. <code>+08:00</code> or <code>-11:00</code>).
0060:         * This introduces a minor incompatibility with Java 1.4, but at a gain of
0061:         * useful functionality.</p>
0062:         *
0063:         * @author TeaTrove project
0064:         * @author Brian S O'Neill
0065:         * @author Sean Schofield
0066:         * @author Gary Gregory
0067:         * @author Stephen Colebourne
0068:         * @author Nikolay Metchev
0069:         * @since 2.0
0070:         * @version $Id: FastDateFormat.java 504349 2007-02-06 22:44:33Z bayard $
0071:         */
0072:        public class FastDateFormat extends Format {
0073:            // A lot of the speed in this class comes from caching, but some comes
0074:            // from the special int to StringBuffer conversion.
0075:            //
0076:            // The following produces a padded 2 digit number:
0077:            //   buffer.append((char)(value / 10 + '0'));
0078:            //   buffer.append((char)(value % 10 + '0'));
0079:            //
0080:            // Note that the fastest append to StringBuffer is a single char (used here).
0081:            // Note that Integer.toString() is not called, the conversion is simply
0082:            // taking the value and adding (mathematically) the ASCII value for '0'.
0083:            // So, don't change this code! It works and is very fast.
0084:
0085:            /**
0086:             * Required for serialization support.
0087:             * 
0088:             * @see java.io.Serializable
0089:             */
0090:            private static final long serialVersionUID = 1L;
0091:
0092:            /**
0093:             * FULL locale dependent date or time style.
0094:             */
0095:            public static final int FULL = DateFormat.FULL;
0096:            /**
0097:             * LONG locale dependent date or time style.
0098:             */
0099:            public static final int LONG = DateFormat.LONG;
0100:            /**
0101:             * MEDIUM locale dependent date or time style.
0102:             */
0103:            public static final int MEDIUM = DateFormat.MEDIUM;
0104:            /**
0105:             * SHORT locale dependent date or time style.
0106:             */
0107:            public static final int SHORT = DateFormat.SHORT;
0108:
0109:            private static String cDefaultPattern;
0110:
0111:            private static Map cInstanceCache = new HashMap(7);
0112:            private static Map cDateInstanceCache = new HashMap(7);
0113:            private static Map cTimeInstanceCache = new HashMap(7);
0114:            private static Map cDateTimeInstanceCache = new HashMap(7);
0115:            private static Map cTimeZoneDisplayCache = new HashMap(7);
0116:
0117:            /**
0118:             * The pattern.
0119:             */
0120:            private final String mPattern;
0121:            /**
0122:             * The time zone.
0123:             */
0124:            private final TimeZone mTimeZone;
0125:            /**
0126:             * Whether the time zone overrides any on Calendars.
0127:             */
0128:            private final boolean mTimeZoneForced;
0129:            /**
0130:             * The locale.
0131:             */
0132:            private final Locale mLocale;
0133:            /**
0134:             * Whether the locale overrides the default.
0135:             */
0136:            private final boolean mLocaleForced;
0137:            /**
0138:             * The parsed rules.
0139:             */
0140:            private transient Rule[] mRules;
0141:            /**
0142:             * The estimated maximum length.
0143:             */
0144:            private transient int mMaxLengthEstimate;
0145:
0146:            //-----------------------------------------------------------------------
0147:            /**
0148:             * <p>Gets a formatter instance using the default pattern in the
0149:             * default locale.</p>
0150:             * 
0151:             * @return a date/time formatter
0152:             */
0153:            public static FastDateFormat getInstance() {
0154:                return getInstance(getDefaultPattern(), null, null);
0155:            }
0156:
0157:            /**
0158:             * <p>Gets a formatter instance using the specified pattern in the
0159:             * default locale.</p>
0160:             * 
0161:             * @param pattern  {@link java.text.SimpleDateFormat} compatible
0162:             *  pattern
0163:             * @return a pattern based date/time formatter
0164:             * @throws IllegalArgumentException if pattern is invalid
0165:             */
0166:            public static FastDateFormat getInstance(String pattern) {
0167:                return getInstance(pattern, null, null);
0168:            }
0169:
0170:            /**
0171:             * <p>Gets a formatter instance using the specified pattern and
0172:             * time zone.</p>
0173:             * 
0174:             * @param pattern  {@link java.text.SimpleDateFormat} compatible
0175:             *  pattern
0176:             * @param timeZone  optional time zone, overrides time zone of
0177:             *  formatted date
0178:             * @return a pattern based date/time formatter
0179:             * @throws IllegalArgumentException if pattern is invalid
0180:             */
0181:            public static FastDateFormat getInstance(String pattern,
0182:                    TimeZone timeZone) {
0183:                return getInstance(pattern, timeZone, null);
0184:            }
0185:
0186:            /**
0187:             * <p>Gets a formatter instance using the specified pattern and
0188:             * locale.</p>
0189:             * 
0190:             * @param pattern  {@link java.text.SimpleDateFormat} compatible
0191:             *  pattern
0192:             * @param locale  optional locale, overrides system locale
0193:             * @return a pattern based date/time formatter
0194:             * @throws IllegalArgumentException if pattern is invalid
0195:             */
0196:            public static FastDateFormat getInstance(String pattern,
0197:                    Locale locale) {
0198:                return getInstance(pattern, null, locale);
0199:            }
0200:
0201:            /**
0202:             * <p>Gets a formatter instance using the specified pattern, time zone
0203:             * and locale.</p>
0204:             * 
0205:             * @param pattern  {@link java.text.SimpleDateFormat} compatible
0206:             *  pattern
0207:             * @param timeZone  optional time zone, overrides time zone of
0208:             *  formatted date
0209:             * @param locale  optional locale, overrides system locale
0210:             * @return a pattern based date/time formatter
0211:             * @throws IllegalArgumentException if pattern is invalid
0212:             *  or <code>null</code>
0213:             */
0214:            public static synchronized FastDateFormat getInstance(
0215:                    String pattern, TimeZone timeZone, Locale locale) {
0216:                FastDateFormat emptyFormat = new FastDateFormat(pattern,
0217:                        timeZone, locale);
0218:                FastDateFormat format = (FastDateFormat) cInstanceCache
0219:                        .get(emptyFormat);
0220:                if (format == null) {
0221:                    format = emptyFormat;
0222:                    format.init(); // convert shell format into usable one
0223:                    cInstanceCache.put(format, format); // this is OK!
0224:                }
0225:                return format;
0226:            }
0227:
0228:            //-----------------------------------------------------------------------
0229:            /**
0230:             * <p>Gets a date formatter instance using the specified style in the
0231:             * default time zone and locale.</p>
0232:             * 
0233:             * @param style  date style: FULL, LONG, MEDIUM, or SHORT
0234:             * @return a localized standard date formatter
0235:             * @throws IllegalArgumentException if the Locale has no date
0236:             *  pattern defined
0237:             * @since 2.1
0238:             */
0239:            public static FastDateFormat getDateInstance(int style) {
0240:                return getDateInstance(style, null, null);
0241:            }
0242:
0243:            /**
0244:             * <p>Gets a date formatter instance using the specified style and
0245:             * locale in the default time zone.</p>
0246:             * 
0247:             * @param style  date style: FULL, LONG, MEDIUM, or SHORT
0248:             * @param locale  optional locale, overrides system locale
0249:             * @return a localized standard date formatter
0250:             * @throws IllegalArgumentException if the Locale has no date
0251:             *  pattern defined
0252:             * @since 2.1
0253:             */
0254:            public static FastDateFormat getDateInstance(int style,
0255:                    Locale locale) {
0256:                return getDateInstance(style, null, locale);
0257:            }
0258:
0259:            /**
0260:             * <p>Gets a date formatter instance using the specified style and
0261:             * time zone in the default locale.</p>
0262:             * 
0263:             * @param style  date style: FULL, LONG, MEDIUM, or SHORT
0264:             * @param timeZone  optional time zone, overrides time zone of
0265:             *  formatted date
0266:             * @return a localized standard date formatter
0267:             * @throws IllegalArgumentException if the Locale has no date
0268:             *  pattern defined
0269:             * @since 2.1
0270:             */
0271:            public static FastDateFormat getDateInstance(int style,
0272:                    TimeZone timeZone) {
0273:                return getDateInstance(style, timeZone, null);
0274:            }
0275:
0276:            /**
0277:             * <p>Gets a date formatter instance using the specified style, time
0278:             * zone and locale.</p>
0279:             * 
0280:             * @param style  date style: FULL, LONG, MEDIUM, or SHORT
0281:             * @param timeZone  optional time zone, overrides time zone of
0282:             *  formatted date
0283:             * @param locale  optional locale, overrides system locale
0284:             * @return a localized standard date formatter
0285:             * @throws IllegalArgumentException if the Locale has no date
0286:             *  pattern defined
0287:             */
0288:            public static synchronized FastDateFormat getDateInstance(
0289:                    int style, TimeZone timeZone, Locale locale) {
0290:                Object key = new Integer(style);
0291:                if (timeZone != null) {
0292:                    key = new Pair(key, timeZone);
0293:                }
0294:                if (locale != null) {
0295:                    key = new Pair(key, locale);
0296:                }
0297:
0298:                FastDateFormat format = (FastDateFormat) cDateInstanceCache
0299:                        .get(key);
0300:                if (format == null) {
0301:                    if (locale == null) {
0302:                        locale = Locale.getDefault();
0303:                    }
0304:
0305:                    try {
0306:                        SimpleDateFormat formatter = (SimpleDateFormat) DateFormat
0307:                                .getDateInstance(style, locale);
0308:                        String pattern = formatter.toPattern();
0309:                        format = getInstance(pattern, timeZone, locale);
0310:                        cDateInstanceCache.put(key, format);
0311:
0312:                    } catch (ClassCastException ex) {
0313:                        throw new IllegalArgumentException(
0314:                                "No date pattern for locale: " + locale);
0315:                    }
0316:                }
0317:                return format;
0318:            }
0319:
0320:            //-----------------------------------------------------------------------
0321:            /**
0322:             * <p>Gets a time formatter instance using the specified style in the
0323:             * default time zone and locale.</p>
0324:             * 
0325:             * @param style  time style: FULL, LONG, MEDIUM, or SHORT
0326:             * @return a localized standard time formatter
0327:             * @throws IllegalArgumentException if the Locale has no time
0328:             *  pattern defined
0329:             * @since 2.1
0330:             */
0331:            public static FastDateFormat getTimeInstance(int style) {
0332:                return getTimeInstance(style, null, null);
0333:            }
0334:
0335:            /**
0336:             * <p>Gets a time formatter instance using the specified style and
0337:             * locale in the default time zone.</p>
0338:             * 
0339:             * @param style  time style: FULL, LONG, MEDIUM, or SHORT
0340:             * @param locale  optional locale, overrides system locale
0341:             * @return a localized standard time formatter
0342:             * @throws IllegalArgumentException if the Locale has no time
0343:             *  pattern defined
0344:             * @since 2.1
0345:             */
0346:            public static FastDateFormat getTimeInstance(int style,
0347:                    Locale locale) {
0348:                return getTimeInstance(style, null, locale);
0349:            }
0350:
0351:            /**
0352:             * <p>Gets a time formatter instance using the specified style and
0353:             * time zone in the default locale.</p>
0354:             * 
0355:             * @param style  time style: FULL, LONG, MEDIUM, or SHORT
0356:             * @param timeZone  optional time zone, overrides time zone of
0357:             *  formatted time
0358:             * @return a localized standard time formatter
0359:             * @throws IllegalArgumentException if the Locale has no time
0360:             *  pattern defined
0361:             * @since 2.1
0362:             */
0363:            public static FastDateFormat getTimeInstance(int style,
0364:                    TimeZone timeZone) {
0365:                return getTimeInstance(style, timeZone, null);
0366:            }
0367:
0368:            /**
0369:             * <p>Gets a time formatter instance using the specified style, time
0370:             * zone and locale.</p>
0371:             * 
0372:             * @param style  time style: FULL, LONG, MEDIUM, or SHORT
0373:             * @param timeZone  optional time zone, overrides time zone of
0374:             *  formatted time
0375:             * @param locale  optional locale, overrides system locale
0376:             * @return a localized standard time formatter
0377:             * @throws IllegalArgumentException if the Locale has no time
0378:             *  pattern defined
0379:             */
0380:            public static synchronized FastDateFormat getTimeInstance(
0381:                    int style, TimeZone timeZone, Locale locale) {
0382:                Object key = new Integer(style);
0383:                if (timeZone != null) {
0384:                    key = new Pair(key, timeZone);
0385:                }
0386:                if (locale != null) {
0387:                    key = new Pair(key, locale);
0388:                }
0389:
0390:                FastDateFormat format = (FastDateFormat) cTimeInstanceCache
0391:                        .get(key);
0392:                if (format == null) {
0393:                    if (locale == null) {
0394:                        locale = Locale.getDefault();
0395:                    }
0396:
0397:                    try {
0398:                        SimpleDateFormat formatter = (SimpleDateFormat) DateFormat
0399:                                .getTimeInstance(style, locale);
0400:                        String pattern = formatter.toPattern();
0401:                        format = getInstance(pattern, timeZone, locale);
0402:                        cTimeInstanceCache.put(key, format);
0403:
0404:                    } catch (ClassCastException ex) {
0405:                        throw new IllegalArgumentException(
0406:                                "No date pattern for locale: " + locale);
0407:                    }
0408:                }
0409:                return format;
0410:            }
0411:
0412:            //-----------------------------------------------------------------------
0413:            /**
0414:             * <p>Gets a date/time formatter instance using the specified style
0415:             * in the default time zone and locale.</p>
0416:             * 
0417:             * @param dateStyle  date style: FULL, LONG, MEDIUM, or SHORT
0418:             * @param timeStyle  time style: FULL, LONG, MEDIUM, or SHORT
0419:             * @return a localized standard date/time formatter
0420:             * @throws IllegalArgumentException if the Locale has no date/time
0421:             *  pattern defined
0422:             * @since 2.1
0423:             */
0424:            public static FastDateFormat getDateTimeInstance(int dateStyle,
0425:                    int timeStyle) {
0426:                return getDateTimeInstance(dateStyle, timeStyle, null, null);
0427:            }
0428:
0429:            /**
0430:             * <p>Gets a date/time formatter instance using the specified style and
0431:             * locale in the default time zone.</p>
0432:             * 
0433:             * @param dateStyle  date style: FULL, LONG, MEDIUM, or SHORT
0434:             * @param timeStyle  time style: FULL, LONG, MEDIUM, or SHORT
0435:             * @param locale  optional locale, overrides system locale
0436:             * @return a localized standard date/time formatter
0437:             * @throws IllegalArgumentException if the Locale has no date/time
0438:             *  pattern defined
0439:             * @since 2.1
0440:             */
0441:            public static FastDateFormat getDateTimeInstance(int dateStyle,
0442:                    int timeStyle, Locale locale) {
0443:                return getDateTimeInstance(dateStyle, timeStyle, null, locale);
0444:            }
0445:
0446:            /**
0447:             * <p>Gets a date/time formatter instance using the specified style and
0448:             * time zone in the default locale.</p>
0449:             * 
0450:             * @param dateStyle  date style: FULL, LONG, MEDIUM, or SHORT
0451:             * @param timeStyle  time style: FULL, LONG, MEDIUM, or SHORT
0452:             * @param timeZone  optional time zone, overrides time zone of
0453:             *  formatted date
0454:             * @return a localized standard date/time formatter
0455:             * @throws IllegalArgumentException if the Locale has no date/time
0456:             *  pattern defined
0457:             * @since 2.1
0458:             */
0459:            public static FastDateFormat getDateTimeInstance(int dateStyle,
0460:                    int timeStyle, TimeZone timeZone) {
0461:                return getDateTimeInstance(dateStyle, timeStyle, timeZone, null);
0462:            }
0463:
0464:            /**
0465:             * <p>Gets a date/time formatter instance using the specified style,
0466:             * time zone and locale.</p>
0467:             * 
0468:             * @param dateStyle  date style: FULL, LONG, MEDIUM, or SHORT
0469:             * @param timeStyle  time style: FULL, LONG, MEDIUM, or SHORT
0470:             * @param timeZone  optional time zone, overrides time zone of
0471:             *  formatted date
0472:             * @param locale  optional locale, overrides system locale
0473:             * @return a localized standard date/time formatter
0474:             * @throws IllegalArgumentException if the Locale has no date/time
0475:             *  pattern defined
0476:             */
0477:            public static synchronized FastDateFormat getDateTimeInstance(
0478:                    int dateStyle, int timeStyle, TimeZone timeZone,
0479:                    Locale locale) {
0480:
0481:                Object key = new Pair(new Integer(dateStyle), new Integer(
0482:                        timeStyle));
0483:                if (timeZone != null) {
0484:                    key = new Pair(key, timeZone);
0485:                }
0486:                if (locale != null) {
0487:                    key = new Pair(key, locale);
0488:                }
0489:
0490:                FastDateFormat format = (FastDateFormat) cDateTimeInstanceCache
0491:                        .get(key);
0492:                if (format == null) {
0493:                    if (locale == null) {
0494:                        locale = Locale.getDefault();
0495:                    }
0496:
0497:                    try {
0498:                        SimpleDateFormat formatter = (SimpleDateFormat) DateFormat
0499:                                .getDateTimeInstance(dateStyle, timeStyle,
0500:                                        locale);
0501:                        String pattern = formatter.toPattern();
0502:                        format = getInstance(pattern, timeZone, locale);
0503:                        cDateTimeInstanceCache.put(key, format);
0504:
0505:                    } catch (ClassCastException ex) {
0506:                        throw new IllegalArgumentException(
0507:                                "No date time pattern for locale: " + locale);
0508:                    }
0509:                }
0510:                return format;
0511:            }
0512:
0513:            //-----------------------------------------------------------------------
0514:            /**
0515:             * <p>Gets the time zone display name, using a cache for performance.</p>
0516:             * 
0517:             * @param tz  the zone to query
0518:             * @param daylight  true if daylight savings
0519:             * @param style  the style to use <code>TimeZone.LONG</code>
0520:             *  or <code>TimeZone.SHORT</code>
0521:             * @param locale  the locale to use
0522:             * @return the textual name of the time zone
0523:             */
0524:            static synchronized String getTimeZoneDisplay(TimeZone tz,
0525:                    boolean daylight, int style, Locale locale) {
0526:                Object key = new TimeZoneDisplayKey(tz, daylight, style, locale);
0527:                String value = (String) cTimeZoneDisplayCache.get(key);
0528:                if (value == null) {
0529:                    // This is a very slow call, so cache the results.
0530:                    value = tz.getDisplayName(daylight, style, locale);
0531:                    cTimeZoneDisplayCache.put(key, value);
0532:                }
0533:                return value;
0534:            }
0535:
0536:            /**
0537:             * <p>Gets the default pattern.</p>
0538:             * 
0539:             * @return the default pattern
0540:             */
0541:            private static synchronized String getDefaultPattern() {
0542:                if (cDefaultPattern == null) {
0543:                    cDefaultPattern = new SimpleDateFormat().toPattern();
0544:                }
0545:                return cDefaultPattern;
0546:            }
0547:
0548:            // Constructor
0549:            //-----------------------------------------------------------------------
0550:            /**
0551:             * <p>Constructs a new FastDateFormat.</p>
0552:             * 
0553:             * @param pattern  {@link java.text.SimpleDateFormat} compatible
0554:             *  pattern
0555:             * @param timeZone  time zone to use, <code>null</code> means use
0556:             *  default for <code>Date</code> and value within for
0557:             *  <code>Calendar</code>
0558:             * @param locale  locale, <code>null</code> means use system
0559:             *  default
0560:             * @throws IllegalArgumentException if pattern is invalid or
0561:             *  <code>null</code>
0562:             */
0563:            protected FastDateFormat(String pattern, TimeZone timeZone,
0564:                    Locale locale) {
0565:                super ();
0566:                if (pattern == null) {
0567:                    throw new IllegalArgumentException(
0568:                            "The pattern must not be null");
0569:                }
0570:                mPattern = pattern;
0571:
0572:                mTimeZoneForced = (timeZone != null);
0573:                if (timeZone == null) {
0574:                    timeZone = TimeZone.getDefault();
0575:                }
0576:                mTimeZone = timeZone;
0577:
0578:                mLocaleForced = (locale != null);
0579:                if (locale == null) {
0580:                    locale = Locale.getDefault();
0581:                }
0582:                mLocale = locale;
0583:            }
0584:
0585:            /**
0586:             * <p>Initializes the instance for first use.</p>
0587:             */
0588:            protected void init() {
0589:                List rulesList = parsePattern();
0590:                mRules = (Rule[]) rulesList.toArray(new Rule[rulesList.size()]);
0591:
0592:                int len = 0;
0593:                for (int i = mRules.length; --i >= 0;) {
0594:                    len += mRules[i].estimateLength();
0595:                }
0596:
0597:                mMaxLengthEstimate = len;
0598:            }
0599:
0600:            // Parse the pattern
0601:            //-----------------------------------------------------------------------
0602:            /**
0603:             * <p>Returns a list of Rules given a pattern.</p>
0604:             * 
0605:             * @return a <code>List</code> of Rule objects
0606:             * @throws IllegalArgumentException if pattern is invalid
0607:             */
0608:            protected List parsePattern() {
0609:                DateFormatSymbols symbols = new DateFormatSymbols(mLocale);
0610:                List rules = new ArrayList();
0611:
0612:                String[] ERAs = symbols.getEras();
0613:                String[] months = symbols.getMonths();
0614:                String[] shortMonths = symbols.getShortMonths();
0615:                String[] weekdays = symbols.getWeekdays();
0616:                String[] shortWeekdays = symbols.getShortWeekdays();
0617:                String[] AmPmStrings = symbols.getAmPmStrings();
0618:
0619:                int length = mPattern.length();
0620:                int[] indexRef = new int[1];
0621:
0622:                for (int i = 0; i < length; i++) {
0623:                    indexRef[0] = i;
0624:                    String token = parseToken(mPattern, indexRef);
0625:                    i = indexRef[0];
0626:
0627:                    int tokenLen = token.length();
0628:                    if (tokenLen == 0) {
0629:                        break;
0630:                    }
0631:
0632:                    Rule rule;
0633:                    char c = token.charAt(0);
0634:
0635:                    switch (c) {
0636:                    case 'G': // era designator (text)
0637:                        rule = new TextField(Calendar.ERA, ERAs);
0638:                        break;
0639:                    case 'y': // year (number)
0640:                        if (tokenLen >= 4) {
0641:                            rule = selectNumberRule(Calendar.YEAR, tokenLen);
0642:                        } else {
0643:                            rule = TwoDigitYearField.INSTANCE;
0644:                        }
0645:                        break;
0646:                    case 'M': // month in year (text and number)
0647:                        if (tokenLen >= 4) {
0648:                            rule = new TextField(Calendar.MONTH, months);
0649:                        } else if (tokenLen == 3) {
0650:                            rule = new TextField(Calendar.MONTH, shortMonths);
0651:                        } else if (tokenLen == 2) {
0652:                            rule = TwoDigitMonthField.INSTANCE;
0653:                        } else {
0654:                            rule = UnpaddedMonthField.INSTANCE;
0655:                        }
0656:                        break;
0657:                    case 'd': // day in month (number)
0658:                        rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen);
0659:                        break;
0660:                    case 'h': // hour in am/pm (number, 1..12)
0661:                        rule = new TwelveHourField(selectNumberRule(
0662:                                Calendar.HOUR, tokenLen));
0663:                        break;
0664:                    case 'H': // hour in day (number, 0..23)
0665:                        rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen);
0666:                        break;
0667:                    case 'm': // minute in hour (number)
0668:                        rule = selectNumberRule(Calendar.MINUTE, tokenLen);
0669:                        break;
0670:                    case 's': // second in minute (number)
0671:                        rule = selectNumberRule(Calendar.SECOND, tokenLen);
0672:                        break;
0673:                    case 'S': // millisecond (number)
0674:                        rule = selectNumberRule(Calendar.MILLISECOND, tokenLen);
0675:                        break;
0676:                    case 'E': // day in week (text)
0677:                        rule = new TextField(Calendar.DAY_OF_WEEK,
0678:                                tokenLen < 4 ? shortWeekdays : weekdays);
0679:                        break;
0680:                    case 'D': // day in year (number)
0681:                        rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen);
0682:                        break;
0683:                    case 'F': // day of week in month (number)
0684:                        rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH,
0685:                                tokenLen);
0686:                        break;
0687:                    case 'w': // week in year (number)
0688:                        rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen);
0689:                        break;
0690:                    case 'W': // week in month (number)
0691:                        rule = selectNumberRule(Calendar.WEEK_OF_MONTH,
0692:                                tokenLen);
0693:                        break;
0694:                    case 'a': // am/pm marker (text)
0695:                        rule = new TextField(Calendar.AM_PM, AmPmStrings);
0696:                        break;
0697:                    case 'k': // hour in day (1..24)
0698:                        rule = new TwentyFourHourField(selectNumberRule(
0699:                                Calendar.HOUR_OF_DAY, tokenLen));
0700:                        break;
0701:                    case 'K': // hour in am/pm (0..11)
0702:                        rule = selectNumberRule(Calendar.HOUR, tokenLen);
0703:                        break;
0704:                    case 'z': // time zone (text)
0705:                        if (tokenLen >= 4) {
0706:                            rule = new TimeZoneNameRule(mTimeZone,
0707:                                    mTimeZoneForced, mLocale, TimeZone.LONG);
0708:                        } else {
0709:                            rule = new TimeZoneNameRule(mTimeZone,
0710:                                    mTimeZoneForced, mLocale, TimeZone.SHORT);
0711:                        }
0712:                        break;
0713:                    case 'Z': // time zone (value)
0714:                        if (tokenLen == 1) {
0715:                            rule = TimeZoneNumberRule.INSTANCE_NO_COLON;
0716:                        } else {
0717:                            rule = TimeZoneNumberRule.INSTANCE_COLON;
0718:                        }
0719:                        break;
0720:                    case '\'': // literal text
0721:                        String sub = token.substring(1);
0722:                        if (sub.length() == 1) {
0723:                            rule = new CharacterLiteral(sub.charAt(0));
0724:                        } else {
0725:                            rule = new StringLiteral(sub);
0726:                        }
0727:                        break;
0728:                    default:
0729:                        throw new IllegalArgumentException(
0730:                                "Illegal pattern component: " + token);
0731:                    }
0732:
0733:                    rules.add(rule);
0734:                }
0735:
0736:                return rules;
0737:            }
0738:
0739:            /**
0740:             * <p>Performs the parsing of tokens.</p>
0741:             * 
0742:             * @param pattern  the pattern
0743:             * @param indexRef  index references
0744:             * @return parsed token
0745:             */
0746:            protected String parseToken(String pattern, int[] indexRef) {
0747:                StringBuffer buf = new StringBuffer();
0748:
0749:                int i = indexRef[0];
0750:                int length = pattern.length();
0751:
0752:                char c = pattern.charAt(i);
0753:                if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') {
0754:                    // Scan a run of the same character, which indicates a time
0755:                    // pattern.
0756:                    buf.append(c);
0757:
0758:                    while (i + 1 < length) {
0759:                        char peek = pattern.charAt(i + 1);
0760:                        if (peek == c) {
0761:                            buf.append(c);
0762:                            i++;
0763:                        } else {
0764:                            break;
0765:                        }
0766:                    }
0767:                } else {
0768:                    // This will identify token as text.
0769:                    buf.append('\'');
0770:
0771:                    boolean inLiteral = false;
0772:
0773:                    for (; i < length; i++) {
0774:                        c = pattern.charAt(i);
0775:
0776:                        if (c == '\'') {
0777:                            if (i + 1 < length && pattern.charAt(i + 1) == '\'') {
0778:                                // '' is treated as escaped '
0779:                                i++;
0780:                                buf.append(c);
0781:                            } else {
0782:                                inLiteral = !inLiteral;
0783:                            }
0784:                        } else if (!inLiteral
0785:                                && (c >= 'A' && c <= 'Z' || c >= 'a'
0786:                                        && c <= 'z')) {
0787:                            i--;
0788:                            break;
0789:                        } else {
0790:                            buf.append(c);
0791:                        }
0792:                    }
0793:                }
0794:
0795:                indexRef[0] = i;
0796:                return buf.toString();
0797:            }
0798:
0799:            /**
0800:             * <p>Gets an appropriate rule for the padding required.</p>
0801:             * 
0802:             * @param field  the field to get a rule for
0803:             * @param padding  the padding required
0804:             * @return a new rule with the correct padding
0805:             */
0806:            protected NumberRule selectNumberRule(int field, int padding) {
0807:                switch (padding) {
0808:                case 1:
0809:                    return new UnpaddedNumberField(field);
0810:                case 2:
0811:                    return new TwoDigitNumberField(field);
0812:                default:
0813:                    return new PaddedNumberField(field, padding);
0814:                }
0815:            }
0816:
0817:            // Format methods
0818:            //-----------------------------------------------------------------------
0819:            /**
0820:             * <p>Formats a <code>Date</code>, <code>Calendar</code> or
0821:             * <code>Long</code> (milliseconds) object.</p>
0822:             * 
0823:             * @param obj  the object to format
0824:             * @param toAppendTo  the buffer to append to
0825:             * @param pos  the position - ignored
0826:             * @return the buffer passed in
0827:             */
0828:            public StringBuffer format(Object obj, StringBuffer toAppendTo,
0829:                    FieldPosition pos) {
0830:                if (obj instanceof  Date) {
0831:                    return format((Date) obj, toAppendTo);
0832:                } else if (obj instanceof  Calendar) {
0833:                    return format((Calendar) obj, toAppendTo);
0834:                } else if (obj instanceof  Long) {
0835:                    return format(((Long) obj).longValue(), toAppendTo);
0836:                } else {
0837:                    throw new IllegalArgumentException("Unknown class: "
0838:                            + (obj == null ? "<null>" : obj.getClass()
0839:                                    .getName()));
0840:                }
0841:            }
0842:
0843:            /**
0844:             * <p>Formats a millisecond <code>long</code> value.</p>
0845:             * 
0846:             * @param millis  the millisecond value to format
0847:             * @return the formatted string
0848:             * @since 2.1
0849:             */
0850:            public String format(long millis) {
0851:                return format(new Date(millis));
0852:            }
0853:
0854:            /**
0855:             * <p>Formats a <code>Date</code> object.</p>
0856:             * 
0857:             * @param date  the date to format
0858:             * @return the formatted string
0859:             */
0860:            public String format(Date date) {
0861:                Calendar c = new GregorianCalendar(mTimeZone);
0862:                c.setTime(date);
0863:                return applyRules(c, new StringBuffer(mMaxLengthEstimate))
0864:                        .toString();
0865:            }
0866:
0867:            /**
0868:             * <p>Formats a <code>Calendar</code> object.</p>
0869:             * 
0870:             * @param calendar  the calendar to format
0871:             * @return the formatted string
0872:             */
0873:            public String format(Calendar calendar) {
0874:                return format(calendar, new StringBuffer(mMaxLengthEstimate))
0875:                        .toString();
0876:            }
0877:
0878:            /**
0879:             * <p>Formats a milliseond <code>long</code> value into the
0880:             * supplied <code>StringBuffer</code>.</p>
0881:             * 
0882:             * @param millis  the millisecond value to format
0883:             * @param buf  the buffer to format into
0884:             * @return the specified string buffer
0885:             * @since 2.1
0886:             */
0887:            public StringBuffer format(long millis, StringBuffer buf) {
0888:                return format(new Date(millis), buf);
0889:            }
0890:
0891:            /**
0892:             * <p>Formats a <code>Date</code> object into the
0893:             * supplied <code>StringBuffer</code>.</p>
0894:             * 
0895:             * @param date  the date to format
0896:             * @param buf  the buffer to format into
0897:             * @return the specified string buffer
0898:             */
0899:            public StringBuffer format(Date date, StringBuffer buf) {
0900:                Calendar c = new GregorianCalendar(mTimeZone);
0901:                c.setTime(date);
0902:                return applyRules(c, buf);
0903:            }
0904:
0905:            /**
0906:             * <p>Formats a <code>Calendar</code> object into the
0907:             * supplied <code>StringBuffer</code>.</p>
0908:             * 
0909:             * @param calendar  the calendar to format
0910:             * @param buf  the buffer to format into
0911:             * @return the specified string buffer
0912:             */
0913:            public StringBuffer format(Calendar calendar, StringBuffer buf) {
0914:                if (mTimeZoneForced) {
0915:                    calendar = (Calendar) calendar.clone();
0916:                    calendar.setTimeZone(mTimeZone);
0917:                }
0918:                return applyRules(calendar, buf);
0919:            }
0920:
0921:            /**
0922:             * <p>Performs the formatting by applying the rules to the
0923:             * specified calendar.</p>
0924:             * 
0925:             * @param calendar  the calendar to format
0926:             * @param buf  the buffer to format into
0927:             * @return the specified string buffer
0928:             */
0929:            protected StringBuffer applyRules(Calendar calendar,
0930:                    StringBuffer buf) {
0931:                Rule[] rules = mRules;
0932:                int len = mRules.length;
0933:                for (int i = 0; i < len; i++) {
0934:                    rules[i].appendTo(buf, calendar);
0935:                }
0936:                return buf;
0937:            }
0938:
0939:            // Parsing
0940:            //-----------------------------------------------------------------------
0941:            /**
0942:             * <p>Parsing is not supported.</p>
0943:             * 
0944:             * @param source  the string to parse
0945:             * @param pos  the parsing position
0946:             * @return <code>null</code> as not supported
0947:             */
0948:            public Object parseObject(String source, ParsePosition pos) {
0949:                pos.setIndex(0);
0950:                pos.setErrorIndex(0);
0951:                return null;
0952:            }
0953:
0954:            // Accessors
0955:            //-----------------------------------------------------------------------
0956:            /**
0957:             * <p>Gets the pattern used by this formatter.</p>
0958:             * 
0959:             * @return the pattern, {@link java.text.SimpleDateFormat} compatible
0960:             */
0961:            public String getPattern() {
0962:                return mPattern;
0963:            }
0964:
0965:            /**
0966:             * <p>Gets the time zone used by this formatter.</p>
0967:             *
0968:             * <p>This zone is always used for <code>Date</code> formatting.
0969:             * If a <code>Calendar</code> is passed in to be formatted, the
0970:             * time zone on that may be used depending on
0971:             * {@link #getTimeZoneOverridesCalendar()}.</p>
0972:             * 
0973:             * @return the time zone
0974:             */
0975:            public TimeZone getTimeZone() {
0976:                return mTimeZone;
0977:            }
0978:
0979:            /**
0980:             * <p>Returns <code>true</code> if the time zone of the
0981:             * calendar overrides the time zone of the formatter.</p>
0982:             * 
0983:             * @return <code>true</code> if time zone of formatter
0984:             *  overridden for calendars
0985:             */
0986:            public boolean getTimeZoneOverridesCalendar() {
0987:                return mTimeZoneForced;
0988:            }
0989:
0990:            /**
0991:             * <p>Gets the locale used by this formatter.</p>
0992:             * 
0993:             * @return the locale
0994:             */
0995:            public Locale getLocale() {
0996:                return mLocale;
0997:            }
0998:
0999:            /**
1000:             * <p>Gets an estimate for the maximum string length that the
1001:             * formatter will produce.</p>
1002:             *
1003:             * <p>The actual formatted length will almost always be less than or
1004:             * equal to this amount.</p>
1005:             * 
1006:             * @return the maximum formatted length
1007:             */
1008:            public int getMaxLengthEstimate() {
1009:                return mMaxLengthEstimate;
1010:            }
1011:
1012:            // Basics
1013:            //-----------------------------------------------------------------------
1014:            /**
1015:             * <p>Compares two objects for equality.</p>
1016:             * 
1017:             * @param obj  the object to compare to
1018:             * @return <code>true</code> if equal
1019:             */
1020:            public boolean equals(Object obj) {
1021:                if (obj instanceof  FastDateFormat == false) {
1022:                    return false;
1023:                }
1024:                FastDateFormat other = (FastDateFormat) obj;
1025:                if ((mPattern == other.mPattern || mPattern
1026:                        .equals(other.mPattern))
1027:                        && (mTimeZone == other.mTimeZone || mTimeZone
1028:                                .equals(other.mTimeZone))
1029:                        && (mLocale == other.mLocale || mLocale
1030:                                .equals(other.mLocale))
1031:                        && (mTimeZoneForced == other.mTimeZoneForced)
1032:                        && (mLocaleForced == other.mLocaleForced)) {
1033:                    return true;
1034:                }
1035:                return false;
1036:            }
1037:
1038:            /**
1039:             * <p>Returns a hashcode compatible with equals.</p>
1040:             * 
1041:             * @return a hashcode compatible with equals
1042:             */
1043:            public int hashCode() {
1044:                int total = 0;
1045:                total += mPattern.hashCode();
1046:                total += mTimeZone.hashCode();
1047:                total += (mTimeZoneForced ? 1 : 0);
1048:                total += mLocale.hashCode();
1049:                total += (mLocaleForced ? 1 : 0);
1050:                return total;
1051:            }
1052:
1053:            /**
1054:             * <p>Gets a debugging string version of this formatter.</p>
1055:             * 
1056:             * @return a debugging string
1057:             */
1058:            public String toString() {
1059:                return "FastDateFormat[" + mPattern + "]";
1060:            }
1061:
1062:            // Serializing
1063:            //-----------------------------------------------------------------------
1064:            /**
1065:             * Create the object after serialization. This implementation reinitializes the 
1066:             * transient properties.
1067:             *
1068:             * @param in ObjectInputStream from which the object is being deserialized.
1069:             * @throws IOException if there is an IO issue.
1070:             * @throws ClassNotFoundException if a class cannot be found.
1071:             */
1072:            private void readObject(ObjectInputStream in) throws IOException,
1073:                    ClassNotFoundException {
1074:                in.defaultReadObject();
1075:                init();
1076:            }
1077:
1078:            // Rules
1079:            //-----------------------------------------------------------------------
1080:            /**
1081:             * <p>Inner class defining a rule.</p>
1082:             */
1083:            private interface Rule {
1084:                /**
1085:                 * Returns the estimated lentgh of the result.
1086:                 * 
1087:                 * @return the estimated length
1088:                 */
1089:                int estimateLength();
1090:
1091:                /**
1092:                 * Appends the value of the specified calendar to the output buffer based on the rule implementation.
1093:                 * 
1094:                 * @param buffer the output buffer
1095:                 * @param calendar calendar to be appended
1096:                 */
1097:                void appendTo(StringBuffer buffer, Calendar calendar);
1098:            }
1099:
1100:            /**
1101:             * <p>Inner class defining a numeric rule.</p>
1102:             */
1103:            private interface NumberRule extends Rule {
1104:                /**
1105:                 * Appends the specified value to the output buffer based on the rule implementation.
1106:                 * 
1107:                 * @param buffer the output buffer
1108:                 * @param value the value to be appended
1109:                 */
1110:                void appendTo(StringBuffer buffer, int value);
1111:            }
1112:
1113:            /**
1114:             * <p>Inner class to output a constant single character.</p>
1115:             */
1116:            private static class CharacterLiteral implements  Rule {
1117:                private final char mValue;
1118:
1119:                /**
1120:                 * Constructs a new instance of <code>CharacterLiteral</code>
1121:                 * to hold the specified value.
1122:                 * 
1123:                 * @param value the character literal
1124:                 */
1125:                CharacterLiteral(char value) {
1126:                    mValue = value;
1127:                }
1128:
1129:                /**
1130:                 * {@inheritDoc}
1131:                 */
1132:                public int estimateLength() {
1133:                    return 1;
1134:                }
1135:
1136:                /**
1137:                 * {@inheritDoc}
1138:                 */
1139:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1140:                    buffer.append(mValue);
1141:                }
1142:            }
1143:
1144:            /**
1145:             * <p>Inner class to output a constant string.</p>
1146:             */
1147:            private static class StringLiteral implements  Rule {
1148:                private final String mValue;
1149:
1150:                /**
1151:                 * Constructs a new instance of <code>StringLiteral</code>
1152:                 * to hold the specified value.
1153:                 * 
1154:                 * @param value the string literal
1155:                 */
1156:                StringLiteral(String value) {
1157:                    mValue = value;
1158:                }
1159:
1160:                /**
1161:                 * {@inheritDoc}
1162:                 */
1163:                public int estimateLength() {
1164:                    return mValue.length();
1165:                }
1166:
1167:                /**
1168:                 * {@inheritDoc}
1169:                 */
1170:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1171:                    buffer.append(mValue);
1172:                }
1173:            }
1174:
1175:            /**
1176:             * <p>Inner class to output one of a set of values.</p>
1177:             */
1178:            private static class TextField implements  Rule {
1179:                private final int mField;
1180:                private final String[] mValues;
1181:
1182:                /**
1183:                 * Constructs an instance of <code>TextField</code>
1184:                 * with the specified field and values.
1185:                 * 
1186:                 * @param field the field
1187:                 * @param values the field values
1188:                 */
1189:                TextField(int field, String[] values) {
1190:                    mField = field;
1191:                    mValues = values;
1192:                }
1193:
1194:                /**
1195:                 * {@inheritDoc}
1196:                 */
1197:                public int estimateLength() {
1198:                    int max = 0;
1199:                    for (int i = mValues.length; --i >= 0;) {
1200:                        int len = mValues[i].length();
1201:                        if (len > max) {
1202:                            max = len;
1203:                        }
1204:                    }
1205:                    return max;
1206:                }
1207:
1208:                /**
1209:                 * {@inheritDoc}
1210:                 */
1211:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1212:                    buffer.append(mValues[calendar.get(mField)]);
1213:                }
1214:            }
1215:
1216:            /**
1217:             * <p>Inner class to output an unpadded number.</p>
1218:             */
1219:            private static class UnpaddedNumberField implements  NumberRule {
1220:                static final UnpaddedNumberField INSTANCE_YEAR = new UnpaddedNumberField(
1221:                        Calendar.YEAR);
1222:
1223:                private final int mField;
1224:
1225:                /**
1226:                 * Constructs an instance of <code>UnpadedNumberField</code> with the specified field.
1227:                 * 
1228:                 * @param field the field
1229:                 */
1230:                UnpaddedNumberField(int field) {
1231:                    mField = field;
1232:                }
1233:
1234:                /**
1235:                 * {@inheritDoc}
1236:                 */
1237:                public int estimateLength() {
1238:                    return 4;
1239:                }
1240:
1241:                /**
1242:                 * {@inheritDoc}
1243:                 */
1244:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1245:                    appendTo(buffer, calendar.get(mField));
1246:                }
1247:
1248:                /**
1249:                 * {@inheritDoc}
1250:                 */
1251:                public final void appendTo(StringBuffer buffer, int value) {
1252:                    if (value < 10) {
1253:                        buffer.append((char) (value + '0'));
1254:                    } else if (value < 100) {
1255:                        buffer.append((char) (value / 10 + '0'));
1256:                        buffer.append((char) (value % 10 + '0'));
1257:                    } else {
1258:                        buffer.append(Integer.toString(value));
1259:                    }
1260:                }
1261:            }
1262:
1263:            /**
1264:             * <p>Inner class to output an unpadded month.</p>
1265:             */
1266:            private static class UnpaddedMonthField implements  NumberRule {
1267:                static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField();
1268:
1269:                /**
1270:                 * Constructs an instance of <code>UnpaddedMonthField</code>.
1271:                 *
1272:                 */
1273:                UnpaddedMonthField() {
1274:                    super ();
1275:                }
1276:
1277:                /**
1278:                 * {@inheritDoc}
1279:                 */
1280:                public int estimateLength() {
1281:                    return 2;
1282:                }
1283:
1284:                /**
1285:                 * {@inheritDoc}
1286:                 */
1287:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1288:                    appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
1289:                }
1290:
1291:                /**
1292:                 * {@inheritDoc}
1293:                 */
1294:                public final void appendTo(StringBuffer buffer, int value) {
1295:                    if (value < 10) {
1296:                        buffer.append((char) (value + '0'));
1297:                    } else {
1298:                        buffer.append((char) (value / 10 + '0'));
1299:                        buffer.append((char) (value % 10 + '0'));
1300:                    }
1301:                }
1302:            }
1303:
1304:            /**
1305:             * <p>Inner class to output a padded number.</p>
1306:             */
1307:            private static class PaddedNumberField implements  NumberRule {
1308:                private final int mField;
1309:                private final int mSize;
1310:
1311:                /**
1312:                 * Constructs an instance of <code>PaddedNumberField</code>.
1313:                 * 
1314:                 * @param field the field
1315:                 * @param size size of the output field
1316:                 */
1317:                PaddedNumberField(int field, int size) {
1318:                    if (size < 3) {
1319:                        // Should use UnpaddedNumberField or TwoDigitNumberField.
1320:                        throw new IllegalArgumentException();
1321:                    }
1322:                    mField = field;
1323:                    mSize = size;
1324:                }
1325:
1326:                /**
1327:                 * {@inheritDoc}
1328:                 */
1329:                public int estimateLength() {
1330:                    return 4;
1331:                }
1332:
1333:                /**
1334:                 * {@inheritDoc}
1335:                 */
1336:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1337:                    appendTo(buffer, calendar.get(mField));
1338:                }
1339:
1340:                /**
1341:                 * {@inheritDoc}
1342:                 */
1343:                public final void appendTo(StringBuffer buffer, int value) {
1344:                    if (value < 100) {
1345:                        for (int i = mSize; --i >= 2;) {
1346:                            buffer.append('0');
1347:                        }
1348:                        buffer.append((char) (value / 10 + '0'));
1349:                        buffer.append((char) (value % 10 + '0'));
1350:                    } else {
1351:                        int digits;
1352:                        if (value < 1000) {
1353:                            digits = 3;
1354:                        } else {
1355:                            Validate.isTrue(value > -1,
1356:                                    "Negative values should not be possible",
1357:                                    value);
1358:                            digits = Integer.toString(value).length();
1359:                        }
1360:                        for (int i = mSize; --i >= digits;) {
1361:                            buffer.append('0');
1362:                        }
1363:                        buffer.append(Integer.toString(value));
1364:                    }
1365:                }
1366:            }
1367:
1368:            /**
1369:             * <p>Inner class to output a two digit number.</p>
1370:             */
1371:            private static class TwoDigitNumberField implements  NumberRule {
1372:                private final int mField;
1373:
1374:                /**
1375:                 * Constructs an instance of <code>TwoDigitNumberField</code> with the specified field.
1376:                 * 
1377:                 * @param field the field
1378:                 */
1379:                TwoDigitNumberField(int field) {
1380:                    mField = field;
1381:                }
1382:
1383:                /**
1384:                 * {@inheritDoc}
1385:                 */
1386:                public int estimateLength() {
1387:                    return 2;
1388:                }
1389:
1390:                /**
1391:                 * {@inheritDoc}
1392:                 */
1393:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1394:                    appendTo(buffer, calendar.get(mField));
1395:                }
1396:
1397:                /**
1398:                 * {@inheritDoc}
1399:                 */
1400:                public final void appendTo(StringBuffer buffer, int value) {
1401:                    if (value < 100) {
1402:                        buffer.append((char) (value / 10 + '0'));
1403:                        buffer.append((char) (value % 10 + '0'));
1404:                    } else {
1405:                        buffer.append(Integer.toString(value));
1406:                    }
1407:                }
1408:            }
1409:
1410:            /**
1411:             * <p>Inner class to output a two digit year.</p>
1412:             */
1413:            private static class TwoDigitYearField implements  NumberRule {
1414:                static final TwoDigitYearField INSTANCE = new TwoDigitYearField();
1415:
1416:                /**
1417:                 * Constructs an instance of <code>TwoDigitYearField</code>.
1418:                 */
1419:                TwoDigitYearField() {
1420:                    super ();
1421:                }
1422:
1423:                /**
1424:                 * {@inheritDoc}
1425:                 */
1426:                public int estimateLength() {
1427:                    return 2;
1428:                }
1429:
1430:                /**
1431:                 * {@inheritDoc}
1432:                 */
1433:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1434:                    appendTo(buffer, calendar.get(Calendar.YEAR) % 100);
1435:                }
1436:
1437:                /**
1438:                 * {@inheritDoc}
1439:                 */
1440:                public final void appendTo(StringBuffer buffer, int value) {
1441:                    buffer.append((char) (value / 10 + '0'));
1442:                    buffer.append((char) (value % 10 + '0'));
1443:                }
1444:            }
1445:
1446:            /**
1447:             * <p>Inner class to output a two digit month.</p>
1448:             */
1449:            private static class TwoDigitMonthField implements  NumberRule {
1450:                static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField();
1451:
1452:                /**
1453:                 * Constructs an instance of <code>TwoDigitMonthField</code>.
1454:                 */
1455:                TwoDigitMonthField() {
1456:                    super ();
1457:                }
1458:
1459:                /**
1460:                 * {@inheritDoc}
1461:                 */
1462:                public int estimateLength() {
1463:                    return 2;
1464:                }
1465:
1466:                /**
1467:                 * {@inheritDoc}
1468:                 */
1469:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1470:                    appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
1471:                }
1472:
1473:                /**
1474:                 * {@inheritDoc}
1475:                 */
1476:                public final void appendTo(StringBuffer buffer, int value) {
1477:                    buffer.append((char) (value / 10 + '0'));
1478:                    buffer.append((char) (value % 10 + '0'));
1479:                }
1480:            }
1481:
1482:            /**
1483:             * <p>Inner class to output the twelve hour field.</p>
1484:             */
1485:            private static class TwelveHourField implements  NumberRule {
1486:                private final NumberRule mRule;
1487:
1488:                /**
1489:                 * Constructs an instance of <code>TwelveHourField</code> with the specified
1490:                 * <code>NumberRule</code>.
1491:                 * 
1492:                 * @param rule the rule
1493:                 */
1494:                TwelveHourField(NumberRule rule) {
1495:                    mRule = rule;
1496:                }
1497:
1498:                /**
1499:                 * {@inheritDoc}
1500:                 */
1501:                public int estimateLength() {
1502:                    return mRule.estimateLength();
1503:                }
1504:
1505:                /**
1506:                 * {@inheritDoc}
1507:                 */
1508:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1509:                    int value = calendar.get(Calendar.HOUR);
1510:                    if (value == 0) {
1511:                        value = calendar.getLeastMaximum(Calendar.HOUR) + 1;
1512:                    }
1513:                    mRule.appendTo(buffer, value);
1514:                }
1515:
1516:                /**
1517:                 * {@inheritDoc}
1518:                 */
1519:                public void appendTo(StringBuffer buffer, int value) {
1520:                    mRule.appendTo(buffer, value);
1521:                }
1522:            }
1523:
1524:            /**
1525:             * <p>Inner class to output the twenty four hour field.</p>
1526:             */
1527:            private static class TwentyFourHourField implements  NumberRule {
1528:                private final NumberRule mRule;
1529:
1530:                /**
1531:                 * Constructs an instance of <code>TwentyFourHourField</code> with the specified
1532:                 * <code>NumberRule</code>.
1533:                 * 
1534:                 * @param rule the rule
1535:                 */
1536:                TwentyFourHourField(NumberRule rule) {
1537:                    mRule = rule;
1538:                }
1539:
1540:                /**
1541:                 * {@inheritDoc}
1542:                 */
1543:                public int estimateLength() {
1544:                    return mRule.estimateLength();
1545:                }
1546:
1547:                /**
1548:                 * {@inheritDoc}
1549:                 */
1550:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1551:                    int value = calendar.get(Calendar.HOUR_OF_DAY);
1552:                    if (value == 0) {
1553:                        value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1;
1554:                    }
1555:                    mRule.appendTo(buffer, value);
1556:                }
1557:
1558:                /**
1559:                 * {@inheritDoc}
1560:                 */
1561:                public void appendTo(StringBuffer buffer, int value) {
1562:                    mRule.appendTo(buffer, value);
1563:                }
1564:            }
1565:
1566:            /**
1567:             * <p>Inner class to output a time zone name.</p>
1568:             */
1569:            private static class TimeZoneNameRule implements  Rule {
1570:                private final TimeZone mTimeZone;
1571:                private final boolean mTimeZoneForced;
1572:                private final Locale mLocale;
1573:                private final int mStyle;
1574:                private final String mStandard;
1575:                private final String mDaylight;
1576:
1577:                /**
1578:                 * Constructs an instance of <code>TimeZoneNameRule</code> with the specified properties.
1579:                 * 
1580:                 * @param timeZone the time zone
1581:                 * @param timeZoneForced if <code>true</code> the time zone is forced into standard and daylight
1582:                 * @param locale the locale
1583:                 * @param style the style
1584:                 */
1585:                TimeZoneNameRule(TimeZone timeZone, boolean timeZoneForced,
1586:                        Locale locale, int style) {
1587:                    mTimeZone = timeZone;
1588:                    mTimeZoneForced = timeZoneForced;
1589:                    mLocale = locale;
1590:                    mStyle = style;
1591:
1592:                    if (timeZoneForced) {
1593:                        mStandard = getTimeZoneDisplay(timeZone, false, style,
1594:                                locale);
1595:                        mDaylight = getTimeZoneDisplay(timeZone, true, style,
1596:                                locale);
1597:                    } else {
1598:                        mStandard = null;
1599:                        mDaylight = null;
1600:                    }
1601:                }
1602:
1603:                /**
1604:                 * {@inheritDoc}
1605:                 */
1606:                public int estimateLength() {
1607:                    if (mTimeZoneForced) {
1608:                        return Math.max(mStandard.length(), mDaylight.length());
1609:                    } else if (mStyle == TimeZone.SHORT) {
1610:                        return 4;
1611:                    } else {
1612:                        return 40;
1613:                    }
1614:                }
1615:
1616:                /**
1617:                 * {@inheritDoc}
1618:                 */
1619:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1620:                    if (mTimeZoneForced) {
1621:                        if (mTimeZone.useDaylightTime()
1622:                                && calendar.get(Calendar.DST_OFFSET) != 0) {
1623:                            buffer.append(mDaylight);
1624:                        } else {
1625:                            buffer.append(mStandard);
1626:                        }
1627:                    } else {
1628:                        TimeZone timeZone = calendar.getTimeZone();
1629:                        if (timeZone.useDaylightTime()
1630:                                && calendar.get(Calendar.DST_OFFSET) != 0) {
1631:                            buffer.append(getTimeZoneDisplay(timeZone, true,
1632:                                    mStyle, mLocale));
1633:                        } else {
1634:                            buffer.append(getTimeZoneDisplay(timeZone, false,
1635:                                    mStyle, mLocale));
1636:                        }
1637:                    }
1638:                }
1639:            }
1640:
1641:            /**
1642:             * <p>Inner class to output a time zone as a number <code>+/-HHMM</code>
1643:             * or <code>+/-HH:MM</code>.</p>
1644:             */
1645:            private static class TimeZoneNumberRule implements  Rule {
1646:                static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(
1647:                        true);
1648:                static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(
1649:                        false);
1650:
1651:                final boolean mColon;
1652:
1653:                /**
1654:                 * Constructs an instance of <code>TimeZoneNumberRule</code> with the specified properties.
1655:                 * 
1656:                 * @param colon add colon between HH and MM in the output if <code>true</code>
1657:                 */
1658:                TimeZoneNumberRule(boolean colon) {
1659:                    mColon = colon;
1660:                }
1661:
1662:                /**
1663:                 * {@inheritDoc}
1664:                 */
1665:                public int estimateLength() {
1666:                    return 5;
1667:                }
1668:
1669:                /**
1670:                 * {@inheritDoc}
1671:                 */
1672:                public void appendTo(StringBuffer buffer, Calendar calendar) {
1673:                    int offset = calendar.get(Calendar.ZONE_OFFSET)
1674:                            + calendar.get(Calendar.DST_OFFSET);
1675:
1676:                    if (offset < 0) {
1677:                        buffer.append('-');
1678:                        offset = -offset;
1679:                    } else {
1680:                        buffer.append('+');
1681:                    }
1682:
1683:                    int hours = offset / (60 * 60 * 1000);
1684:                    buffer.append((char) (hours / 10 + '0'));
1685:                    buffer.append((char) (hours % 10 + '0'));
1686:
1687:                    if (mColon) {
1688:                        buffer.append(':');
1689:                    }
1690:
1691:                    int minutes = offset / (60 * 1000) - 60 * hours;
1692:                    buffer.append((char) (minutes / 10 + '0'));
1693:                    buffer.append((char) (minutes % 10 + '0'));
1694:                }
1695:            }
1696:
1697:            // ----------------------------------------------------------------------
1698:            /**
1699:             * <p>Inner class that acts as a compound key for time zone names.</p>
1700:             */
1701:            private static class TimeZoneDisplayKey {
1702:                private final TimeZone mTimeZone;
1703:                private final int mStyle;
1704:                private final Locale mLocale;
1705:
1706:                /**
1707:                 * Constructs an instance of <code>TimeZoneDisplayKey</code> with the specified properties.
1708:                 *  
1709:                 * @param timeZone the time zone
1710:                 * @param daylight adjust the style for daylight saving time if <code>true</code>
1711:                 * @param style the timezone style
1712:                 * @param locale the timezone locale
1713:                 */
1714:                TimeZoneDisplayKey(TimeZone timeZone, boolean daylight,
1715:                        int style, Locale locale) {
1716:                    mTimeZone = timeZone;
1717:                    if (daylight) {
1718:                        style |= 0x80000000;
1719:                    }
1720:                    mStyle = style;
1721:                    mLocale = locale;
1722:                }
1723:
1724:                /**
1725:                 * {@inheritDoc}
1726:                 */
1727:                public int hashCode() {
1728:                    return mStyle * 31 + mLocale.hashCode();
1729:                }
1730:
1731:                /**
1732:                 * {@inheritDoc}
1733:                 */
1734:                public boolean equals(Object obj) {
1735:                    if (this  == obj) {
1736:                        return true;
1737:                    }
1738:                    if (obj instanceof  TimeZoneDisplayKey) {
1739:                        TimeZoneDisplayKey other = (TimeZoneDisplayKey) obj;
1740:                        return mTimeZone.equals(other.mTimeZone)
1741:                                && mStyle == other.mStyle
1742:                                && mLocale.equals(other.mLocale);
1743:                    }
1744:                    return false;
1745:                }
1746:            }
1747:
1748:            // ----------------------------------------------------------------------
1749:            /**
1750:             * <p>Helper class for creating compound objects.</p>
1751:             *
1752:             * <p>One use for this class is to create a hashtable key
1753:             * out of multiple objects.</p>
1754:             */
1755:            private static class Pair {
1756:                private final Object mObj1;
1757:                private final Object mObj2;
1758:
1759:                /**
1760:                 * Constructs an instance of <code>Pair</code> to hold the specified objects.
1761:                 * @param obj1 one object in the pair
1762:                 * @param obj2 second object in the pair
1763:                 */
1764:                public Pair(Object obj1, Object obj2) {
1765:                    mObj1 = obj1;
1766:                    mObj2 = obj2;
1767:                }
1768:
1769:                /**
1770:                 * {@inheritDoc}
1771:                 */
1772:                public boolean equals(Object obj) {
1773:                    if (this  == obj) {
1774:                        return true;
1775:                    }
1776:
1777:                    if (!(obj instanceof  Pair)) {
1778:                        return false;
1779:                    }
1780:
1781:                    Pair key = (Pair) obj;
1782:
1783:                    return (mObj1 == null ? key.mObj1 == null : mObj1
1784:                            .equals(key.mObj1))
1785:                            && (mObj2 == null ? key.mObj2 == null : mObj2
1786:                                    .equals(key.mObj2));
1787:                }
1788:
1789:                /**
1790:                 * {@inheritDoc}
1791:                 */
1792:                public int hashCode() {
1793:                    return (mObj1 == null ? 0 : mObj1.hashCode())
1794:                            + (mObj2 == null ? 0 : mObj2.hashCode());
1795:                }
1796:
1797:                /**
1798:                 * {@inheritDoc}
1799:                 */
1800:                public String toString() {
1801:                    return "[" + mObj1 + ':' + mObj2 + ']';
1802:                }
1803:            }
1804:
1805:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.