Source Code Cross Referenced for DateTimeFormat.java in  » Development » Joda-Time » org » joda » time » format » 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 » Development » Joda Time » org.joda.time.format 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *  Copyright 2001-2005 Stephen Colebourne
003:         *
004:         *  Licensed under the Apache License, Version 2.0 (the "License");
005:         *  you may not use this file except in compliance with the License.
006:         *  You may obtain a copy of the License at
007:         *
008:         *      http://www.apache.org/licenses/LICENSE-2.0
009:         *
010:         *  Unless required by applicable law or agreed to in writing, software
011:         *  distributed under the License is distributed on an "AS IS" BASIS,
012:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013:         *  See the License for the specific language governing permissions and
014:         *  limitations under the License.
015:         */
016:        package org.joda.time.format;
017:
018:        import java.io.IOException;
019:        import java.io.Writer;
020:        import java.text.DateFormat;
021:        import java.text.SimpleDateFormat;
022:        import java.util.HashMap;
023:        import java.util.Locale;
024:        import java.util.Map;
025:
026:        import org.joda.time.Chronology;
027:        import org.joda.time.DateTime;
028:        import org.joda.time.DateTimeZone;
029:        import org.joda.time.ReadablePartial;
030:
031:        /**
032:         * Factory that creates instances of DateTimeFormatter from patterns and styles.
033:         * <p>
034:         * Datetime formatting is performed by the {@link DateTimeFormatter} class.
035:         * Three classes provide factory methods to create formatters, and this is one.
036:         * The others are {@link ISODateTimeFormat} and {@link DateTimeFormatterBuilder}.
037:         * <p>
038:         * This class provides two types of factory:
039:         * <ul>
040:         * <li>{@link #forPattern(String) Pattern} provides a DateTimeFormatter based on
041:         * a pattern string that is mostly compatible with the JDK date patterns.
042:         * <li>{@link #forStyle(String) Style} provides a DateTimeFormatter based on a
043:         * two character style, representing short, medium, long and full.
044:         * </ul>
045:         * <p>
046:         * For example, to use a patterm:
047:         * <pre>
048:         * DateTime dt = new DateTime();
049:         * DateTimeFormatter fmt = DateTimeFormat.forPattern("MMMM, yyyy");
050:         * String str = fmt.print(dt);
051:         * </pre>
052:         *
053:         * The pattern syntax is mostly compatible with java.text.SimpleDateFormat -
054:         * time zone names cannot be parsed and a few more symbols are supported.
055:         * All ASCII letters are reserved as pattern letters, which are defined as follows:
056:         * <blockquote>
057:         * <pre>
058:         * Symbol  Meaning                      Presentation  Examples
059:         * ------  -------                      ------------  -------
060:         * G       era                          text          AD
061:         * C       century of era (&gt;=0)         number        20
062:         * Y       year of era (&gt;=0)            year          1996
063:         *
064:         * x       weekyear                     year          1996
065:         * w       week of weekyear             number        27
066:         * e       day of week                  number        2
067:         * E       day of week                  text          Tuesday; Tue
068:         *
069:         * y       year                         year          1996
070:         * D       day of year                  number        189
071:         * M       month of year                month         July; Jul; 07
072:         * d       day of month                 number        10
073:         *
074:         * a       halfday of day               text          PM
075:         * K       hour of halfday (0~11)       number        0
076:         * h       clockhour of halfday (1~12)  number        12
077:         *
078:         * H       hour of day (0~23)           number        0
079:         * k       clockhour of day (1~24)      number        24
080:         * m       minute of hour               number        30
081:         * s       second of minute             number        55
082:         * S       fraction of second           number        978
083:         *
084:         * z       time zone                    text          Pacific Standard Time; PST
085:         * Z       time zone offset/id          zone          -0800; -08:00; America/Los_Angeles
086:         *
087:         * '       escape for text              delimiter
088:         * ''      single quote                 literal       '
089:         * </pre>
090:         * </blockquote>
091:         * The count of pattern letters determine the format.
092:         * <p>
093:         * <strong>Text</strong>: If the number of pattern letters is 4 or more,
094:         * the full form is used; otherwise a short or abbreviated form is used if
095:         * available.
096:         * <p>
097:         * <strong>Number</strong>: The minimum number of digits. Shorter numbers
098:         * are zero-padded to this amount.
099:         * <p>
100:         * <strong>Year</strong>: Numeric presentation for year and weekyear fields
101:         * are handled specially. For example, if the count of 'y' is 2, the year
102:         * will be displayed as the zero-based year of the century, which is two
103:         * digits.
104:         * <p>
105:         * <strong>Month</strong>: 3 or over, use text, otherwise use number.
106:         * <p>
107:         * <strong>Zone</strong>: 'Z' outputs offset without a colon, 'ZZ' outputs
108:         * the offset with a colon, 'ZZZ' or more outputs the zone id.
109:         * <p>
110:         * <strong>Zone names</strong>: Time zone names ('z') cannot be parsed.
111:         * <p>
112:         * Any characters in the pattern that are not in the ranges of ['a'..'z']
113:         * and ['A'..'Z'] will be treated as quoted text. For instance, characters
114:         * like ':', '.', ' ', '#' and '?' will appear in the resulting time text
115:         * even they are not embraced within single quotes.
116:         * <p>
117:         * DateTimeFormat is thread-safe and immutable, and the formatters it returns
118:         * are as well.
119:         *
120:         * @author Brian S O'Neill
121:         * @author Maxim Zhao
122:         * @since 1.0
123:         * @see ISODateTimeFormat
124:         * @see DateTimeFormatterBuilder
125:         */
126:        public class DateTimeFormat {
127:
128:            /** Style constant for FULL. */
129:            static final int FULL = 0; // DateFormat.FULL
130:            /** Style constant for LONG. */
131:            static final int LONG = 1; // DateFormat.LONG
132:            /** Style constant for MEDIUM. */
133:            static final int MEDIUM = 2; // DateFormat.MEDIUM
134:            /** Style constant for SHORT. */
135:            static final int SHORT = 3; // DateFormat.SHORT
136:            /** Style constant for NONE. */
137:            static final int NONE = 4;
138:
139:            /** Type constant for DATE only. */
140:            static final int DATE = 0;
141:            /** Type constant for TIME only. */
142:            static final int TIME = 1;
143:            /** Type constant for DATETIME. */
144:            static final int DATETIME = 2;
145:
146:            /** Maps patterns to formatters, patterns don't vary by locale. */
147:            private static final Map cPatternedCache = new HashMap(7);
148:            /** Maps patterns to formatters, patterns don't vary by locale. */
149:            private static final DateTimeFormatter[] cStyleCache = new DateTimeFormatter[25];
150:
151:            //-----------------------------------------------------------------------
152:            /**
153:             * Factory to create a formatter from a pattern string.
154:             * The pattern string is described above in the class level javadoc.
155:             * It is very similar to SimpleDateFormat patterns.
156:             * <p>
157:             * The format may contain locale specific output, and this will change as
158:             * you change the locale of the formatter.
159:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
160:             * For example:
161:             * <pre>
162:             * DateTimeFormat.forPattern(pattern).withLocale(Locale.FRANCE).print(dt);
163:             * </pre>
164:             *
165:             * @param pattern  pattern specification
166:             * @return the formatter
167:             * @throws IllegalArgumentException if the pattern is invalid
168:             */
169:            public static DateTimeFormatter forPattern(String pattern) {
170:                return createFormatterForPattern(pattern);
171:            }
172:
173:            /**
174:             * Factory to create a format from a two character style pattern.
175:             * <p>
176:             * The first character is the date style, and the second character is the
177:             * time style. Specify a character of 'S' for short style, 'M' for medium,
178:             * 'L' for long, and 'F' for full.
179:             * A date or time may be ommitted by specifying a style character '-'.
180:             * <p>
181:             * The returned formatter will dynamically adjust to the locale that
182:             * the print/parse takes place in. Thus you just call
183:             * {@link DateTimeFormatter#withLocale(Locale)} and the Short/Medium/Long/Full
184:             * style for that locale will be output. For example:
185:             * <pre>
186:             * DateTimeFormat.forStyle(style).withLocale(Locale.FRANCE).print(dt);
187:             * </pre>
188:             *
189:             * @param style  two characters from the set {"S", "M", "L", "F", "-"}
190:             * @return the formatter
191:             * @throws IllegalArgumentException if the style is invalid
192:             */
193:            public static DateTimeFormatter forStyle(String style) {
194:                return createFormatterForStyle(style);
195:            }
196:
197:            /**
198:             * Returns the pattern used by a particular style and locale.
199:             * <p>
200:             * The first character is the date style, and the second character is the
201:             * time style. Specify a character of 'S' for short style, 'M' for medium,
202:             * 'L' for long, and 'F' for full.
203:             * A date or time may be ommitted by specifying a style character '-'.
204:             *
205:             * @param style  two characters from the set {"S", "M", "L", "F", "-"}
206:             * @param locale  locale to use, null means default
207:             * @return the formatter
208:             * @throws IllegalArgumentException if the style is invalid
209:             * @since 1.3
210:             */
211:            public static String patternForStyle(String style, Locale locale) {
212:                DateTimeFormatter formatter = createFormatterForStyle(style);
213:                if (locale == null) {
214:                    locale = Locale.getDefault();
215:                }
216:                // Not pretty, but it works.
217:                return ((StyleFormatter) formatter.getPrinter())
218:                        .getPattern(locale);
219:            }
220:
221:            //-----------------------------------------------------------------------
222:            /**
223:             * Creates a format that outputs a short date format.
224:             * <p>
225:             * The format will change as you change the locale of the formatter.
226:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
227:             * 
228:             * @return the formatter
229:             */
230:            public static DateTimeFormatter shortDate() {
231:                return createFormatterForStyleIndex(SHORT, NONE);
232:            }
233:
234:            /**
235:             * Creates a format that outputs a short time format.
236:             * <p>
237:             * The format will change as you change the locale of the formatter.
238:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
239:             * 
240:             * @return the formatter
241:             */
242:            public static DateTimeFormatter shortTime() {
243:                return createFormatterForStyleIndex(NONE, SHORT);
244:            }
245:
246:            /**
247:             * Creates a format that outputs a short datetime format.
248:             * <p>
249:             * The format will change as you change the locale of the formatter.
250:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
251:             * 
252:             * @return the formatter
253:             */
254:            public static DateTimeFormatter shortDateTime() {
255:                return createFormatterForStyleIndex(SHORT, SHORT);
256:            }
257:
258:            //-----------------------------------------------------------------------
259:            /**
260:             * Creates a format that outputs a medium date format.
261:             * <p>
262:             * The format will change as you change the locale of the formatter.
263:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
264:             * 
265:             * @return the formatter
266:             */
267:            public static DateTimeFormatter mediumDate() {
268:                return createFormatterForStyleIndex(MEDIUM, NONE);
269:            }
270:
271:            /**
272:             * Creates a format that outputs a medium time format.
273:             * <p>
274:             * The format will change as you change the locale of the formatter.
275:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
276:             * 
277:             * @return the formatter
278:             */
279:            public static DateTimeFormatter mediumTime() {
280:                return createFormatterForStyleIndex(NONE, MEDIUM);
281:            }
282:
283:            /**
284:             * Creates a format that outputs a medium datetime format.
285:             * <p>
286:             * The format will change as you change the locale of the formatter.
287:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
288:             * 
289:             * @return the formatter
290:             */
291:            public static DateTimeFormatter mediumDateTime() {
292:                return createFormatterForStyleIndex(MEDIUM, MEDIUM);
293:            }
294:
295:            //-----------------------------------------------------------------------
296:            /**
297:             * Creates a format that outputs a long date format.
298:             * <p>
299:             * The format will change as you change the locale of the formatter.
300:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
301:             * 
302:             * @return the formatter
303:             */
304:            public static DateTimeFormatter longDate() {
305:                return createFormatterForStyleIndex(LONG, NONE);
306:            }
307:
308:            /**
309:             * Creates a format that outputs a long time format.
310:             * <p>
311:             * The format will change as you change the locale of the formatter.
312:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
313:             * 
314:             * @return the formatter
315:             */
316:            public static DateTimeFormatter longTime() {
317:                return createFormatterForStyleIndex(NONE, LONG);
318:            }
319:
320:            /**
321:             * Creates a format that outputs a long datetime format.
322:             * <p>
323:             * The format will change as you change the locale of the formatter.
324:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
325:             * 
326:             * @return the formatter
327:             */
328:            public static DateTimeFormatter longDateTime() {
329:                return createFormatterForStyleIndex(LONG, LONG);
330:            }
331:
332:            //-----------------------------------------------------------------------
333:            /**
334:             * Creates a format that outputs a full date format.
335:             * <p>
336:             * The format will change as you change the locale of the formatter.
337:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
338:             * 
339:             * @return the formatter
340:             */
341:            public static DateTimeFormatter fullDate() {
342:                return createFormatterForStyleIndex(FULL, NONE);
343:            }
344:
345:            /**
346:             * Creates a format that outputs a full time format.
347:             * <p>
348:             * The format will change as you change the locale of the formatter.
349:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
350:             * 
351:             * @return the formatter
352:             */
353:            public static DateTimeFormatter fullTime() {
354:                return createFormatterForStyleIndex(NONE, FULL);
355:            }
356:
357:            /**
358:             * Creates a format that outputs a full datetime format.
359:             * <p>
360:             * The format will change as you change the locale of the formatter.
361:             * Call {@link DateTimeFormatter#withLocale(Locale)} to switch the locale.
362:             * 
363:             * @return the formatter
364:             */
365:            public static DateTimeFormatter fullDateTime() {
366:                return createFormatterForStyleIndex(FULL, FULL);
367:            }
368:
369:            //-----------------------------------------------------------------------
370:            /**
371:             * Parses the given pattern and appends the rules to the given
372:             * DateTimeFormatterBuilder.
373:             *
374:             * @param pattern  pattern specification
375:             * @throws IllegalArgumentException if the pattern is invalid
376:             */
377:            static void appendPatternTo(DateTimeFormatterBuilder builder,
378:                    String pattern) {
379:                parsePatternTo(builder, pattern);
380:            }
381:
382:            //-----------------------------------------------------------------------
383:            /**
384:             * Constructor.
385:             *
386:             * @since 1.1 (previously private)
387:             */
388:            protected DateTimeFormat() {
389:                super ();
390:            }
391:
392:            //-----------------------------------------------------------------------
393:            /**
394:             * Parses the given pattern and appends the rules to the given
395:             * DateTimeFormatterBuilder.
396:             *
397:             * @param pattern  pattern specification
398:             * @throws IllegalArgumentException if the pattern is invalid
399:             * @see #forPattern
400:             */
401:            private static void parsePatternTo(
402:                    DateTimeFormatterBuilder builder, String pattern) {
403:                int length = pattern.length();
404:                int[] indexRef = new int[1];
405:
406:                for (int i = 0; i < length; i++) {
407:                    indexRef[0] = i;
408:                    String token = parseToken(pattern, indexRef);
409:                    i = indexRef[0];
410:
411:                    int tokenLen = token.length();
412:                    if (tokenLen == 0) {
413:                        break;
414:                    }
415:                    char c = token.charAt(0);
416:
417:                    switch (c) {
418:                    case 'G': // era designator (text)
419:                        builder.appendEraText();
420:                        break;
421:                    case 'C': // century of era (number)
422:                        builder.appendCenturyOfEra(tokenLen, tokenLen);
423:                        break;
424:                    case 'x': // weekyear (number)
425:                    case 'y': // year (number)
426:                    case 'Y': // year of era (number)
427:                        if (tokenLen == 2) {
428:                            boolean lenientParse = true;
429:
430:                            // Peek ahead to next token.
431:                            if (i + 1 < length) {
432:                                indexRef[0]++;
433:                                if (isNumericToken(parseToken(pattern, indexRef))) {
434:                                    // If next token is a number, cannot support
435:                                    // lenient parse, because it will consume digits
436:                                    // that it should not.
437:                                    lenientParse = false;
438:                                }
439:                                indexRef[0]--;
440:                            }
441:
442:                            // Use pivots which are compatible with SimpleDateFormat.
443:                            switch (c) {
444:                            case 'x':
445:                                builder.appendTwoDigitWeekyear(new DateTime()
446:                                        .getWeekyear() - 30, lenientParse);
447:                                break;
448:                            case 'y':
449:                            case 'Y':
450:                            default:
451:                                builder.appendTwoDigitYear(new DateTime()
452:                                        .getYear() - 30, lenientParse);
453:                                break;
454:                            }
455:                        } else {
456:                            // Try to support long year values.
457:                            int maxDigits = 9;
458:
459:                            // Peek ahead to next token.
460:                            if (i + 1 < length) {
461:                                indexRef[0]++;
462:                                if (isNumericToken(parseToken(pattern, indexRef))) {
463:                                    // If next token is a number, cannot support long years.
464:                                    maxDigits = tokenLen;
465:                                }
466:                                indexRef[0]--;
467:                            }
468:
469:                            switch (c) {
470:                            case 'x':
471:                                builder.appendWeekyear(tokenLen, maxDigits);
472:                                break;
473:                            case 'y':
474:                                builder.appendYear(tokenLen, maxDigits);
475:                                break;
476:                            case 'Y':
477:                                builder.appendYearOfEra(tokenLen, maxDigits);
478:                                break;
479:                            }
480:                        }
481:                        break;
482:                    case 'M': // month of year (text and number)
483:                        if (tokenLen >= 3) {
484:                            if (tokenLen >= 4) {
485:                                builder.appendMonthOfYearText();
486:                            } else {
487:                                builder.appendMonthOfYearShortText();
488:                            }
489:                        } else {
490:                            builder.appendMonthOfYear(tokenLen);
491:                        }
492:                        break;
493:                    case 'd': // day of month (number)
494:                        builder.appendDayOfMonth(tokenLen);
495:                        break;
496:                    case 'a': // am/pm marker (text)
497:                        builder.appendHalfdayOfDayText();
498:                        break;
499:                    case 'h': // clockhour of halfday (number, 1..12)
500:                        builder.appendClockhourOfHalfday(tokenLen);
501:                        break;
502:                    case 'H': // hour of day (number, 0..23)
503:                        builder.appendHourOfDay(tokenLen);
504:                        break;
505:                    case 'k': // clockhour of day (1..24)
506:                        builder.appendClockhourOfDay(tokenLen);
507:                        break;
508:                    case 'K': // hour of halfday (0..11)
509:                        builder.appendHourOfHalfday(tokenLen);
510:                        break;
511:                    case 'm': // minute of hour (number)
512:                        builder.appendMinuteOfHour(tokenLen);
513:                        break;
514:                    case 's': // second of minute (number)
515:                        builder.appendSecondOfMinute(tokenLen);
516:                        break;
517:                    case 'S': // fraction of second (number)
518:                        builder.appendFractionOfSecond(tokenLen, tokenLen);
519:                        break;
520:                    case 'e': // day of week (number)
521:                        builder.appendDayOfWeek(tokenLen);
522:                        break;
523:                    case 'E': // dayOfWeek (text)
524:                        if (tokenLen >= 4) {
525:                            builder.appendDayOfWeekText();
526:                        } else {
527:                            builder.appendDayOfWeekShortText();
528:                        }
529:                        break;
530:                    case 'D': // day of year (number)
531:                        builder.appendDayOfYear(tokenLen);
532:                        break;
533:                    case 'w': // week of weekyear (number)
534:                        builder.appendWeekOfWeekyear(tokenLen);
535:                        break;
536:                    case 'z': // time zone (text)
537:                        if (tokenLen >= 4) {
538:                            builder.appendTimeZoneName();
539:                        } else {
540:                            builder.appendTimeZoneShortName();
541:                        }
542:                        break;
543:                    case 'Z': // time zone offset
544:                        if (tokenLen == 1) {
545:                            builder.appendTimeZoneOffset(null, false, 2, 2);
546:                        } else if (tokenLen == 2) {
547:                            builder.appendTimeZoneOffset(null, true, 2, 2);
548:                        } else {
549:                            builder.appendTimeZoneId();
550:                        }
551:                        break;
552:                    case '\'': // literal text
553:                        String sub = token.substring(1);
554:                        if (sub.length() == 1) {
555:                            builder.appendLiteral(sub.charAt(0));
556:                        } else {
557:                            // Create copy of sub since otherwise the temporary quoted
558:                            // string would still be referenced internally.
559:                            builder.appendLiteral(new String(sub));
560:                        }
561:                        break;
562:                    default:
563:                        throw new IllegalArgumentException(
564:                                "Illegal pattern component: " + token);
565:                    }
566:                }
567:            }
568:
569:            /**
570:             * Parses an individual token.
571:             * 
572:             * @param pattern  the pattern string
573:             * @param indexRef  a single element array, where the input is the start
574:             *  location and the output is the location after parsing the token
575:             * @return the parsed token
576:             */
577:            private static String parseToken(String pattern, int[] indexRef) {
578:                StringBuffer buf = new StringBuffer();
579:
580:                int i = indexRef[0];
581:                int length = pattern.length();
582:
583:                char c = pattern.charAt(i);
584:                if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') {
585:                    // Scan a run of the same character, which indicates a time
586:                    // pattern.
587:                    buf.append(c);
588:
589:                    while (i + 1 < length) {
590:                        char peek = pattern.charAt(i + 1);
591:                        if (peek == c) {
592:                            buf.append(c);
593:                            i++;
594:                        } else {
595:                            break;
596:                        }
597:                    }
598:                } else {
599:                    // This will identify token as text.
600:                    buf.append('\'');
601:
602:                    boolean inLiteral = false;
603:
604:                    for (; i < length; i++) {
605:                        c = pattern.charAt(i);
606:
607:                        if (c == '\'') {
608:                            if (i + 1 < length && pattern.charAt(i + 1) == '\'') {
609:                                // '' is treated as escaped '
610:                                i++;
611:                                buf.append(c);
612:                            } else {
613:                                inLiteral = !inLiteral;
614:                            }
615:                        } else if (!inLiteral
616:                                && (c >= 'A' && c <= 'Z' || c >= 'a'
617:                                        && c <= 'z')) {
618:                            i--;
619:                            break;
620:                        } else {
621:                            buf.append(c);
622:                        }
623:                    }
624:                }
625:
626:                indexRef[0] = i;
627:                return buf.toString();
628:            }
629:
630:            /**
631:             * Returns true if token should be parsed as a numeric field.
632:             * 
633:             * @param token  the token to parse
634:             * @return true if numeric field
635:             */
636:            private static boolean isNumericToken(String token) {
637:                int tokenLen = token.length();
638:                if (tokenLen > 0) {
639:                    char c = token.charAt(0);
640:                    switch (c) {
641:                    case 'c': // century (number)
642:                    case 'C': // century of era (number)
643:                    case 'x': // weekyear (number)
644:                    case 'y': // year (number)
645:                    case 'Y': // year of era (number)
646:                    case 'd': // day of month (number)
647:                    case 'h': // hour of day (number, 1..12)
648:                    case 'H': // hour of day (number, 0..23)
649:                    case 'm': // minute of hour (number)
650:                    case 's': // second of minute (number)
651:                    case 'S': // fraction of second (number)
652:                    case 'e': // day of week (number)
653:                    case 'D': // day of year (number)
654:                    case 'F': // day of week in month (number)
655:                    case 'w': // week of year (number)
656:                    case 'W': // week of month (number)
657:                    case 'k': // hour of day (1..24)
658:                    case 'K': // hour of day (0..11)
659:                        return true;
660:                    case 'M': // month of year (text and number)
661:                        if (tokenLen <= 2) {
662:                            return true;
663:                        }
664:                    }
665:                }
666:
667:                return false;
668:            }
669:
670:            //-----------------------------------------------------------------------
671:            /**
672:             * Select a format from a custom pattern.
673:             *
674:             * @param pattern  pattern specification
675:             * @throws IllegalArgumentException if the pattern is invalid
676:             * @see #appendPatternTo
677:             */
678:            private static DateTimeFormatter createFormatterForPattern(
679:                    String pattern) {
680:                if (pattern == null || pattern.length() == 0) {
681:                    throw new IllegalArgumentException(
682:                            "Invalid pattern specification");
683:                }
684:                DateTimeFormatter formatter = null;
685:                synchronized (cPatternedCache) {
686:                    formatter = (DateTimeFormatter) cPatternedCache
687:                            .get(pattern);
688:                    if (formatter == null) {
689:                        DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
690:                        parsePatternTo(builder, pattern);
691:                        formatter = builder.toFormatter();
692:
693:                        cPatternedCache.put(pattern, formatter);
694:                    }
695:                }
696:                return formatter;
697:            }
698:
699:            /**
700:             * Select a format from a two character style pattern. The first character
701:             * is the date style, and the second character is the time style. Specify a
702:             * character of 'S' for short style, 'M' for medium, 'L' for long, and 'F'
703:             * for full. A date or time may be ommitted by specifying a style character '-'.
704:             *
705:             * @param style  two characters from the set {"S", "M", "L", "F", "-"}
706:             * @throws IllegalArgumentException if the style is invalid
707:             */
708:            private static DateTimeFormatter createFormatterForStyle(
709:                    String style) {
710:                if (style == null || style.length() != 2) {
711:                    throw new IllegalArgumentException(
712:                            "Invalid style specification: " + style);
713:                }
714:                int dateStyle = selectStyle(style.charAt(0));
715:                int timeStyle = selectStyle(style.charAt(1));
716:                if (dateStyle == NONE && timeStyle == NONE) {
717:                    throw new IllegalArgumentException("Style '--' is invalid");
718:                }
719:                return createFormatterForStyleIndex(dateStyle, timeStyle);
720:            }
721:
722:            /**
723:             * Gets the formatter for the specified style.
724:             * 
725:             * @param dateStyle  the date style
726:             * @param timeStyle  the time style
727:             * @return the formatter
728:             */
729:            private static DateTimeFormatter createFormatterForStyleIndex(
730:                    int dateStyle, int timeStyle) {
731:                int index = ((dateStyle << 2) + dateStyle) + timeStyle;
732:                DateTimeFormatter f = null;
733:                synchronized (cStyleCache) {
734:                    f = cStyleCache[index];
735:                    if (f == null) {
736:                        int type = DATETIME;
737:                        if (dateStyle == NONE) {
738:                            type = TIME;
739:                        } else if (timeStyle == NONE) {
740:                            type = DATE;
741:                        }
742:                        StyleFormatter llf = new StyleFormatter(dateStyle,
743:                                timeStyle, type);
744:                        f = new DateTimeFormatter(llf, llf);
745:                        cStyleCache[index] = f;
746:                    }
747:                }
748:                return f;
749:            }
750:
751:            /**
752:             * Gets the JDK style code from the Joda code.
753:             * 
754:             * @param ch  the Joda style code
755:             * @return the JDK style code
756:             */
757:            private static int selectStyle(char ch) {
758:                switch (ch) {
759:                case 'S':
760:                    return SHORT;
761:                case 'M':
762:                    return MEDIUM;
763:                case 'L':
764:                    return LONG;
765:                case 'F':
766:                    return FULL;
767:                case '-':
768:                    return NONE;
769:                default:
770:                    throw new IllegalArgumentException(
771:                            "Invalid style character: " + ch);
772:                }
773:            }
774:
775:            //-----------------------------------------------------------------------
776:            static class StyleFormatter implements  DateTimePrinter,
777:                    DateTimeParser {
778:
779:                private static final Map cCache = new HashMap(); // manual sync
780:
781:                private final int iDateStyle;
782:                private final int iTimeStyle;
783:                private final int iType;
784:
785:                StyleFormatter(int dateStyle, int timeStyle, int type) {
786:                    super ();
787:                    iDateStyle = dateStyle;
788:                    iTimeStyle = timeStyle;
789:                    iType = type;
790:                }
791:
792:                public int estimatePrintedLength() {
793:                    return 40; // guess
794:                }
795:
796:                public void printTo(StringBuffer buf, long instant,
797:                        Chronology chrono, int displayOffset,
798:                        DateTimeZone displayZone, Locale locale) {
799:                    DateTimePrinter p = getFormatter(locale).getPrinter();
800:                    p.printTo(buf, instant, chrono, displayOffset, displayZone,
801:                            locale);
802:                }
803:
804:                public void printTo(Writer out, long instant,
805:                        Chronology chrono, int displayOffset,
806:                        DateTimeZone displayZone, Locale locale)
807:                        throws IOException {
808:                    DateTimePrinter p = getFormatter(locale).getPrinter();
809:                    p.printTo(out, instant, chrono, displayOffset, displayZone,
810:                            locale);
811:                }
812:
813:                public void printTo(StringBuffer buf, ReadablePartial partial,
814:                        Locale locale) {
815:                    DateTimePrinter p = getFormatter(locale).getPrinter();
816:                    p.printTo(buf, partial, locale);
817:                }
818:
819:                public void printTo(Writer out, ReadablePartial partial,
820:                        Locale locale) throws IOException {
821:                    DateTimePrinter p = getFormatter(locale).getPrinter();
822:                    p.printTo(out, partial, locale);
823:                }
824:
825:                public int estimateParsedLength() {
826:                    return 40; // guess
827:                }
828:
829:                public int parseInto(DateTimeParserBucket bucket, String text,
830:                        int position) {
831:                    DateTimeParser p = getFormatter(bucket.getLocale())
832:                            .getParser();
833:                    return p.parseInto(bucket, text, position);
834:                }
835:
836:                private DateTimeFormatter getFormatter(Locale locale) {
837:                    locale = (locale == null ? Locale.getDefault() : locale);
838:                    String key = Integer.toString(iType + (iDateStyle << 4)
839:                            + (iTimeStyle << 8))
840:                            + locale.toString();
841:                    DateTimeFormatter f = null;
842:                    synchronized (cCache) {
843:                        f = (DateTimeFormatter) cCache.get(key);
844:                        if (f == null) {
845:                            String pattern = getPattern(locale);
846:                            f = DateTimeFormat.forPattern(pattern);
847:                            cCache.put(key, f);
848:                        }
849:                    }
850:                    return f;
851:                }
852:
853:                String getPattern(Locale locale) {
854:                    DateFormat f = null;
855:                    switch (iType) {
856:                    case DATE:
857:                        f = DateFormat.getDateInstance(iDateStyle, locale);
858:                        break;
859:                    case TIME:
860:                        f = DateFormat.getTimeInstance(iTimeStyle, locale);
861:                        break;
862:                    case DATETIME:
863:                        f = DateFormat.getDateTimeInstance(iDateStyle,
864:                                iTimeStyle, locale);
865:                        break;
866:                    }
867:                    if (f instanceof  SimpleDateFormat == false) {
868:                        throw new IllegalArgumentException(
869:                                "No datetime pattern for locale: " + locale);
870:                    }
871:                    return ((SimpleDateFormat) f).toPattern();
872:                }
873:            }
874:
875:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.