1 /* |
|
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 /* |
|
27 * This file is available under and governed by the GNU General Public |
|
28 * License version 2 only, as published by the Free Software Foundation. |
|
29 * However, the following notice accompanied the original version of this |
|
30 * file: |
|
31 * |
|
32 * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos |
|
33 * |
|
34 * All rights reserved. |
|
35 * |
|
36 * Redistribution and use in source and binary forms, with or without |
|
37 * modification, are permitted provided that the following conditions are met: |
|
38 * |
|
39 * * Redistributions of source code must retain the above copyright notice, |
|
40 * this list of conditions and the following disclaimer. |
|
41 * |
|
42 * * Redistributions in binary form must reproduce the above copyright notice, |
|
43 * this list of conditions and the following disclaimer in the documentation |
|
44 * and/or other materials provided with the distribution. |
|
45 * |
|
46 * * Neither the name of JSR-310 nor the names of its contributors |
|
47 * may be used to endorse or promote products derived from this software |
|
48 * without specific prior written permission. |
|
49 * |
|
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
54 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
55 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
56 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
57 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
58 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
59 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
61 */ |
|
62 package java.time.format; |
|
63 |
|
64 import static java.time.temporal.ChronoField.DAY_OF_MONTH; |
|
65 import static java.time.temporal.ChronoField.DAY_OF_WEEK; |
|
66 import static java.time.temporal.ChronoField.DAY_OF_YEAR; |
|
67 import static java.time.temporal.ChronoField.HOUR_OF_DAY; |
|
68 import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; |
|
69 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; |
|
70 import static java.time.temporal.ChronoField.NANO_OF_SECOND; |
|
71 import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; |
|
72 import static java.time.temporal.ChronoField.YEAR; |
|
73 |
|
74 import java.time.ZoneId; |
|
75 import java.time.ZoneOffset; |
|
76 import java.time.temporal.ChronoField; |
|
77 import java.time.temporal.ISOFields; |
|
78 import java.util.HashMap; |
|
79 import java.util.Locale; |
|
80 import java.util.Map; |
|
81 import java.util.Objects; |
|
82 |
|
83 /** |
|
84 * Provides common implementations of {@code DateTimeFormatter}. |
|
85 * <p> |
|
86 * This utility class provides three different ways to obtain a formatter. |
|
87 * <p><ul> |
|
88 * <li>Using pattern letters, such as {@code yyyy-MMM-dd} |
|
89 * <li>Using localized styles, such as {@code long} or {@code medium} |
|
90 * <li>Using predefined constants, such as {@code isoLocalDate()} |
|
91 * </ul><p> |
|
92 * |
|
93 * <h3>Specification for implementors</h3> |
|
94 * This is a thread-safe utility class. |
|
95 * All returned formatters are immutable and thread-safe. |
|
96 * |
|
97 * @since 1.8 |
|
98 */ |
|
99 public final class DateTimeFormatters { |
|
100 |
|
101 /** |
|
102 * Private constructor since this is a utility class. |
|
103 */ |
|
104 private DateTimeFormatters() { |
|
105 } |
|
106 |
|
107 //----------------------------------------------------------------------- |
|
108 /** |
|
109 * Creates a formatter using the specified pattern. |
|
110 * <p> |
|
111 * This method will create a formatter based on a simple pattern of letters and symbols. |
|
112 * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'. |
|
113 * <p> |
|
114 * The returned formatter will use the default locale, but this can be changed |
|
115 * using {@link DateTimeFormatter#withLocale(Locale)}. |
|
116 * <p> |
|
117 * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. |
|
118 * The following pattern letters are defined: |
|
119 * <pre> |
|
120 * Symbol Meaning Presentation Examples |
|
121 * ------ ------- ------------ ------- |
|
122 * G era number/text 1; 01; AD; Anno Domini |
|
123 * y year year 2004; 04 |
|
124 * D day-of-year number 189 |
|
125 * M month-of-year number/text 7; 07; Jul; July; J |
|
126 * d day-of-month number 10 |
|
127 * |
|
128 * Q quarter-of-year number/text 3; 03; Q3 |
|
129 * Y week-based-year year 1996; 96 |
|
130 * w week-of-year number 27 |
|
131 * W week-of-month number 27 |
|
132 * e localized day-of-week number 2; Tue; Tuesday; T |
|
133 * E day-of-week number/text 2; Tue; Tuesday; T |
|
134 * F week-of-month number 3 |
|
135 * |
|
136 * a am-pm-of-day text PM |
|
137 * h clock-hour-of-am-pm (1-12) number 12 |
|
138 * K hour-of-am-pm (0-11) number 0 |
|
139 * k clock-hour-of-am-pm (1-24) number 0 |
|
140 * |
|
141 * H hour-of-day (0-23) number 0 |
|
142 * m minute-of-hour number 30 |
|
143 * s second-of-minute number 55 |
|
144 * S fraction-of-second fraction 978 |
|
145 * A milli-of-day number 1234 |
|
146 * n nano-of-second number 987654321 |
|
147 * N nano-of-day number 1234000000 |
|
148 * |
|
149 * I time-zone ID zoneId America/Los_Angeles |
|
150 * z time-zone name text Pacific Standard Time; PST |
|
151 * Z zone-offset offset-Z +0000; -0800; -08:00; |
|
152 * X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15; |
|
153 * |
|
154 * p pad next pad modifier 1 |
|
155 * |
|
156 * ' escape for text delimiter |
|
157 * '' single quote literal ' |
|
158 * [ optional section start |
|
159 * ] optional section end |
|
160 * {} reserved for future use |
|
161 * </pre> |
|
162 * <p> |
|
163 * The count of pattern letters determine the format. |
|
164 * <p> |
|
165 * <b>Text</b>: The text style is determined based on the number of pattern letters used. |
|
166 * Less than 4 pattern letters will use the {@link TextStyle#SHORT short form}. |
|
167 * Exactly 4 pattern letters will use the {@link TextStyle#FULL full form}. |
|
168 * Exactly 5 pattern letters will use the {@link TextStyle#NARROW narrow form}. |
|
169 * <p> |
|
170 * <b>Number</b>: If the count of letters is one, then the value is printed using the minimum number |
|
171 * of digits and without padding as per {@link DateTimeFormatterBuilder#appendValue(java.time.temporal.TemporalField)}. |
|
172 * Otherwise, the count of digits is used as the width of the output field as per |
|
173 * {@link DateTimeFormatterBuilder#appendValue(java.time.temporal.TemporalField, int)}. |
|
174 * <p> |
|
175 * <b>Number/Text</b>: If the count of pattern letters is 3 or greater, use the Text rules above. |
|
176 * Otherwise use the Number rules above. |
|
177 * <p> |
|
178 * <b>Fraction</b>: Outputs the nano-of-second field as a fraction-of-second. |
|
179 * The nano-of-second value has nine digits, thus the count of pattern letters is from 1 to 9. |
|
180 * If it is less than 9, then the nano-of-second value is truncated, with only the most |
|
181 * significant digits being output. |
|
182 * When parsing in strict mode, the number of parsed digits must match the count of pattern letters. |
|
183 * When parsing in lenient mode, the number of parsed digits must be at least the count of pattern |
|
184 * letters, up to 9 digits. |
|
185 * <p> |
|
186 * <b>Year</b>: The count of letters determines the minimum field width below which padding is used. |
|
187 * If the count of letters is two, then a {@link DateTimeFormatterBuilder#appendValueReduced reduced} |
|
188 * two digit form is used. |
|
189 * For printing, this outputs the rightmost two digits. For parsing, this will parse using the |
|
190 * base value of 2000, resulting in a year within the range 2000 to 2099 inclusive. |
|
191 * If the count of letters is less than four (but not two), then the sign is only output for negative |
|
192 * years as per {@link SignStyle#NORMAL}. |
|
193 * Otherwise, the sign is output if the pad width is exceeded, as per {@link SignStyle#EXCEEDS_PAD} |
|
194 * <p> |
|
195 * <b>ZoneId</b>: 'I' outputs the zone ID, such as 'Europe/Paris'. |
|
196 * <p> |
|
197 * <b>Offset X</b>: This formats the offset using 'Z' when the offset is zero. |
|
198 * One letter outputs just the hour', such as '+01' |
|
199 * Two letters outputs the hour and minute, without a colon, such as '+0130'. |
|
200 * Three letters outputs the hour and minute, with a colon, such as '+01:30'. |
|
201 * Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'. |
|
202 * Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'. |
|
203 * <p> |
|
204 * <b>Offset Z</b>: This formats the offset using '+0000' or '+00:00' when the offset is zero. |
|
205 * One or two letters outputs the hour and minute, without a colon, such as '+0130'. |
|
206 * Three letters outputs the hour and minute, with a colon, such as '+01:30'. |
|
207 * <p> |
|
208 * <b>Zone names</b>: Time zone names ('z') cannot be parsed. |
|
209 * <p> |
|
210 * <b>Optional section</b>: The optional section markers work exactly like calling |
|
211 * {@link DateTimeFormatterBuilder#optionalStart()} and {@link DateTimeFormatterBuilder#optionalEnd()}. |
|
212 * <p> |
|
213 * <b>Pad modifier</b>: Modifies the pattern that immediately follows to be padded with spaces. |
|
214 * The pad width is determined by the number of pattern letters. |
|
215 * This is the same as calling {@link DateTimeFormatterBuilder#padNext(int)}. |
|
216 * <p> |
|
217 * For example, 'ppH' outputs the hour-of-day padded on the left with spaces to a width of 2. |
|
218 * <p> |
|
219 * Any unrecognized letter is an error. |
|
220 * Any non-letter character, other than '[', ']', '{', '}' and the single quote will be output directly. |
|
221 * Despite this, it is recommended to use single quotes around all characters that you want to |
|
222 * output directly to ensure that future changes do not break your application. |
|
223 * <p> |
|
224 * The pattern string is similar, but not identical, to {@link java.text.SimpleDateFormat SimpleDateFormat}. |
|
225 * Pattern letters 'E' and 'u' are merged, which changes the meaning of "E" and "EE" to be numeric. |
|
226 * Pattern letters 'Z' and 'X' are extended. |
|
227 * Pattern letter 'y' and 'Y' parse years of two digits and more than 4 digits differently. |
|
228 * Pattern letters 'n', 'A', 'N', 'I' and 'p' are added. |
|
229 * Number types will reject large numbers. |
|
230 * The pattern string is also similar, but not identical, to that defined by the |
|
231 * Unicode Common Locale Data Repository (CLDR). |
|
232 * |
|
233 * @param pattern the pattern to use, not null |
|
234 * @return the formatter based on the pattern, not null |
|
235 * @throws IllegalArgumentException if the pattern is invalid |
|
236 * @see DateTimeFormatterBuilder#appendPattern(String) |
|
237 */ |
|
238 public static DateTimeFormatter pattern(String pattern) { |
|
239 return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(); |
|
240 } |
|
241 |
|
242 /** |
|
243 * Creates a formatter using the specified pattern. |
|
244 * <p> |
|
245 * This method will create a formatter based on a simple pattern of letters and symbols. |
|
246 * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'. |
|
247 * <p> |
|
248 * See {@link #pattern(String)} for details of the pattern. |
|
249 * <p> |
|
250 * The returned formatter will use the specified locale, but this can be changed |
|
251 * using {@link DateTimeFormatter#withLocale(Locale)}. |
|
252 * |
|
253 * @param pattern the pattern to use, not null |
|
254 * @param locale the locale to use, not null |
|
255 * @return the formatter based on the pattern, not null |
|
256 * @throws IllegalArgumentException if the pattern is invalid |
|
257 * @see DateTimeFormatterBuilder#appendPattern(String) |
|
258 */ |
|
259 public static DateTimeFormatter pattern(String pattern, Locale locale) { |
|
260 return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale); |
|
261 } |
|
262 |
|
263 //----------------------------------------------------------------------- |
|
264 /** |
|
265 * Returns a locale specific date format. |
|
266 * <p> |
|
267 * This returns a formatter that will print/parse a date. |
|
268 * The exact format pattern used varies by locale. |
|
269 * <p> |
|
270 * The locale is determined from the formatter. The formatter returned directly by |
|
271 * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}. |
|
272 * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} |
|
273 * on the result of this method. |
|
274 * <p> |
|
275 * Note that the localized pattern is looked up lazily. |
|
276 * This {@code DateTimeFormatter} holds the style required and the locale, |
|
277 * looking up the pattern required on demand. |
|
278 * |
|
279 * @param dateStyle the formatter style to obtain, not null |
|
280 * @return the date formatter, not null |
|
281 */ |
|
282 public static DateTimeFormatter localizedDate(FormatStyle dateStyle) { |
|
283 Objects.requireNonNull(dateStyle, "dateStyle"); |
|
284 return new DateTimeFormatterBuilder().appendLocalized(dateStyle, null).toFormatter(); |
|
285 } |
|
286 |
|
287 /** |
|
288 * Returns a locale specific time format. |
|
289 * <p> |
|
290 * This returns a formatter that will print/parse a time. |
|
291 * The exact format pattern used varies by locale. |
|
292 * <p> |
|
293 * The locale is determined from the formatter. The formatter returned directly by |
|
294 * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}. |
|
295 * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} |
|
296 * on the result of this method. |
|
297 * <p> |
|
298 * Note that the localized pattern is looked up lazily. |
|
299 * This {@code DateTimeFormatter} holds the style required and the locale, |
|
300 * looking up the pattern required on demand. |
|
301 * |
|
302 * @param timeStyle the formatter style to obtain, not null |
|
303 * @return the time formatter, not null |
|
304 */ |
|
305 public static DateTimeFormatter localizedTime(FormatStyle timeStyle) { |
|
306 Objects.requireNonNull(timeStyle, "timeStyle"); |
|
307 return new DateTimeFormatterBuilder().appendLocalized(null, timeStyle).toFormatter(); |
|
308 } |
|
309 |
|
310 /** |
|
311 * Returns a locale specific date-time format, which is typically of short length. |
|
312 * <p> |
|
313 * This returns a formatter that will print/parse a date-time. |
|
314 * The exact format pattern used varies by locale. |
|
315 * <p> |
|
316 * The locale is determined from the formatter. The formatter returned directly by |
|
317 * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}. |
|
318 * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} |
|
319 * on the result of this method. |
|
320 * <p> |
|
321 * Note that the localized pattern is looked up lazily. |
|
322 * This {@code DateTimeFormatter} holds the style required and the locale, |
|
323 * looking up the pattern required on demand. |
|
324 * |
|
325 * @param dateTimeStyle the formatter style to obtain, not null |
|
326 * @return the date-time formatter, not null |
|
327 */ |
|
328 public static DateTimeFormatter localizedDateTime(FormatStyle dateTimeStyle) { |
|
329 Objects.requireNonNull(dateTimeStyle, "dateTimeStyle"); |
|
330 return new DateTimeFormatterBuilder().appendLocalized(dateTimeStyle, dateTimeStyle).toFormatter(); |
|
331 } |
|
332 |
|
333 /** |
|
334 * Returns a locale specific date and time format. |
|
335 * <p> |
|
336 * This returns a formatter that will print/parse a date-time. |
|
337 * The exact format pattern used varies by locale. |
|
338 * <p> |
|
339 * The locale is determined from the formatter. The formatter returned directly by |
|
340 * this method will use the {@link Locale#getDefault() default FORMAT locale}. |
|
341 * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} |
|
342 * on the result of this method. |
|
343 * <p> |
|
344 * Note that the localized pattern is looked up lazily. |
|
345 * This {@code DateTimeFormatter} holds the style required and the locale, |
|
346 * looking up the pattern required on demand. |
|
347 * |
|
348 * @param dateStyle the date formatter style to obtain, not null |
|
349 * @param timeStyle the time formatter style to obtain, not null |
|
350 * @return the date, time or date-time formatter, not null |
|
351 */ |
|
352 public static DateTimeFormatter localizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle) { |
|
353 Objects.requireNonNull(dateStyle, "dateStyle"); |
|
354 Objects.requireNonNull(timeStyle, "timeStyle"); |
|
355 return new DateTimeFormatterBuilder().appendLocalized(dateStyle, timeStyle).toFormatter(); |
|
356 } |
|
357 |
|
358 //----------------------------------------------------------------------- |
|
359 /** |
|
360 * Returns the ISO date formatter that prints/parses a date without an offset, |
|
361 * such as '2011-12-03'. |
|
362 * <p> |
|
363 * This returns an immutable formatter capable of printing and parsing |
|
364 * the ISO-8601 extended local date format. |
|
365 * The format consists of: |
|
366 * <p><ul> |
|
367 * <li>Four digits or more for the {@link ChronoField#YEAR year}. |
|
368 * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. |
|
369 * Years outside that range will have a prefixed positive or negative symbol. |
|
370 * <li>A dash |
|
371 * <li>Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}. |
|
372 * This is pre-padded by zero to ensure two digits. |
|
373 * <li>A dash |
|
374 * <li>Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. |
|
375 * This is pre-padded by zero to ensure two digits. |
|
376 * </ul><p> |
|
377 * |
|
378 * @return the ISO local date formatter, not null |
|
379 */ |
|
380 public static DateTimeFormatter isoLocalDate() { |
|
381 return ISO_LOCAL_DATE; |
|
382 } |
|
383 |
|
384 /** Singleton date formatter. */ |
|
385 private static final DateTimeFormatter ISO_LOCAL_DATE; |
|
386 static { |
|
387 ISO_LOCAL_DATE = new DateTimeFormatterBuilder() |
|
388 .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) |
|
389 .appendLiteral('-') |
|
390 .appendValue(MONTH_OF_YEAR, 2) |
|
391 .appendLiteral('-') |
|
392 .appendValue(DAY_OF_MONTH, 2) |
|
393 .toFormatter(); |
|
394 } |
|
395 |
|
396 //----------------------------------------------------------------------- |
|
397 /** |
|
398 * Returns the ISO date formatter that prints/parses a date with an offset, |
|
399 * such as '2011-12-03+01:00'. |
|
400 * <p> |
|
401 * This returns an immutable formatter capable of printing and parsing |
|
402 * the ISO-8601 extended offset date format. |
|
403 * The format consists of: |
|
404 * <p><ul> |
|
405 * <li>The {@link #isoLocalDate()} |
|
406 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then |
|
407 * they will be handled even though this is not part of the ISO-8601 standard. |
|
408 * Parsing is case insensitive. |
|
409 * </ul><p> |
|
410 * |
|
411 * @return the ISO offset date formatter, not null |
|
412 */ |
|
413 public static DateTimeFormatter isoOffsetDate() { |
|
414 return ISO_OFFSET_DATE; |
|
415 } |
|
416 |
|
417 /** Singleton date formatter. */ |
|
418 private static final DateTimeFormatter ISO_OFFSET_DATE; |
|
419 static { |
|
420 ISO_OFFSET_DATE = new DateTimeFormatterBuilder() |
|
421 .parseCaseInsensitive() |
|
422 .append(ISO_LOCAL_DATE) |
|
423 .appendOffsetId() |
|
424 .toFormatter(); |
|
425 } |
|
426 |
|
427 //----------------------------------------------------------------------- |
|
428 /** |
|
429 * Returns the ISO date formatter that prints/parses a date with the |
|
430 * offset if available, such as '2011-12-03' or '2011-12-03+01:00'. |
|
431 * <p> |
|
432 * This returns an immutable formatter capable of printing and parsing |
|
433 * the ISO-8601 extended date format. |
|
434 * The format consists of: |
|
435 * <p><ul> |
|
436 * <li>The {@link #isoLocalDate()} |
|
437 * <li>If the offset is not available to print/parse then the format is complete. |
|
438 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then |
|
439 * they will be handled even though this is not part of the ISO-8601 standard. |
|
440 * Parsing is case insensitive. |
|
441 * </ul><p> |
|
442 * As this formatter has an optional element, it may be necessary to parse using |
|
443 * {@link DateTimeFormatter#parseBest}. |
|
444 * |
|
445 * @return the ISO date formatter, not null |
|
446 */ |
|
447 public static DateTimeFormatter isoDate() { |
|
448 return ISO_DATE; |
|
449 } |
|
450 |
|
451 /** Singleton date formatter. */ |
|
452 private static final DateTimeFormatter ISO_DATE; |
|
453 static { |
|
454 ISO_DATE = new DateTimeFormatterBuilder() |
|
455 .parseCaseInsensitive() |
|
456 .append(ISO_LOCAL_DATE) |
|
457 .optionalStart() |
|
458 .appendOffsetId() |
|
459 .toFormatter(); |
|
460 } |
|
461 |
|
462 //----------------------------------------------------------------------- |
|
463 /** |
|
464 * Returns the ISO time formatter that prints/parses a time without an offset, |
|
465 * such as '10:15' or '10:15:30'. |
|
466 * <p> |
|
467 * This returns an immutable formatter capable of printing and parsing |
|
468 * the ISO-8601 extended local time format. |
|
469 * The format consists of: |
|
470 * <p><ul> |
|
471 * <li>Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}. |
|
472 * This is pre-padded by zero to ensure two digits. |
|
473 * <li>A colon |
|
474 * <li>Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}. |
|
475 * This is pre-padded by zero to ensure two digits. |
|
476 * <li>If the second-of-minute is not available to print/parse then the format is complete. |
|
477 * <li>A colon |
|
478 * <li>Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}. |
|
479 * This is pre-padded by zero to ensure two digits. |
|
480 * <li>If the nano-of-second is zero or not available to print/parse then the format is complete. |
|
481 * <li>A decimal point |
|
482 * <li>One to nine digits for the {@link ChronoField#NANO_OF_SECOND nano-of-second}. |
|
483 * As many digits will be printed as required. |
|
484 * </ul><p> |
|
485 * |
|
486 * @return the ISO local time formatter, not null |
|
487 */ |
|
488 public static DateTimeFormatter isoLocalTime() { |
|
489 return ISO_LOCAL_TIME; |
|
490 } |
|
491 |
|
492 /** Singleton date formatter. */ |
|
493 private static final DateTimeFormatter ISO_LOCAL_TIME; |
|
494 static { |
|
495 ISO_LOCAL_TIME = new DateTimeFormatterBuilder() |
|
496 .appendValue(HOUR_OF_DAY, 2) |
|
497 .appendLiteral(':') |
|
498 .appendValue(MINUTE_OF_HOUR, 2) |
|
499 .optionalStart() |
|
500 .appendLiteral(':') |
|
501 .appendValue(SECOND_OF_MINUTE, 2) |
|
502 .optionalStart() |
|
503 .appendFraction(NANO_OF_SECOND, 0, 9, true) |
|
504 .toFormatter(); |
|
505 } |
|
506 |
|
507 //----------------------------------------------------------------------- |
|
508 /** |
|
509 * Returns the ISO time formatter that prints/parses a time with an offset, |
|
510 * such as '10:15+01:00' or '10:15:30+01:00'. |
|
511 * <p> |
|
512 * This returns an immutable formatter capable of printing and parsing |
|
513 * the ISO-8601 extended offset time format. |
|
514 * The format consists of: |
|
515 * <p><ul> |
|
516 * <li>The {@link #isoLocalTime()} |
|
517 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then |
|
518 * they will be handled even though this is not part of the ISO-8601 standard. |
|
519 * Parsing is case insensitive. |
|
520 * </ul><p> |
|
521 * |
|
522 * @return the ISO offset time formatter, not null |
|
523 */ |
|
524 public static DateTimeFormatter isoOffsetTime() { |
|
525 return ISO_OFFSET_TIME; |
|
526 } |
|
527 |
|
528 /** Singleton date formatter. */ |
|
529 private static final DateTimeFormatter ISO_OFFSET_TIME; |
|
530 static { |
|
531 ISO_OFFSET_TIME = new DateTimeFormatterBuilder() |
|
532 .parseCaseInsensitive() |
|
533 .append(ISO_LOCAL_TIME) |
|
534 .appendOffsetId() |
|
535 .toFormatter(); |
|
536 } |
|
537 |
|
538 //----------------------------------------------------------------------- |
|
539 /** |
|
540 * Returns the ISO time formatter that prints/parses a time, with the |
|
541 * offset if available, such as '10:15', '10:15:30' or '10:15:30+01:00'. |
|
542 * <p> |
|
543 * This returns an immutable formatter capable of printing and parsing |
|
544 * the ISO-8601 extended offset time format. |
|
545 * The format consists of: |
|
546 * <p><ul> |
|
547 * <li>The {@link #isoLocalTime()} |
|
548 * <li>If the offset is not available to print/parse then the format is complete. |
|
549 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then |
|
550 * they will be handled even though this is not part of the ISO-8601 standard. |
|
551 * Parsing is case insensitive. |
|
552 * </ul><p> |
|
553 * As this formatter has an optional element, it may be necessary to parse using |
|
554 * {@link DateTimeFormatter#parseBest}. |
|
555 * |
|
556 * @return the ISO time formatter, not null |
|
557 */ |
|
558 public static DateTimeFormatter isoTime() { |
|
559 return ISO_TIME; |
|
560 } |
|
561 |
|
562 /** Singleton date formatter. */ |
|
563 private static final DateTimeFormatter ISO_TIME; |
|
564 static { |
|
565 ISO_TIME = new DateTimeFormatterBuilder() |
|
566 .parseCaseInsensitive() |
|
567 .append(ISO_LOCAL_TIME) |
|
568 .optionalStart() |
|
569 .appendOffsetId() |
|
570 .toFormatter(); |
|
571 } |
|
572 |
|
573 //----------------------------------------------------------------------- |
|
574 /** |
|
575 * Returns the ISO date formatter that prints/parses a date-time |
|
576 * without an offset, such as '2011-12-03T10:15:30'. |
|
577 * <p> |
|
578 * This returns an immutable formatter capable of printing and parsing |
|
579 * the ISO-8601 extended offset date-time format. |
|
580 * The format consists of: |
|
581 * <p><ul> |
|
582 * <li>The {@link #isoLocalDate()} |
|
583 * <li>The letter 'T'. Parsing is case insensitive. |
|
584 * <li>The {@link #isoLocalTime()} |
|
585 * </ul><p> |
|
586 * |
|
587 * @return the ISO local date-time formatter, not null |
|
588 */ |
|
589 public static DateTimeFormatter isoLocalDateTime() { |
|
590 return ISO_LOCAL_DATE_TIME; |
|
591 } |
|
592 |
|
593 /** Singleton date formatter. */ |
|
594 private static final DateTimeFormatter ISO_LOCAL_DATE_TIME; |
|
595 static { |
|
596 ISO_LOCAL_DATE_TIME = new DateTimeFormatterBuilder() |
|
597 .parseCaseInsensitive() |
|
598 .append(ISO_LOCAL_DATE) |
|
599 .appendLiteral('T') |
|
600 .append(ISO_LOCAL_TIME) |
|
601 .toFormatter(); |
|
602 } |
|
603 |
|
604 //----------------------------------------------------------------------- |
|
605 /** |
|
606 * Returns the ISO date formatter that prints/parses a date-time |
|
607 * with an offset, such as '2011-12-03T10:15:30+01:00'. |
|
608 * <p> |
|
609 * This returns an immutable formatter capable of printing and parsing |
|
610 * the ISO-8601 extended offset date-time format. |
|
611 * The format consists of: |
|
612 * <p><ul> |
|
613 * <li>The {@link #isoLocalDateTime()} |
|
614 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then |
|
615 * they will be handled even though this is not part of the ISO-8601 standard. |
|
616 * Parsing is case insensitive. |
|
617 * </ul><p> |
|
618 * |
|
619 * @return the ISO offset date-time formatter, not null |
|
620 */ |
|
621 public static DateTimeFormatter isoOffsetDateTime() { |
|
622 return ISO_OFFSET_DATE_TIME; |
|
623 } |
|
624 |
|
625 /** Singleton date formatter. */ |
|
626 private static final DateTimeFormatter ISO_OFFSET_DATE_TIME; |
|
627 static { |
|
628 ISO_OFFSET_DATE_TIME = new DateTimeFormatterBuilder() |
|
629 .parseCaseInsensitive() |
|
630 .append(ISO_LOCAL_DATE_TIME) |
|
631 .appendOffsetId() |
|
632 .toFormatter(); |
|
633 } |
|
634 |
|
635 //----------------------------------------------------------------------- |
|
636 /** |
|
637 * Returns the ISO date formatter that prints/parses a date-time with |
|
638 * offset and zone, such as '2011-12-03T10:15:30+01:00[Europe/Paris]'. |
|
639 * <p> |
|
640 * This returns an immutable formatter capable of printing and parsing |
|
641 * a format that extends the ISO-8601 extended offset date-time format |
|
642 * to add the time-zone. |
|
643 * The format consists of: |
|
644 * <p><ul> |
|
645 * <li>The {@link #isoOffsetDateTime()} |
|
646 * <li>If the zone ID is not available or is a {@code ZoneOffset} then the format is complete. |
|
647 * <li>An open square bracket '['. |
|
648 * <li>The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard. |
|
649 * Parsing is case sensitive. |
|
650 * <li>A close square bracket ']'. |
|
651 * </ul><p> |
|
652 * |
|
653 * @return the ISO zoned date-time formatter, not null |
|
654 */ |
|
655 public static DateTimeFormatter isoZonedDateTime() { |
|
656 return ISO_ZONED_DATE_TIME; |
|
657 } |
|
658 |
|
659 /** Singleton date formatter. */ |
|
660 private static final DateTimeFormatter ISO_ZONED_DATE_TIME; |
|
661 static { |
|
662 ISO_ZONED_DATE_TIME = new DateTimeFormatterBuilder() |
|
663 .append(ISO_OFFSET_DATE_TIME) |
|
664 .optionalStart() |
|
665 .appendLiteral('[') |
|
666 .parseCaseSensitive() |
|
667 .appendZoneRegionId() |
|
668 .appendLiteral(']') |
|
669 .toFormatter(); |
|
670 } |
|
671 |
|
672 //----------------------------------------------------------------------- |
|
673 /** |
|
674 * Returns the ISO date formatter that prints/parses a date-time |
|
675 * with the offset and zone if available, such as '2011-12-03T10:15:30', |
|
676 * '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]'. |
|
677 * <p> |
|
678 * This returns an immutable formatter capable of printing and parsing |
|
679 * the ISO-8601 extended offset date-time format. |
|
680 * The format consists of: |
|
681 * <p><ul> |
|
682 * <li>The {@link #isoLocalDateTime()} |
|
683 * <li>If the offset is not available to print/parse then the format is complete. |
|
684 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then |
|
685 * they will be handled even though this is not part of the ISO-8601 standard. |
|
686 * <li>If the zone ID is not available or is a {@code ZoneOffset} then the format is complete. |
|
687 * <li>An open square bracket '['. |
|
688 * <li>The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard. |
|
689 * Parsing is case sensitive. |
|
690 * <li>A close square bracket ']'. |
|
691 * </ul><p> |
|
692 * As this formatter has an optional element, it may be necessary to parse using |
|
693 * {@link DateTimeFormatter#parseBest}. |
|
694 * |
|
695 * @return the ISO date-time formatter, not null |
|
696 */ |
|
697 public static DateTimeFormatter isoDateTime() { |
|
698 return ISO_DATE_TIME; |
|
699 } |
|
700 |
|
701 /** Singleton date formatter. */ |
|
702 private static final DateTimeFormatter ISO_DATE_TIME; |
|
703 static { |
|
704 ISO_DATE_TIME = new DateTimeFormatterBuilder() |
|
705 .append(ISO_LOCAL_DATE_TIME) |
|
706 .optionalStart() |
|
707 .appendOffsetId() |
|
708 .optionalStart() |
|
709 .appendLiteral('[') |
|
710 .parseCaseSensitive() |
|
711 .appendZoneRegionId() |
|
712 .appendLiteral(']') |
|
713 .toFormatter(); |
|
714 } |
|
715 |
|
716 //----------------------------------------------------------------------- |
|
717 /** |
|
718 * Returns the ISO date formatter that prints/parses the ordinal date |
|
719 * without an offset, such as '2012-337'. |
|
720 * <p> |
|
721 * This returns an immutable formatter capable of printing and parsing |
|
722 * the ISO-8601 extended ordinal date format. |
|
723 * The format consists of: |
|
724 * <p><ul> |
|
725 * <li>Four digits or more for the {@link ChronoField#YEAR year}. |
|
726 * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. |
|
727 * Years outside that range will have a prefixed positive or negative symbol. |
|
728 * <li>A dash |
|
729 * <li>Three digits for the {@link ChronoField#DAY_OF_YEAR day-of-year}. |
|
730 * This is pre-padded by zero to ensure three digits. |
|
731 * <li>If the offset is not available to print/parse then the format is complete. |
|
732 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then |
|
733 * they will be handled even though this is not part of the ISO-8601 standard. |
|
734 * Parsing is case insensitive. |
|
735 * </ul><p> |
|
736 * As this formatter has an optional element, it may be necessary to parse using |
|
737 * {@link DateTimeFormatter#parseBest}. |
|
738 * |
|
739 * @return the ISO ordinal date formatter, not null |
|
740 */ |
|
741 public static DateTimeFormatter isoOrdinalDate() { |
|
742 return ISO_ORDINAL_DATE; |
|
743 } |
|
744 |
|
745 /** Singleton date formatter. */ |
|
746 private static final DateTimeFormatter ISO_ORDINAL_DATE; |
|
747 static { |
|
748 ISO_ORDINAL_DATE = new DateTimeFormatterBuilder() |
|
749 .parseCaseInsensitive() |
|
750 .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) |
|
751 .appendLiteral('-') |
|
752 .appendValue(DAY_OF_YEAR, 3) |
|
753 .optionalStart() |
|
754 .appendOffsetId() |
|
755 .toFormatter(); |
|
756 } |
|
757 |
|
758 //----------------------------------------------------------------------- |
|
759 /** |
|
760 * Returns the ISO date formatter that prints/parses the week-based date |
|
761 * without an offset, such as '2012-W48-6'. |
|
762 * <p> |
|
763 * This returns an immutable formatter capable of printing and parsing |
|
764 * the ISO-8601 extended week-based date format. |
|
765 * The format consists of: |
|
766 * <p><ul> |
|
767 * <li>Four digits or more for the {@link ISOFields#WEEK_BASED_YEAR week-based-year}. |
|
768 * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. |
|
769 * Years outside that range will have a prefixed positive or negative symbol. |
|
770 * <li>A dash |
|
771 * <li>The letter 'W'. Parsing is case insensitive. |
|
772 * <li>Two digits for the {@link ISOFields#WEEK_OF_WEEK_BASED_YEAR week-of-week-based-year}. |
|
773 * This is pre-padded by zero to ensure three digits. |
|
774 * <li>A dash |
|
775 * <li>One digit for the {@link ChronoField#DAY_OF_WEEK day-of-week}. |
|
776 * The value run from Monday (1) to Sunday (7). |
|
777 * <li>If the offset is not available to print/parse then the format is complete. |
|
778 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then |
|
779 * they will be handled even though this is not part of the ISO-8601 standard. |
|
780 * Parsing is case insensitive. |
|
781 * </ul><p> |
|
782 * As this formatter has an optional element, it may be necessary to parse using |
|
783 * {@link DateTimeFormatter#parseBest}. |
|
784 * |
|
785 * @return the ISO week-based date formatter, not null |
|
786 */ |
|
787 public static DateTimeFormatter isoWeekDate() { |
|
788 return ISO_WEEK_DATE; |
|
789 } |
|
790 |
|
791 /** Singleton date formatter. */ |
|
792 private static final DateTimeFormatter ISO_WEEK_DATE; |
|
793 static { |
|
794 ISO_WEEK_DATE = new DateTimeFormatterBuilder() |
|
795 .parseCaseInsensitive() |
|
796 .appendValue(ISOFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD) |
|
797 .appendLiteral("-W") |
|
798 .appendValue(ISOFields.WEEK_OF_WEEK_BASED_YEAR, 2) |
|
799 .appendLiteral('-') |
|
800 .appendValue(DAY_OF_WEEK, 1) |
|
801 .optionalStart() |
|
802 .appendOffsetId() |
|
803 .toFormatter(); |
|
804 } |
|
805 |
|
806 //----------------------------------------------------------------------- |
|
807 /** |
|
808 * Returns the ISO instant formatter that prints/parses an instant in UTC. |
|
809 * <p> |
|
810 * This returns an immutable formatter capable of printing and parsing |
|
811 * the ISO-8601 instant format. |
|
812 * The format consists of: |
|
813 * <p><ul> |
|
814 * <li>The {@link #isoOffsetDateTime()} where the instant is converted from |
|
815 * {@link ChronoField#INSTANT_SECONDS} and {@link ChronoField#NANO_OF_SECOND} |
|
816 * using the {@code UTC} offset. Parsing is case insensitive. |
|
817 * </ul><p> |
|
818 * |
|
819 * @return the ISO instant formatter, not null |
|
820 */ |
|
821 public static DateTimeFormatter isoInstant() { |
|
822 return ISO_INSTANT; |
|
823 } |
|
824 |
|
825 /** Singleton formatter. */ |
|
826 private static final DateTimeFormatter ISO_INSTANT; |
|
827 static { |
|
828 ISO_INSTANT = new DateTimeFormatterBuilder() |
|
829 .parseCaseInsensitive() |
|
830 .appendInstant() |
|
831 .toFormatter(); |
|
832 } |
|
833 |
|
834 //----------------------------------------------------------------------- |
|
835 /** |
|
836 * Returns the ISO date formatter that prints/parses a date without an offset, |
|
837 * such as '20111203'. |
|
838 * <p> |
|
839 * This returns an immutable formatter capable of printing and parsing |
|
840 * the ISO-8601 basic local date format. |
|
841 * The format consists of: |
|
842 * <p><ul> |
|
843 * <li>Four digits for the {@link ChronoField#YEAR year}. |
|
844 * Only years in the range 0000 to 9999 are supported. |
|
845 * <li>Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}. |
|
846 * This is pre-padded by zero to ensure two digits. |
|
847 * <li>Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. |
|
848 * This is pre-padded by zero to ensure two digits. |
|
849 * <li>If the offset is not available to print/parse then the format is complete. |
|
850 * <li>The {@link ZoneOffset#getId() offset ID} without colons. If the offset has |
|
851 * seconds then they will be handled even though this is not part of the ISO-8601 standard. |
|
852 * Parsing is case insensitive. |
|
853 * </ul><p> |
|
854 * As this formatter has an optional element, it may be necessary to parse using |
|
855 * {@link DateTimeFormatter#parseBest}. |
|
856 * |
|
857 * @return the ISO basic local date formatter, not null |
|
858 */ |
|
859 public static DateTimeFormatter basicIsoDate() { |
|
860 return BASIC_ISO_DATE; |
|
861 } |
|
862 |
|
863 /** Singleton date formatter. */ |
|
864 private static final DateTimeFormatter BASIC_ISO_DATE; |
|
865 static { |
|
866 BASIC_ISO_DATE = new DateTimeFormatterBuilder() |
|
867 .parseCaseInsensitive() |
|
868 .appendValue(YEAR, 4) |
|
869 .appendValue(MONTH_OF_YEAR, 2) |
|
870 .appendValue(DAY_OF_MONTH, 2) |
|
871 .optionalStart() |
|
872 .appendOffset("+HHMMss", "Z") |
|
873 .toFormatter(); |
|
874 } |
|
875 |
|
876 //----------------------------------------------------------------------- |
|
877 /** |
|
878 * Returns the RFC-1123 date-time formatter, such as 'Tue, 3 Jun 2008 11:05:30 GMT'. |
|
879 * <p> |
|
880 * This returns an immutable formatter capable of printing and parsing |
|
881 * most of the RFC-1123 format. |
|
882 * RFC-1123 updates RFC-822 changing the year from two digits to four. |
|
883 * This implementation requires a four digit year. |
|
884 * This implementation also does not handle North American or military zone |
|
885 * names, only 'GMT' and offset amounts. |
|
886 * <p> |
|
887 * The format consists of: |
|
888 * <p><ul> |
|
889 * <li>If the day-of-week is not available to print/parse then jump to day-of-month. |
|
890 * <li>Three letter {@link ChronoField#DAY_OF_WEEK day-of-week} in English. |
|
891 * <li>A comma |
|
892 * <li>A space |
|
893 * <li>One or two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. |
|
894 * <li>A space |
|
895 * <li>Three letter {@link ChronoField#MONTH_OF_YEAR month-of-year} in English. |
|
896 * <li>A space |
|
897 * <li>Four digits for the {@link ChronoField#YEAR year}. |
|
898 * Only years in the range 0000 to 9999 are supported. |
|
899 * <li>A space |
|
900 * <li>Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}. |
|
901 * This is pre-padded by zero to ensure two digits. |
|
902 * <li>A colon |
|
903 * <li>Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}. |
|
904 * This is pre-padded by zero to ensure two digits. |
|
905 * <li>If the second-of-minute is not available to print/parse then jump to the next space. |
|
906 * <li>A colon |
|
907 * <li>Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}. |
|
908 * This is pre-padded by zero to ensure two digits. |
|
909 * <li>A space |
|
910 * <li>The {@link ZoneOffset#getId() offset ID} without colons or seconds. |
|
911 * An offset of zero uses "GMT". North American zone names and military zone names are not handled. |
|
912 * </ul><p> |
|
913 * Parsing is case insensitive. |
|
914 * |
|
915 * @return the RFC-1123 formatter, not null |
|
916 */ |
|
917 public static DateTimeFormatter rfc1123() { |
|
918 return RFC_1123_DATE_TIME; |
|
919 } |
|
920 |
|
921 /** Singleton date formatter. */ |
|
922 private static final DateTimeFormatter RFC_1123_DATE_TIME; |
|
923 static { |
|
924 // manually code maps to ensure correct data always used |
|
925 // (locale data can be changed by application code) |
|
926 Map<Long, String> dow = new HashMap<>(); |
|
927 dow.put(1L, "Mon"); |
|
928 dow.put(2L, "Tue"); |
|
929 dow.put(3L, "Wed"); |
|
930 dow.put(4L, "Thu"); |
|
931 dow.put(5L, "Fri"); |
|
932 dow.put(6L, "Sat"); |
|
933 dow.put(7L, "Sun"); |
|
934 Map<Long, String> moy = new HashMap<>(); |
|
935 moy.put(1L, "Jan"); |
|
936 moy.put(2L, "Feb"); |
|
937 moy.put(3L, "Mar"); |
|
938 moy.put(4L, "Apr"); |
|
939 moy.put(5L, "May"); |
|
940 moy.put(6L, "Jun"); |
|
941 moy.put(7L, "Jul"); |
|
942 moy.put(8L, "Aug"); |
|
943 moy.put(9L, "Sep"); |
|
944 moy.put(10L, "Oct"); |
|
945 moy.put(11L, "Nov"); |
|
946 moy.put(12L, "Dec"); |
|
947 RFC_1123_DATE_TIME = new DateTimeFormatterBuilder() |
|
948 .parseCaseInsensitive() |
|
949 .parseLenient() |
|
950 .optionalStart() |
|
951 .appendText(DAY_OF_WEEK, dow) |
|
952 .appendLiteral(", ") |
|
953 .optionalEnd() |
|
954 .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE) |
|
955 .appendLiteral(' ') |
|
956 .appendText(MONTH_OF_YEAR, moy) |
|
957 .appendLiteral(' ') |
|
958 .appendValue(YEAR, 4) // 2 digit year not handled |
|
959 .appendLiteral(' ') |
|
960 .appendValue(HOUR_OF_DAY, 2) |
|
961 .appendLiteral(':') |
|
962 .appendValue(MINUTE_OF_HOUR, 2) |
|
963 .optionalStart() |
|
964 .appendLiteral(':') |
|
965 .appendValue(SECOND_OF_MINUTE, 2) |
|
966 .optionalEnd() |
|
967 .appendLiteral(' ') |
|
968 .appendOffset("+HHMM", "GMT") // should handle UT/Z/EST/EDT/CST/CDT/MST/MDT/PST/MDT |
|
969 .toFormatter(); |
|
970 } |
|
971 |
|
972 } |
|