1 /*
2  * hunt-time: A time library for D programming language.
3  *
4  * Copyright (C) 2015-2018 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.time.format.DateTimeFormatter;
13 
14 import hunt.time.temporal.ChronoField;
15 
16 import hunt.Exceptions;
17 // import hunt.text.FieldPosition;
18 // import hunt.text.Format;
19 // import hunt.text.ParseException;
20 // import hunt.text.ParsePosition;
21 import hunt.time.Exceptions;
22 import hunt.time.Period;
23 import hunt.time.ZoneId;
24 import hunt.time.ZoneOffset;
25 import hunt.time.chrono.ChronoLocalDateTime;
26 import hunt.time.chrono.Chronology;
27 import hunt.time.chrono.IsoChronology;
28 // import hunt.time.format.DateTimeFormatterBuilder;
29 import hunt.time.temporal.ChronoField;
30 import hunt.time.temporal.IsoFields;
31 import hunt.time.temporal.TemporalAccessor;
32 import hunt.time.temporal.TemporalField;
33 import hunt.time.temporal.TemporalQuery;
34 
35 import hunt.time.text.ParsePosition;
36 import hunt.time.format.DateTimeParseException;
37 import hunt.time.format.DateTimeParseContext;
38 import hunt.time.format.Parsed;
39 import hunt.time.format.SignStyle;
40 import hunt.time.format.DateTimePrintContext;
41 import hunt.time.util.QueryHelper;
42 
43 import hunt.Boolean;
44 import hunt.Long;
45 import hunt.collection;
46 import hunt.util.Appendable;
47 import hunt.util.Common;
48 import hunt.util.Locale;
49 import hunt.util.StringBuilder;
50 
51 import std.algorithm.searching;
52 import std.conv;
53 import std.concurrency : initOnce;
54 
55 // import sun.util.locale.provider.TimeZoneNameUtility;
56 
57 /**
58  * Formatter for printing and parsing date-time objects.
59  * !(p)
60  * This class provides the main application entry point for printing and parsing
61  * and provides common implementations of {@code DateTimeFormatter}:
62  * !(ul)
63  * !(li)Using predefined constants, such as {@link #ISO_LOCAL_DATE}</li>
64  * !(li)Using pattern letters, such as {@code uuuu-MMM-dd}</li>
65  * !(li)Using localized styles, such as {@code long} or {@code medium}</li>
66  * </ul>
67  * !(p)
68  * More complex formatters are provided by
69  * {@link DateTimeFormatterBuilder DateTimeFormatterBuilder}.
70  *
71  * !(p)
72  * The main date-time classes provide two methods - one for formatting,
73  * {@code format(DateTimeFormatter formatter)}, and one for parsing,
74  * {@code parse(string text, DateTimeFormatter formatter)}.
75  * !(p)For example:
76  * !(blockquote)!(pre)
77  *  LocalDate date = LocalDate.now();
78  *  string text = date.format(formatter);
79  *  LocalDate parsedDate = LocalDate.parse(text, formatter);
80  * </pre></blockquote>
81  * !(p)
82  * In addition to the format, formatters can be created with desired Locale,
83  * Chronology, ZoneId, and DecimalStyle.
84  * !(p)
85  * The {@link #withLocale withLocale} method returns a new formatter that
86  * overrides the locale. The locale affects some aspects of formatting and
87  * parsing. For example, the {@link #ofLocalizedDate ofLocalizedDate} provides a
88  * formatter that uses the locale specific date format.
89  * !(p)
90  * The {@link #withChronology withChronology} method returns a new formatter
91  * that overrides the chronology. If overridden, the date-time value is
92  * converted to the chronology before formatting. During parsing the date-time
93  * value is converted to the chronology before it is returned.
94  * !(p)
95  * The {@link #withZone withZone} method returns a new formatter that overrides
96  * the zone. If overridden, the date-time value is converted to a ZonedDateTime
97  * with the requested ZoneId before formatting. During parsing the ZoneId is
98  * applied before the value is returned.
99  * !(p)
100  * The {@link #withDecimalStyle withDecimalStyle} method returns a new formatter that
101  * overrides the {@link DecimalStyle}. The DecimalStyle symbols are used for
102  * formatting and parsing.
103  * !(p)
104  * Some applications may need to use the older {@link Format java.text.Format}
105  * class for formatting. The {@link #toFormat()} method returns an
106  * implementation of {@code java.text.Format}.
107  *
108  * <h3 id="predefined">Predefined Formatters</h3>
109  * <table class="striped" style="text-align:left">
110  * !(caption)Predefined Formatters</caption>
111  * !(thead)
112  * !(tr)
113  * <th scope="col">Formatter</th>
114  * <th scope="col">Description</th>
115  * <th scope="col">Example</th>
116  * </tr>
117  * </thead>
118  * !(tbody)
119  * !(tr)
120  * <th scope="row">{@link #ofLocalizedDate ofLocalizedDate(dateStyle)} </th>
121  * !(td) Formatter with date style from the locale </td>
122  * !(td) '2011-12-03'</td>
123  * </tr>
124  * !(tr)
125  * <th scope="row"> {@link #ofLocalizedTime ofLocalizedTime(timeStyle)} </th>
126  * !(td) Formatter with time style from the locale </td>
127  * !(td) '10:15:30'</td>
128  * </tr>
129  * !(tr)
130  * <th scope="row"> {@link #ofLocalizedDateTime ofLocalizedDateTime(dateTimeStyle)} </th>
131  * !(td) Formatter with a style for date and time from the locale</td>
132  * !(td) '3 Jun 2008 11:05:30'</td>
133  * </tr>
134  * !(tr)
135  * <th scope="row"> {@link #ofLocalizedDateTime ofLocalizedDateTime(dateStyle,timeStyle)}
136  * </th>
137  * !(td) Formatter with date and time styles from the locale </td>
138  * !(td) '3 Jun 2008 11:05'</td>
139  * </tr>
140  * !(tr)
141  * <th scope="row"> {@link #BASIC_ISO_DATE}</th>
142  * !(td)Basic ISO date </td> !(td)'20111203'</td>
143  * </tr>
144  * !(tr)
145  * <th scope="row"> {@link #ISO_LOCAL_DATE}</th>
146  * !(td) ISO Local Date </td>
147  * !(td)'2011-12-03'</td>
148  * </tr>
149  * !(tr)
150  * <th scope="row"> {@link #ISO_OFFSET_DATE}</th>
151  * !(td) ISO Date with offset </td>
152  * !(td)'2011-12-03+01:00'</td>
153  * </tr>
154  * !(tr)
155  * <th scope="row"> {@link #ISO_DATE}</th>
156  * !(td) ISO Date with or without offset </td>
157  * !(td) '2011-12-03+01:00'; '2011-12-03'</td>
158  * </tr>
159  * !(tr)
160  * <th scope="row"> {@link #ISO_LOCAL_TIME}</th>
161  * !(td) Time without offset </td>
162  * !(td)'10:15:30'</td>
163  * </tr>
164  * !(tr)
165  * <th scope="row"> {@link #ISO_OFFSET_TIME}</th>
166  * !(td) Time with offset </td>
167  * !(td)'10:15:30+01:00'</td>
168  * </tr>
169  * !(tr)
170  * <th scope="row"> {@link #ISO_TIME}</th>
171  * !(td) Time with or without offset </td>
172  * !(td)'10:15:30+01:00'; '10:15:30'</td>
173  * </tr>
174  * !(tr)
175  * <th scope="row"> {@link #ISO_LOCAL_DATE_TIME}</th>
176  * !(td) ISO Local Date and Time </td>
177  * !(td)'2011-12-03T10:15:30'</td>
178  * </tr>
179  * !(tr)
180  * <th scope="row"> {@link #ISO_OFFSET_DATE_TIME}</th>
181  * !(td) Date Time with Offset
182  * </td>!(td)'2011-12-03T10:15:30+01:00'</td>
183  * </tr>
184  * !(tr)
185  * <th scope="row"> {@link #ISO_ZONED_DATE_TIME}</th>
186  * !(td) Zoned Date Time </td>
187  * !(td)'2011-12-03T10:15:30+01:00[Europe/Paris]'</td>
188  * </tr>
189  * !(tr)
190  * <th scope="row"> {@link #ISO_DATE_TIME}</th>
191  * !(td) Date and time with ZoneId </td>
192  * !(td)'2011-12-03T10:15:30+01:00[Europe/Paris]'</td>
193  * </tr>
194  * !(tr)
195  * <th scope="row"> {@link #ISO_ORDINAL_DATE}</th>
196  * !(td) Year and day of year </td>
197  * !(td)'2012-337'</td>
198  * </tr>
199  * !(tr)
200  * <th scope="row"> {@link #ISO_WEEK_DATE}</th>
201  * !(td) Year and Week </td>
202  * !(td)'2012-W48-6'</td></tr>
203  * !(tr)
204  * <th scope="row"> {@link #ISO_INSTANT}</th>
205  * !(td) Date and Time of an Instant </td>
206  * !(td)'2011-12-03T10:15:30Z' </td>
207  * </tr>
208  * !(tr)
209  * <th scope="row"> {@link #RFC_1123_DATE_TIME}</th>
210  * !(td) RFC 1123 / RFC 822 </td>
211  * !(td)'Tue, 3 Jun 2008 11:05:30 GMT'</td>
212  * </tr>
213  * </tbody>
214  * </table>
215  *
216  * <h3 id="patterns">Patterns for Formatting and Parsing</h3>
217  * Patterns are based on a simple sequence of letters and symbols.
218  * A pattern is used to create a Formatter using the
219  * {@link #ofPattern(string)} and {@link #ofPattern(string, Locale)} methods.
220  * For example,
221  * {@code "d MMM uuuu"} will format 2011-12-03 as '3&nbsp;Dec&nbsp;2011'.
222  * A formatter created from a pattern can be used as many times as necessary,
223  * it is immutable and is thread-safe.
224  * !(p)
225  * For example:
226  * !(blockquote)!(pre)
227  *  LocalDate date = LocalDate.now();
228  *  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
229  *  string text = date.format(formatter);
230  *  LocalDate parsedDate = LocalDate.parse(text, formatter);
231  * </pre></blockquote>
232  * !(p)
233  * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. The
234  * following pattern letters are defined:
235  * <table class="striped">
236  * !(caption)Pattern Letters and Symbols</caption>
237  * !(thead)
238  *  !(tr)<th scope="col">Symbol</th>   <th scope="col">Meaning</th>         <th scope="col">Presentation</th> <th scope="col">Examples</th>
239  * </thead>
240  * !(tbody)
241  *   !(tr)<th scope="row">G</th>       !(td)era</td>                         !(td)text</td>              !(td)AD; Anno Domini; A</td>
242  *   !(tr)<th scope="row">u</th>       !(td)year</td>                        !(td)year</td>              !(td)2004; 04</td>
243  *   !(tr)<th scope="row">y</th>       !(td)year-of-era</td>                 !(td)year</td>              !(td)2004; 04</td>
244  *   !(tr)<th scope="row">D</th>       !(td)day-of-year</td>                 !(td)number</td>            !(td)189</td>
245  *   !(tr)<th scope="row">M/L</th>     !(td)month-of-year</td>               !(td)number/text</td>       !(td)7; 07; Jul; July; J</td>
246  *   !(tr)<th scope="row">d</th>       !(td)day-of-month</td>                !(td)number</td>            !(td)10</td>
247  *   !(tr)<th scope="row">g</th>       !(td)modified-julian-day</td>         !(td)number</td>            !(td)2451334</td>
248  *
249  *   !(tr)<th scope="row">Q/q</th>     !(td)quarter-of-year</td>             !(td)number/text</td>       !(td)3; 03; Q3; 3rd quarter</td>
250  *   !(tr)<th scope="row">Y</th>       !(td)week-based-year</td>             !(td)year</td>              !(td)1996; 96</td>
251  *   !(tr)<th scope="row">w</th>       !(td)week-of-week-based-year</td>     !(td)number</td>            !(td)27</td>
252  *   !(tr)<th scope="row">W</th>       !(td)week-of-month</td>               !(td)number</td>            !(td)4</td>
253  *   !(tr)<th scope="row">E</th>       !(td)day-of-week</td>                 !(td)text</td>              !(td)Tue; Tuesday; T</td>
254  *   !(tr)<th scope="row">e/c</th>     !(td)localized day-of-week</td>       !(td)number/text</td>       !(td)2; 02; Tue; Tuesday; T</td>
255  *   !(tr)<th scope="row">F</th>       !(td)day-of-week-_in-month</td>        !(td)number</td>            !(td)3</td>
256  *
257  *   !(tr)<th scope="row">a</th>       !(td)am-pm-of-day</td>                !(td)text</td>              !(td)PM</td>
258  *   !(tr)<th scope="row">h</th>       !(td)clock-hour-of-am-pm (1-12)</td>  !(td)number</td>            !(td)12</td>
259  *   !(tr)<th scope="row">K</th>       !(td)hour-of-am-pm (0-11)</td>        !(td)number</td>            !(td)0</td>
260  *   !(tr)<th scope="row">k</th>       !(td)clock-hour-of-day (1-24)</td>    !(td)number</td>            !(td)24</td>
261  *
262  *   !(tr)<th scope="row">H</th>       !(td)hour-of-day (0-23)</td>          !(td)number</td>            !(td)0</td>
263  *   !(tr)<th scope="row">m</th>       !(td)minute-of-hour</td>              !(td)number</td>            !(td)30</td>
264  *   !(tr)<th scope="row">s</th>       !(td)second-of-minute</td>            !(td)number</td>            !(td)55</td>
265  *   !(tr)<th scope="row">S</th>       !(td)fraction-of-second</td>          !(td)fraction</td>          !(td)978</td>
266  *   !(tr)<th scope="row">A</th>       !(td)milli-of-day</td>                !(td)number</td>            !(td)1234</td>
267  *   !(tr)<th scope="row">n</th>       !(td)nano-of-second</td>              !(td)number</td>            !(td)987654321</td>
268  *   !(tr)<th scope="row">N</th>       !(td)nano-of-day</td>                 !(td)number</td>            !(td)1234000000</td>
269  *
270  *   !(tr)<th scope="row">V</th>       !(td)time-zone ID</td>                !(td)zone-id</td>           !(td)America/Los_Angeles; Z; -08:30</td>
271  *   !(tr)<th scope="row">v</th>       !(td)generic time-zone name</td>      !(td)zone-name</td>         !(td)Pacific Time; PT</td>
272  *   !(tr)<th scope="row">z</th>       !(td)time-zone name</td>              !(td)zone-name</td>         !(td)Pacific Standard Time; PST</td>
273  *   !(tr)<th scope="row">O</th>       !(td)localized zone-offset</td>       !(td)offset-O</td>          !(td)GMT+8; GMT+08:00; UTC-08:00</td>
274  *   !(tr)<th scope="row">X</th>       !(td)zone-offset 'Z' for zero</td>    !(td)offset-X</td>          !(td)Z; -08; -0830; -08:30; -083015; -08:30:15</td>
275  *   !(tr)<th scope="row">x</th>       !(td)zone-offset</td>                 !(td)offset-x</td>          !(td)+0000; -08; -0830; -08:30; -083015; -08:30:15</td>
276  *   !(tr)<th scope="row">Z</th>       !(td)zone-offset</td>                 !(td)offset-Z</td>          !(td)+0000; -0800; -08:00</td>
277  *
278  *   !(tr)<th scope="row">p</th>       !(td)pad next</td>                    !(td)pad modifier</td>      !(td)1</td>
279  *
280  *   !(tr)<th scope="row">'</th>       !(td)escape for text</td>             !(td)delimiter</td>         !(td)</td>
281  *   !(tr)<th scope="row">''</th>      !(td)single quote</td>                !(td)literal</td>           !(td)'</td>
282  *   !(tr)<th scope="row">[</th>       !(td)optional section start</td>      !(td)</td>                  !(td)</td>
283  *   !(tr)<th scope="row">]</th>       !(td)optional section end</td>        !(td)</td>                  !(td)</td>
284  *   !(tr)<th scope="row">#</th>       !(td)reserved for future use</td>     !(td)</td>                  !(td)</td>
285  *   !(tr)<th scope="row">{</th>       !(td)reserved for future use</td>     !(td)</td>                  !(td)</td>
286  *   !(tr)<th scope="row">}</th>       !(td)reserved for future use</td>     !(td)</td>                  !(td)</td>
287  * </tbody>
288  * </table>
289  * !(p)
290  * The count of pattern letters determines the format.
291  * !(p)
292  * !(b)Text</b>: The text style is determined based on the number of pattern
293  * letters used. Less than 4 pattern letters will use the
294  * {@link TextStyle#SHORT short form}. Exactly 4 pattern letters will use the
295  * {@link TextStyle#FULL full form}. Exactly 5 pattern letters will use the
296  * {@link TextStyle#NARROW narrow form}.
297  * Pattern letters 'L', 'c', and 'q' specify the stand-alone form of the text styles.
298  * !(p)
299  * !(b)Number</b>: If the count of letters is one, then the value is output using
300  * the minimum number of digits and without padding. Otherwise, the count of digits
301  * is used as the width of the output field, with the value zero-padded as necessary.
302  * The following pattern letters have constraints on the count of letters.
303  * Only one letter of 'c' and 'F' can be specified.
304  * Up to two letters of 'd', 'H', 'h', 'K', 'k', 'm', and 's' can be specified.
305  * Up to three letters of 'D' can be specified.
306  * !(p)
307  * !(b)Number/Text</b>: If the count of pattern letters is 3 or greater, use the
308  * Text rules above. Otherwise use the Number rules above.
309  * !(p)
310  * !(b)Fraction</b>: Outputs the nano-of-second field as a fraction-of-second.
311  * The nano-of-second value has nine digits, thus the count of pattern letters
312  * is from 1 to 9. If it is less than 9, then the nano-of-second value is
313  * truncated, with only the most significant digits being output.
314  * !(p)
315  * !(b)Year</b>: The count of letters determines the minimum field width below
316  * which padding is used. If the count of letters is two, then a
317  * {@link DateTimeFormatterBuilder#appendValueReduced reduced} two digit form is
318  * used. For printing, this outputs the rightmost two digits. For parsing, this
319  * will parse using the base value of 2000, resulting _in a year within the range
320  * 2000 to 2099 inclusive. If the count of letters is less than four (but not
321  * two), then the sign is only output for negative years as per
322  * {@link SignStyle#NORMAL}. Otherwise, the sign is output if the pad width is
323  * exceeded, as per {@link SignStyle#EXCEEDS_PAD}.
324  * !(p)
325  * !(b)ZoneId</b>: This outputs the time-zone ID, such as 'Europe/Paris'. If the
326  * count of letters is two, then the time-zone ID is output. Any other count of
327  * letters throws {@code IllegalArgumentException}.
328  * !(p)
329  * !(b)Zone names</b>: This outputs the display name of the time-zone ID. If the
330  * pattern letter is 'z' the output is the daylight savings aware zone name.
331  * If there is insufficient information to determine whether DST applies,
332  * the name ignoring daylight savings time will be used.
333  * If the count of letters is one, two or three, then the short name is output.
334  * If the count of letters is four, then the full name is output.
335  * Five or more letters throws {@code IllegalArgumentException}.
336  * !(p)
337  * If the pattern letter is 'v' the output provides the zone name ignoring
338  * daylight savings time. If the count of letters is one, then the short name is output.
339  * If the count of letters is four, then the full name is output.
340  * Two, three and five or more letters throw {@code IllegalArgumentException}.
341  * !(p)
342  * !(b)Offset X and x</b>: This formats the offset based on the number of pattern
343  * letters. One letter outputs just the hour, such as '+01', unless the minute
344  * is non-zero _in which case the minute is also output, such as '+0130'. Two
345  * letters outputs the hour and minute, without a colon, such as '+0130'. Three
346  * letters outputs the hour and minute, with a colon, such as '+01:30'. Four
347  * letters outputs the hour and minute and optional second, without a colon,
348  * such as '+013015'. Five letters outputs the hour and minute and optional
349  * second, with a colon, such as '+01:30:15'. Six or more letters throws
350  * {@code IllegalArgumentException}. Pattern letter 'X' (upper case) will output
351  * 'Z' when the offset to be output would be zero, whereas pattern letter 'x'
352  * (lower case) will output '+00', '+0000', or '+00:00'.
353  * !(p)
354  * !(b)Offset O</b>: This formats the localized offset based on the number of
355  * pattern letters. One letter outputs the {@linkplain TextStyle#SHORT short}
356  * form of the localized offset, which is localized offset text, such as 'GMT',
357  * with hour without leading zero, optional 2-digit minute and second if
358  * non-zero, and colon, for example 'GMT+8'. Four letters outputs the
359  * {@linkplain TextStyle#FULL full} form, which is localized offset text,
360  * such as 'GMT, with 2-digit hour and minute field, optional second field
361  * if non-zero, and colon, for example 'GMT+08:00'. Any other count of letters
362  * throws {@code IllegalArgumentException}.
363  * !(p)
364  * !(b)Offset Z</b>: This formats the offset based on the number of pattern
365  * letters. One, two or three letters outputs the hour and minute, without a
366  * colon, such as '+0130'. The output will be '+0000' when the offset is zero.
367  * Four letters outputs the {@linkplain TextStyle#FULL full} form of localized
368  * offset, equivalent to four letters of Offset-O. The output will be the
369  * corresponding localized offset text if the offset is zero. Five
370  * letters outputs the hour, minute, with optional second if non-zero, with
371  * colon. It outputs 'Z' if the offset is zero.
372  * Six or more letters throws {@code IllegalArgumentException}.
373  * !(p)
374  * !(b)Optional section</b>: The optional section markers work exactly like
375  * calling {@link DateTimeFormatterBuilder#optionalStart()} and
376  * {@link DateTimeFormatterBuilder#optionalEnd()}.
377  * !(p)
378  * !(b)Pad modifier</b>: Modifies the pattern that immediately follows to be
379  * padded with spaces. The pad width is determined by the number of pattern
380  * letters. This is the same as calling
381  * {@link DateTimeFormatterBuilder#padNext(int)}.
382  * !(p)
383  * For example, 'ppH' outputs the hour-of-day padded on the left with spaces to
384  * a width of 2.
385  * !(p)
386  * Any unrecognized letter is an error. Any non-letter character, other than
387  * '[', ']', '{', '}', '#' and the single quote will be output directly.
388  * Despite this, it is recommended to use single quotes around all characters
389  * that you want to output directly to ensure that future changes do not break
390  * your application.
391  *
392  * <h3 id="resolving">Resolving</h3>
393  * Parsing is implemented as a two-phase operation.
394  * First, the text is parsed using the layout defined by the formatter, producing
395  * a {@code Map} of field to value, a {@code ZoneId} and a {@code Chronology}.
396  * Second, the parsed data is !(em)resolved</em>, by validating, combining and
397  * simplifying the various fields into more useful ones.
398  * !(p)
399  * Five parsing methods are supplied by this class.
400  * Four of these perform both the parse and resolve phases.
401  * The fifth method, {@link #parseUnresolved(string, ParsePosition)},
402  * only performs the first phase, leaving the result unresolved.
403  * As such, it is essentially a low-level operation.
404  * !(p)
405  * The resolve phase is controlled by two parameters, set on this class.
406  * !(p)
407  * The {@link ResolverStyle} is an enum that offers three different approaches,
408  * strict, smart and lenient. The smart option is the default.
409  * It can be set using {@link #withResolverStyle(ResolverStyle)}.
410  * !(p)
411  * The {@link #withResolverFields(TemporalField...)} parameter allows the
412  * set of fields that will be resolved to be filtered before resolving starts.
413  * For example, if the formatter has parsed a year, month, day-of-month
414  * and day-of-year, then there are two approaches to resolve a date:
415  * (year + month + day-of-month) and (year + day-of-year).
416  * The resolver fields allows one of the two approaches to be selected.
417  * If no resolver fields are set then both approaches must result _in the same date.
418  * !(p)
419  * Resolving separate fields to form a complete date and time is a complex
420  * process with behaviour distributed across a number of classes.
421  * It follows these steps:
422  * !(ol)
423  * !(li)The chronology is determined.
424  * The chronology of the result is either the chronology that was parsed,
425  * or if no chronology was parsed, it is the chronology set on this class,
426  * or if that is null, it is {@code IsoChronology}.
427  * !(li)The {@code ChronoField} date fields are resolved.
428  * This is achieved using {@link Chronology#resolveDate(Map, ResolverStyle)}.
429  * Documentation about field resolution is located _in the implementation
430  * of {@code Chronology}.
431  * !(li)The {@code ChronoField} time fields are resolved.
432  * This is documented on {@link ChronoField} and is the same for all chronologies.
433  * !(li)Any fields that are not {@code ChronoField} are processed.
434  * This is achieved using {@link TemporalField#resolve(Map, TemporalAccessor, ResolverStyle)}.
435  * Documentation about field resolution is located _in the implementation
436  * of {@code TemporalField}.
437  * !(li)The {@code ChronoField} date and time fields are re-resolved.
438  * This allows fields _in step four to produce {@code ChronoField} values
439  * and have them be processed into dates and times.
440  * !(li)A {@code LocalTime} is formed if there is at least an hour-of-day available.
441  * This involves providing default values for minute, second and fraction of second.
442  * !(li)Any remaining unresolved fields are cross-checked against any
443  * date and/or time that was resolved. Thus, an earlier stage would resolve
444  * (year + month + day-of-month) to a date, and this stage would check that
445  * day-of-week was valid for the date.
446  * !(li)If an {@linkplain #parsedExcessDays() excess number of days}
447  * was parsed then it is added to the date if a date is available.
448  * !(li) If a second-based field is present, but {@code LocalTime} was not parsed,
449  * then the resolver ensures that milli, micro and nano second values are
450  * available to meet the contract of {@link ChronoField}.
451  * These will be set to zero if missing.
452  * !(li)If both date and time were parsed and either an offset or zone is present,
453  * the field {@link ChronoField#INSTANT_SECONDS} is created.
454  * If an offset was parsed then the offset will be combined with the
455  * {@code LocalDateTime} to form the instant, with any zone ignored.
456  * If a {@code ZoneId} was parsed without an offset then the zone will be
457  * combined with the {@code LocalDateTime} to form the instant using the rules
458  * of {@link ChronoLocalDateTime#atZone(ZoneId)}.
459  * </ol>
460  *
461  * @implSpec
462  * This class is immutable and thread-safe.
463  *
464  * @since 1.8
465  */
466 import hunt.time.format.DecimalStyle;
467 import hunt.time.format.ResolverStyle;
468 import hunt.time.format.FormatStyle;
469 import hunt.time.format.CompositePrinterParser;
470 
471 public final class DateTimeFormatter {
472 
473     /**
474      * The printer and/or parser to use, not null.
475      */
476     private  CompositePrinterParser printerParser;
477     /**
478      * The locale to use for formatting, not null.
479      */
480     private  Locale locale;
481     /**
482      * The symbols to use for formatting, not null.
483      */
484     private  DecimalStyle decimalStyle;
485     /**
486      * The resolver style to use, not null.
487      */
488     private  ResolverStyle resolverStyle;
489     /**
490      * The fields to use _in resolving, null for all fields.
491      */
492     private  Set!(TemporalField) resolverFields;
493     /**
494      * The chronology to use for formatting, null for no override.
495      */
496     private  Chronology chrono;
497     /**
498      * The zone to use for formatting, null for no override.
499      */
500     private  ZoneId zone;
501 
502     //-----------------------------------------------------------------------
503 
504     deprecated("Using DateTimeFormatterBuilder.ofPattern instead.")
505     public static DateTimeFormatter ofPattern(string pattern) {
506         throw new Exception("Using DateTimeFormatterBuilder.ofPattern instead.");
507     }
508 
509     deprecated("Using DateTimeFormatterBuilder.ofPattern instead.")
510     public static DateTimeFormatter ofPattern(string pattern, Locale locale) {
511         throw new Exception("Using DateTimeFormatterBuilder.ofPattern instead.");
512     }
513 
514     deprecated("Using DateTimeFormatterBuilder.ofLocalizedDate instead.")
515     public static DateTimeFormatter ofLocalizedDate(FormatStyle dateStyle) {
516         throw new Exception("Using DateTimeFormatterBuilder.ofLocalizedDate instead.");
517     }
518 
519     deprecated("Using DateTimeFormatterBuilder.ofLocalizedTime instead.")
520     public static DateTimeFormatter ofLocalizedTime(FormatStyle timeStyle) {
521         throw new Exception("Using DateTimeFormatterBuilder.ofLocalizedTime instead.");
522     }
523 
524     deprecated("Using DateTimeFormatterBuilder.ofLocalizedDateTime instead.")
525     public static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateTimeStyle) {
526         throw new Exception("Using DateTimeFormatterBuilder.ofLocalizedDateTime instead.");
527     }
528 
529     deprecated("Using DateTimeFormatterBuilder.ofLocalizedDateTime instead.")
530     public static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle) {        
531         throw new Exception("Using DateTimeFormatterBuilder.ofLocalizedDateTime instead.");
532     }
533 
534     
535 
536     //-----------------------------------------------------------------------
537     /**
538      * A query that provides access to the excess days that were parsed.
539      * !(p)
540      * This returns a singleton {@linkplain TemporalQuery query} that provides
541      * access to additional information from the parse. The query always returns
542      * a non-null period, with a zero period returned instead of null.
543      * !(p)
544      * There are two situations where this query may return a non-zero period.
545      * !(ul)
546      * !(li)If the {@code ResolverStyle} is {@code LENIENT} and a time is parsed
547      *  without a date, then the complete result of the parse consists of a
548      *  {@code LocalTime} and an excess {@code Period} _in days.
549      *
550      * !(li)If the {@code ResolverStyle} is {@code SMART} and a time is parsed
551      *  without a date where the time is 24:00:00, then the complete result of
552      *  the parse consists of a {@code LocalTime} of 00:00:00 and an excess
553      *  {@code Period} of one day.
554      * </ul>
555      * !(p)
556      * In both cases, if a complete {@code ChronoLocalDateTime} or {@code Instant}
557      * is parsed, then the excess days are added to the date part.
558      * As a result, this query will return a zero period.
559      * !(p)
560      * The {@code SMART} behaviour handles the common "end of day" 24:00 value.
561      * Processing _in {@code LENIENT} mode also produces the same result:
562      * !(pre)
563      *  Text to parse        Parsed object                         Excess days
564      *  "2012-12-03T00:00"   LocalDateTime.of(2012, 12, 3, 0, 0)   ZERO
565      *  "2012-12-03T24:00"   LocalDateTime.of(2012, 12, 4, 0, 0)   ZERO
566      *  "00:00"              LocalTime.of(0, 0)                    ZERO
567      *  "24:00"              LocalTime.of(0, 0)                    Period.ofDays(1)
568      * </pre>
569      * The query can be used as follows:
570      * !(pre)
571      *  TemporalAccessor parsed = formatter.parse(str);
572      *  LocalTime time = parsed.query(LocalTime.from);
573      *  Period extraDays = parsed.query(DateTimeFormatter.parsedExcessDays());
574      * </pre>
575      * @return a query that provides access to the excess days that were parsed
576      */
577     static TemporalQuery!(Period) parsedExcessDays() {
578         __gshared TemporalQuery!(Period) PARSED_EXCESS_DAYS;
579         return initOnce!PARSED_EXCESS_DAYS(createParsedExcessDays());
580     }
581 
582     private static TemporalQuery!(Period) createParsedExcessDays() {
583         return new class TemporalQuery!(Period)
584         {
585             Period queryFrom(TemporalAccessor t)
586             {
587                 if (cast(Parsed)(t) !is null)
588                 {
589                     return (cast(Parsed) t).excessDays;
590                 }
591                 else
592                 {
593                     return Period.ZERO;
594                 }
595             }
596         };
597     }
598 
599     /**
600      * A query that provides access to whether a leap-second was parsed.
601      * !(p)
602      * This returns a singleton {@linkplain TemporalQuery query} that provides
603      * access to additional information from the parse. The query always returns
604      * a non-null bool, true if parsing saw a leap-second, false if not.
605      * !(p)
606      * Instant parsing handles the special "leap second" time of '23:59:60'.
607      * Leap seconds occur at '23:59:60' _in the UTC time-zone, but at other
608      * local times _in different time-zones. To avoid this potential ambiguity,
609      * the handling of leap-seconds is limited to
610      * {@link DateTimeFormatterBuilder#appendInstant()}, as that method
611      * always parses the instant with the UTC zone offset.
612      * !(p)
613      * If the time '23:59:60' is received, then a simple conversion is applied,
614      * replacing the second-of-minute of 60 with 59. This query can be used
615      * on the parse result to determine if the leap-second adjustment was made.
616      * The query will return {@code true} if it did adjust to remove the
617      * leap-second, and {@code false} if not. Note that applying a leap-second
618      * smoothing mechanism, such as UTC-SLS, is the responsibility of the
619      * application, as follows:
620      * !(pre)
621      *  TemporalAccessor parsed = formatter.parse(str);
622      *  Instant instant = parsed.query(Instant::from);
623      *  if (parsed.query(DateTimeFormatter.parsedLeapSecond())) {
624      *    // validate leap-second is correct and apply correct smoothing
625      *  }
626      * </pre>
627      * @return a query that provides access to whether a leap-second was parsed
628      */
629     static TemporalQuery!(Boolean) parsedLeapSecond() {
630         __gshared TemporalQuery!(Boolean) PARSED_LEAP_SECOND;
631         return initOnce!PARSED_LEAP_SECOND(createParsedLeapSecond());
632     }
633 
634     private static TemporalQuery!(Boolean) createParsedLeapSecond() {
635         return new class TemporalQuery!(Boolean)
636         {
637             Boolean queryFrom(TemporalAccessor t)
638             {
639                 if (cast(Parsed)(t) !is null)
640                 {
641                     return new Boolean((cast(Parsed) t).leapSecond);
642                 }
643                 else
644                 {
645                     return Boolean.FALSE;
646                 }
647             }
648         };
649     }
650 
651     //-----------------------------------------------------------------------
652     /**
653      * Constructor.
654      *
655      * @param printerParser  the printer/parser to use, not null
656      * @param locale  the locale to use, not null
657      * @param decimalStyle  the DecimalStyle to use, not null
658      * @param resolverStyle  the resolver style to use, not null
659      * @param resolverFields  the fields to use during resolving, null for all fields
660      * @param chrono  the chronology to use, null for no override
661      * @param zone  the zone to use, null for no override
662      */
663     this(CompositePrinterParser printerParser,
664             Locale locale, DecimalStyle decimalStyle,
665             ResolverStyle resolverStyle, Set!(TemporalField) resolverFields,
666             Chronology chrono, ZoneId zone) {
667         this.printerParser = printerParser;
668         this.resolverFields = resolverFields;
669         this.locale = locale;
670         this.decimalStyle = decimalStyle;
671         this.resolverStyle = resolverStyle;
672         this.chrono = chrono;
673         this.zone = zone;
674     }
675 
676     //-----------------------------------------------------------------------
677     /**
678      * Gets the locale to be used during formatting.
679      * !(p)
680      * This is used to lookup any part of the formatter needing specific
681      * localization, such as the text or localized pattern.
682      *
683      * @return the locale of this formatter, not null
684      */
685     public Locale getLocale() {
686         return locale;
687     }
688 
689     /**
690      * Returns a copy of this formatter with a new locale.
691      * !(p)
692      * This is used to lookup any part of the formatter needing specific
693      * localization, such as the text or localized pattern.
694      * !(p)
695      * The locale is stored as passed _in, without further processing.
696      * If the locale has <a href="../../util/Locale.html#def_locale_extension">
697      * Unicode extensions</a>, they may be used later _in text
698      * processing. To set the chronology, time-zone and decimal style from
699      * unicode extensions, see {@link #localizedBy localizedBy()}.
700      * !(p)
701      * This instance is immutable and unaffected by this method call.
702      *
703      * @param locale  the new locale, not null
704      * @return a formatter based on this formatter with the requested locale, not null
705      * @see #localizedBy(Locale)
706      */
707     public DateTimeFormatter withLocale(Locale locale) {
708         if (this.locale == (locale)) {
709             return this;
710         }
711         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
712     }
713 
714     /**
715      * Returns a copy of this formatter with localized values of the locale,
716      * calendar, region, decimal style and/or timezone, that supercede values _in
717      * this formatter.
718      * !(p)
719      * This is used to lookup any part of the formatter needing specific
720      * localization, such as the text or localized pattern. If the locale contains the
721      * "ca" (calendar), "nu" (numbering system), "rg" (region override), and/or
722      * "tz" (timezone)
723      * <a href="../../util/Locale.html#def_locale_extension">Unicode extensions</a>,
724      * the chronology, numbering system and/or the zone are overridden. If both "ca"
725      * and "rg" are specified, the chronology from the "ca" extension supersedes the
726      * implicit one from the "rg" extension. Same is true for the "nu" extension.
727      * !(p)
728      * Unlike the {@link #withLocale withLocale} method, the call to this method may
729      * produce a different formatter depending on the order of method chaining with
730      * other withXXXX() methods.
731      * !(p)
732      * This instance is immutable and unaffected by this method call.
733      *
734      * @param locale  the locale, not null
735      * @return a formatter based on this formatter with localized values of
736      *      the calendar, decimal style and/or timezone, that supercede values _in this
737      *      formatter.
738      * @see #withLocale(Locale)
739      * @since 10
740      */
741      ///@gxc
742     // public DateTimeFormatter localizedBy(Locale locale) {
743     //     if (this.locale == (locale)) {
744     //         return this;
745     //     }
746 
747     //     // Check for decimalStyle/chronology/timezone _in locale object
748     //     Chronology c = locale.getUnicodeLocaleType("ca") !is null ?
749     //                    Chronology.ofLocale(locale) : chrono;
750     //     DecimalStyle ds = locale.getUnicodeLocaleType("nu") !is null ?
751     //                    DecimalStyle.of(locale) : decimalStyle;
752     //     string tzType = locale.getUnicodeLocaleType("tz");
753     //     ZoneId z  = tzType !is null ?
754     //                 TimeZoneNameUtility.convertLDMLShortID(tzType)
755     //                     .map(ZoneId.of)
756     //                     .orElse(zone) :
757     //                 zone;
758     //     return new DateTimeFormatter(printerParser, locale, ds, resolverStyle, resolverFields, c, z);
759     // }
760 
761     //-----------------------------------------------------------------------
762     /**
763      * Gets the DecimalStyle to be used during formatting.
764      *
765      * @return the locale of this formatter, not null
766      */
767     public DecimalStyle getDecimalStyle() {
768         return decimalStyle;
769     }
770 
771     /**
772      * Returns a copy of this formatter with a new DecimalStyle.
773      * !(p)
774      * This instance is immutable and unaffected by this method call.
775      *
776      * @param decimalStyle  the new DecimalStyle, not null
777      * @return a formatter based on this formatter with the requested DecimalStyle, not null
778      */
779     public DateTimeFormatter withDecimalStyle(DecimalStyle decimalStyle) {
780         if (this.decimalStyle == (decimalStyle)) {
781             return this;
782         }
783         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
784     }
785 
786     //-----------------------------------------------------------------------
787     /**
788      * Gets the overriding chronology to be used during formatting.
789      * !(p)
790      * This returns the override chronology, used to convert dates.
791      * By default, a formatter has no override chronology, returning null.
792      * See {@link #withChronology(Chronology)} for more details on overriding.
793      *
794      * @return the override chronology of this formatter, null if no override
795      */
796     public Chronology getChronology() {
797         return chrono;
798     }
799 
800     /**
801      * Returns a copy of this formatter with a new override chronology.
802      * !(p)
803      * This returns a formatter with similar state to this formatter but
804      * with the override chronology set.
805      * By default, a formatter has no override chronology, returning null.
806      * !(p)
807      * If an override is added, then any date that is formatted or parsed will be affected.
808      * !(p)
809      * When formatting, if the temporal object contains a date, then it will
810      * be converted to a date _in the override chronology.
811      * Whether the temporal contains a date is determined by querying the
812      * {@link ChronoField#EPOCH_DAY EPOCH_DAY} field.
813      * Any time or zone will be retained unaltered unless overridden.
814      * !(p)
815      * If the temporal object does not contain a date, but does contain one
816      * or more {@code ChronoField} date fields, then a {@code DateTimeException}
817      * is thrown. In all other cases, the override chronology is added to the temporal,
818      * replacing any previous chronology, but without changing the date/time.
819      * !(p)
820      * When parsing, there are two distinct cases to consider.
821      * If a chronology has been parsed directly from the text, perhaps because
822      * {@link DateTimeFormatterBuilder#appendChronologyId()} was used, then
823      * this override chronology has no effect.
824      * If no zone has been parsed, then this override chronology will be used
825      * to interpret the {@code ChronoField} values into a date according to the
826      * date resolving rules of the chronology.
827      * !(p)
828      * This instance is immutable and unaffected by this method call.
829      *
830      * @param chrono  the new chronology, null if no override
831      * @return a formatter based on this formatter with the requested override chronology, not null
832      */
833     public DateTimeFormatter withChronology(Chronology chrono) {
834         if (this.chrono !is null && (this.chrono == chrono)) {
835             return this;
836         }
837         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
838     }
839 
840     //-----------------------------------------------------------------------
841     /**
842      * Gets the overriding zone to be used during formatting.
843      * !(p)
844      * This returns the override zone, used to convert instants.
845      * By default, a formatter has no override zone, returning null.
846      * See {@link #withZone(ZoneId)} for more details on overriding.
847      *
848      * @return the override zone of this formatter, null if no override
849      */
850     public ZoneId getZone() {
851         return zone;
852     }
853 
854     /**
855      * Returns a copy of this formatter with a new override zone.
856      * !(p)
857      * This returns a formatter with similar state to this formatter but
858      * with the override zone set.
859      * By default, a formatter has no override zone, returning null.
860      * !(p)
861      * If an override is added, then any instant that is formatted or parsed will be affected.
862      * !(p)
863      * When formatting, if the temporal object contains an instant, then it will
864      * be converted to a zoned date-time using the override zone.
865      * Whether the temporal is an instant is determined by querying the
866      * {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS} field.
867      * If the input has a chronology then it will be retained unless overridden.
868      * If the input does not have a chronology, such as {@code Instant}, then
869      * the ISO chronology will be used.
870      * !(p)
871      * If the temporal object does not contain an instant, but does contain
872      * an offset then an additional check is made. If the normalized override
873      * zone is an offset that differs from the offset of the temporal, then
874      * a {@code DateTimeException} is thrown. In all other cases, the override
875      * zone is added to the temporal, replacing any previous zone, but without
876      * changing the date/time.
877      * !(p)
878      * When parsing, there are two distinct cases to consider.
879      * If a zone has been parsed directly from the text, perhaps because
880      * {@link DateTimeFormatterBuilder#appendZoneId()} was used, then
881      * this override zone has no effect.
882      * If no zone has been parsed, then this override zone will be included _in
883      * the result of the parse where it can be used to build instants and date-times.
884      * !(p)
885      * This instance is immutable and unaffected by this method call.
886      *
887      * @param zone  the new override zone, null if no override
888      * @return a formatter based on this formatter with the requested override zone, not null
889      */
890     public DateTimeFormatter withZone(ZoneId zone) {
891         if ((this.zone == zone)) {
892             return this;
893         }
894         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
895     }
896 
897     //-----------------------------------------------------------------------
898     /**
899      * Gets the resolver style to use during parsing.
900      * !(p)
901      * This returns the resolver style, used during the second phase of parsing
902      * when fields are resolved into dates and times.
903      * By default, a formatter has the {@link ResolverStyle#SMART SMART} resolver style.
904      * See {@link #withResolverStyle(ResolverStyle)} for more details.
905      *
906      * @return the resolver style of this formatter, not null
907      */
908     public ResolverStyle getResolverStyle() {
909         return resolverStyle;
910     }
911 
912     /**
913      * Returns a copy of this formatter with a new resolver style.
914      * !(p)
915      * This returns a formatter with similar state to this formatter but
916      * with the resolver style set. By default, a formatter has the
917      * {@link ResolverStyle#SMART SMART} resolver style.
918      * !(p)
919      * Changing the resolver style only has an effect during parsing.
920      * Parsing a text string occurs _in two phases.
921      * Phase 1 is a basic text parse according to the fields added to the builder.
922      * Phase 2 resolves the parsed field-value pairs into date and/or time objects.
923      * The resolver style is used to control how phase 2, resolving, happens.
924      * See {@code ResolverStyle} for more information on the options available.
925      * !(p)
926      * This instance is immutable and unaffected by this method call.
927      *
928      * @param resolverStyle  the new resolver style, not null
929      * @return a formatter based on this formatter with the requested resolver style, not null
930      */
931     public DateTimeFormatter withResolverStyle(ResolverStyle resolverStyle) {
932         assert(resolverStyle, "resolverStyle");
933         if ((this.resolverStyle == resolverStyle)) {
934             return this;
935         }
936         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
937     }
938 
939     //-----------------------------------------------------------------------
940     /**
941      * Gets the resolver fields to use during parsing.
942      * !(p)
943      * This returns the resolver fields, used during the second phase of parsing
944      * when fields are resolved into dates and times.
945      * By default, a formatter has no resolver fields, and thus returns null.
946      * See {@link #withResolverFields(Set)} for more details.
947      *
948      * @return the immutable set of resolver fields of this formatter, null if no fields
949      */
950     public Set!(TemporalField) getResolverFields() {
951         return resolverFields;
952     }
953 
954     /**
955      * Returns a copy of this formatter with a new set of resolver fields.
956      * !(p)
957      * This returns a formatter with similar state to this formatter but with
958      * the resolver fields set. By default, a formatter has no resolver fields.
959      * !(p)
960      * Changing the resolver fields only has an effect during parsing.
961      * Parsing a text string occurs _in two phases.
962      * Phase 1 is a basic text parse according to the fields added to the builder.
963      * Phase 2 resolves the parsed field-value pairs into date and/or time objects.
964      * The resolver fields are used to filter the field-value pairs between phase 1 and 2.
965      * !(p)
966      * This can be used to select between two or more ways that a date or time might
967      * be resolved. For example, if the formatter consists of year, month, day-of-month
968      * and day-of-year, then there are two ways to resolve a date.
969      * Calling this method with the arguments {@link ChronoField#YEAR YEAR} and
970      * {@link ChronoField#DAY_OF_YEAR DAY_OF_YEAR} will ensure that the date is
971      * resolved using the year and day-of-year, effectively meaning that the month
972      * and day-of-month are ignored during the resolving phase.
973      * !(p)
974      * In a similar manner, this method can be used to ignore secondary fields that
975      * would otherwise be cross-checked. For example, if the formatter consists of year,
976      * month, day-of-month and day-of-week, then there is only one way to resolve a
977      * date, but the parsed value for day-of-week will be cross-checked against the
978      * resolved date. Calling this method with the arguments {@link ChronoField#YEAR YEAR},
979      * {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
980      * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} will ensure that the date is
981      * resolved correctly, but without any cross-check for the day-of-week.
982      * !(p)
983      * In implementation terms, this method behaves as follows. The result of the
984      * parsing phase can be considered to be a map of field to value. The behavior
985      * of this method is to cause that map to be filtered between phase 1 and 2,
986      * removing all fields other than those specified as arguments to this method.
987      * !(p)
988      * This instance is immutable and unaffected by this method call.
989      *
990      * @param resolverFields  the new set of resolver fields, null if no fields
991      * @return a formatter based on this formatter with the requested resolver style, not null
992      */
993      ///@gxc
994     // public DateTimeFormatter withResolverFields(TemporalField[] resolverFields...) {
995     //     Set!(TemporalField) fields = null;
996     //     if (resolverFields !is null) {
997     //         // Set.of cannot be used because it is hostile to nulls and duplicate elements
998     //         auto hs = new HashSet!TemporalField();
999     //         foreach( t ; resolverFields)
1000     //             hs.add(t);
1001     //         fields = Collections.unmodifiableSet(hs);
1002     //     }
1003     //     if ((this.resolverFields == fields)) {
1004     //         return this;
1005     //     }
1006     //     return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, fields, chrono, zone);
1007     // }
1008 
1009     /**
1010      * Returns a copy of this formatter with a new set of resolver fields.
1011      * !(p)
1012      * This returns a formatter with similar state to this formatter but with
1013      * the resolver fields set. By default, a formatter has no resolver fields.
1014      * !(p)
1015      * Changing the resolver fields only has an effect during parsing.
1016      * Parsing a text string occurs _in two phases.
1017      * Phase 1 is a basic text parse according to the fields added to the builder.
1018      * Phase 2 resolves the parsed field-value pairs into date and/or time objects.
1019      * The resolver fields are used to filter the field-value pairs between phase 1 and 2.
1020      * !(p)
1021      * This can be used to select between two or more ways that a date or time might
1022      * be resolved. For example, if the formatter consists of year, month, day-of-month
1023      * and day-of-year, then there are two ways to resolve a date.
1024      * Calling this method with the arguments {@link ChronoField#YEAR YEAR} and
1025      * {@link ChronoField#DAY_OF_YEAR DAY_OF_YEAR} will ensure that the date is
1026      * resolved using the year and day-of-year, effectively meaning that the month
1027      * and day-of-month are ignored during the resolving phase.
1028      * !(p)
1029      * In a similar manner, this method can be used to ignore secondary fields that
1030      * would otherwise be cross-checked. For example, if the formatter consists of year,
1031      * month, day-of-month and day-of-week, then there is only one way to resolve a
1032      * date, but the parsed value for day-of-week will be cross-checked against the
1033      * resolved date. Calling this method with the arguments {@link ChronoField#YEAR YEAR},
1034      * {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
1035      * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} will ensure that the date is
1036      * resolved correctly, but without any cross-check for the day-of-week.
1037      * !(p)
1038      * In implementation terms, this method behaves as follows. The result of the
1039      * parsing phase can be considered to be a map of field to value. The behavior
1040      * of this method is to cause that map to be filtered between phase 1 and 2,
1041      * removing all fields other than those specified as arguments to this method.
1042      * !(p)
1043      * This instance is immutable and unaffected by this method call.
1044      *
1045      * @param resolverFields  the new set of resolver fields, null if no fields
1046      * @return a formatter based on this formatter with the requested resolver style, not null
1047      */
1048      ///@gxc
1049     // public DateTimeFormatter withResolverFields(Set!(TemporalField) resolverFields) {
1050     //     if (Objects == (this.resolverFields, resolverFields)) {
1051     //         return this;
1052     //     }
1053     //     if (resolverFields !is null) {
1054     //         resolverFields = Collections.unmodifiableSet(new HashSet!()(resolverFields));
1055     //     }
1056     //     return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
1057     // }
1058 
1059     //-----------------------------------------------------------------------
1060     /**
1061      * Formats a date-time object using this formatter.
1062      * !(p)
1063      * This formats the date-time to a string using the rules of the formatter.
1064      *
1065      * @param temporal  the temporal object to format, not null
1066      * @return the formatted string, not null
1067      * @throws DateTimeException if an error occurs during formatting
1068      */
1069     public string format(TemporalAccessor temporal) {
1070         StringBuilder buf = new StringBuilder(32);
1071         formatTo(temporal, buf);
1072         return buf.toString();
1073     }
1074 
1075     //-----------------------------------------------------------------------
1076     /**
1077      * Formats a date-time object to an {@code Appendable} using this formatter.
1078      * !(p)
1079      * This outputs the formatted date-time to the specified destination.
1080      * {@link Appendable} is a general purpose interface that is implemented by all
1081      * key character output classes including {@code StringBuffer}, {@code StringBuilder},
1082      * {@code PrintStream} and {@code Writer}.
1083      * !(p)
1084      * Although {@code Appendable} methods throw an {@code IOException}, this method does not.
1085      * Instead, any {@code IOException} is wrapped _in a runtime exception.
1086      *
1087      * @param temporal  the temporal object to format, not null
1088      * @param appendable  the appendable to format to, not null
1089      * @throws DateTimeException if an error occurs during formatting
1090      */
1091     public void formatTo(TemporalAccessor temporal, Appendable appendable) {
1092         assert(temporal, "temporal");
1093         assert(appendable, "appendable");
1094         try {
1095             DateTimePrintContext context = new DateTimePrintContext(temporal, this);
1096             if (cast(StringBuilder)(appendable) !is null) {
1097                 printerParser.format(context, cast(StringBuilder) appendable);
1098             } else {
1099                 // buffer output to avoid writing to appendable _in case of error
1100                 StringBuilder buf = new StringBuilder(32);
1101                 printerParser.format(context, buf);
1102                 appendable.append(buf.toString);
1103             }
1104         } catch (IOException ex) {
1105             throw new DateTimeException(ex.msg, ex);
1106         }
1107     }
1108 
1109     //-----------------------------------------------------------------------
1110     /**
1111      * Fully parses the text producing a temporal object.
1112      * !(p)
1113      * This parses the entire text producing a temporal object.
1114      * It is typically more useful to use {@link #parse(string, TemporalQuery)}.
1115      * The result of this method is {@code TemporalAccessor} which has been resolved,
1116      * applying basic validation checks to help ensure a valid date-time.
1117      * !(p)
1118      * If the parse completes without reading the entire length of the text,
1119      * or a problem occurs during parsing or merging, then an exception is thrown.
1120      *
1121      * @param text  the text to parse, not null
1122      * @return the parsed temporal object, not null
1123      * @throws DateTimeParseException if unable to parse the requested result
1124      */
1125     public TemporalAccessor parse(string text) {
1126         assert(text, "text");
1127         try {
1128             return parseResolved0(text, null);
1129         } catch (DateTimeParseException ex) {
1130             throw ex;
1131         } catch (RuntimeException ex) {
1132             throw createError(text, ex);
1133         }
1134     }
1135 
1136     /**
1137      * Parses the text using this formatter, providing control over the text position.
1138      * !(p)
1139      * This parses the text without requiring the parse to start from the beginning
1140      * of the string or finish at the end.
1141      * The result of this method is {@code TemporalAccessor} which has been resolved,
1142      * applying basic validation checks to help ensure a valid date-time.
1143      * !(p)
1144      * The text will be parsed from the specified start {@code ParsePosition}.
1145      * The entire length of the text does not have to be parsed, the {@code ParsePosition}
1146      * will be updated with the index at the end of parsing.
1147      * !(p)
1148      * The operation of this method is slightly different to similar methods using
1149      * {@code ParsePosition} on {@code java.text.Format}. That class will return
1150      * errors using the error index on the {@code ParsePosition}. By contrast, this
1151      * method will throw a {@link DateTimeParseException} if an error occurs, with
1152      * the exception containing the error index.
1153      * This change _in behavior is necessary due to the increased complexity of
1154      * parsing and resolving dates/times _in this API.
1155      * !(p)
1156      * If the formatter parses the same field more than once with different values,
1157      * the result will be an error.
1158      *
1159      * @param text  the text to parse, not null
1160      * @param position  the position to parse from, updated with length parsed
1161      *  and the index of any error, not null
1162      * @return the parsed temporal object, not null
1163      * @throws DateTimeParseException if unable to parse the requested result
1164      * @throws IndexOutOfBoundsException if the position is invalid
1165      */
1166     public TemporalAccessor parse(string text, ParsePosition position) {
1167         assert(text, "text");
1168         assert(position, "position");
1169         try {
1170             return parseResolved0(text, position);
1171         } catch (DateTimeParseException  ex) {
1172             throw ex;
1173         } catch (RuntimeException ex) {
1174             throw createError(text, ex);
1175         }
1176     }
1177 
1178     //-----------------------------------------------------------------------
1179     /**
1180      * Fully parses the text producing an object of the specified type.
1181      * !(p)
1182      * Most applications should use this method for parsing.
1183      * It parses the entire text to produce the required date-time.
1184      * The query is typically a method reference to a {@code from(TemporalAccessor)} method.
1185      * For example:
1186      * !(pre)
1187      *  LocalDateTime dt = parser.parse(str, LocalDateTime.from);
1188      * </pre>
1189      * If the parse completes without reading the entire length of the text,
1190      * or a problem occurs during parsing or merging, then an exception is thrown.
1191      *
1192      * @param !(T) the type of the parsed date-time
1193      * @param text  the text to parse, not null
1194      * @param query  the query defining the type to parse to, not null
1195      * @return the parsed date-time, not null
1196      * @throws DateTimeParseException if unable to parse the requested result
1197      */
1198     public  T parse(T)(string text, TemporalQuery!(T) query) {
1199         assert(text, "text");
1200         assert(query, "query");
1201         try {
1202             return QueryHelper.query!T(parseResolved0(text, null),query);
1203         } catch (DateTimeParseException ex) {
1204             throw ex;
1205         } catch (RuntimeException ex) {
1206             throw createError(text, ex);
1207         }
1208     }
1209 
1210     /**
1211      * Fully parses the text producing an object of one of the specified types.
1212      * !(p)
1213      * This parse method is convenient for use when the parser can handle optional elements.
1214      * For example, a pattern of 'uuuu-MM-dd HH.mm[ VV]' can be fully parsed to a {@code ZonedDateTime},
1215      * or partially parsed to a {@code LocalDateTime}.
1216      * The queries must be specified _in order, starting from the best matching full-parse option
1217      * and ending with the worst matching minimal parse option.
1218      * The query is typically a method reference to a {@code from(TemporalAccessor)} method.
1219      * !(p)
1220      * The result is associated with the first type that successfully parses.
1221      * Normally, applications will use {@code instanceof} to check the result.
1222      * For example:
1223      * !(pre)
1224      *  TemporalAccessor dt = parser.parseBest(str, ZonedDateTime::from, LocalDateTime.from);
1225      *  if (cast(ZonedDateTime)(dt) !is null) {
1226      *   ...
1227      *  } else {
1228      *   ...
1229      *  }
1230      * </pre>
1231      * If the parse completes without reading the entire length of the text,
1232      * or a problem occurs during parsing or merging, then an exception is thrown.
1233      *
1234      * @param text  the text to parse, not null
1235      * @param queries  the queries defining the types to attempt to parse to,
1236      *  must implement {@code TemporalAccessor}, not null
1237      * @return the parsed date-time, not null
1238      * @throws IllegalArgumentException if less than 2 types are specified
1239      * @throws DateTimeParseException if unable to parse the requested result
1240      */
1241     public TemporalAccessor parseBest(string text, TemporalQuery!(Object)[] queries...) {
1242         assert(text, "text");
1243         assert(queries, "queries");
1244         if (queries.length < 2) {
1245             throw new IllegalArgumentException("At least two queries must be specified");
1246         }
1247         try {
1248             TemporalAccessor resolved = parseResolved0(text, null);
1249             foreach(TemporalQuery!(Object) query ; queries) {
1250                 try {
1251                     return cast(TemporalAccessor) (QueryHelper.query!Object(resolved,query)); ///@gxc
1252                 } catch (RuntimeException ex) {
1253                     // continue
1254                 }
1255             }
1256             throw new DateTimeException("Unable to convert parsed text using any of the specified queries");
1257         } catch (DateTimeParseException ex) {
1258             throw ex;
1259         } catch (RuntimeException ex) {
1260             throw createError(text, ex);
1261         }
1262     }
1263 
1264     private DateTimeParseException createError(string text, RuntimeException ex) {
1265         string abbr;
1266         if (text.length > 64) {
1267             abbr = text[0 .. 64] ~ "...";
1268         } else {
1269             abbr = text/* .toString() */;
1270         }
1271         return new DateTimeParseException("Text '" ~ abbr ~ "' could not be parsed: " ~ ex.msg, text, 0, ex);
1272     }
1273 
1274     //-----------------------------------------------------------------------
1275     /**
1276      * Parses and resolves the specified text.
1277      * !(p)
1278      * This parses to a {@code TemporalAccessor} ensuring that the text is fully parsed.
1279      *
1280      * @param text  the text to parse, not null
1281      * @param position  the position to parse from, updated with length parsed
1282      *  and the index of any error, null if parsing whole string
1283      * @return the resolved result of the parse, not null
1284      * @throws DateTimeParseException if the parse fails
1285      * @throws DateTimeException if an error occurs while resolving the date or time
1286      * @throws IndexOutOfBoundsException if the position is invalid
1287      */
1288     private TemporalAccessor parseResolved0( string text,  ParsePosition position) {
1289         ParsePosition pos = (position !is null ? position : new ParsePosition(0));
1290         DateTimeParseContext context = parseUnresolved0(text, pos);
1291         if (context is null || pos.getErrorIndex() >= 0 || (position is null && pos.getIndex() < text.length)) {
1292             string abbr;
1293             if (text.length > 64) {
1294                 abbr = text[0 .. 64] ~ "...";
1295             } else {
1296                 abbr = text/* .toString() */;
1297             }
1298             if (pos.getErrorIndex() >= 0) {
1299                 throw new DateTimeParseException("Text '" ~ abbr ~ "' could not be parsed at index " ~
1300                         pos.getErrorIndex().to!string, text, pos.getErrorIndex());
1301             } else {
1302                 throw new DateTimeParseException("Text '" ~ abbr ~ "' could not be parsed, unparsed text found at index " ~
1303                         pos.getIndex().to!string, text, pos.getIndex());
1304             }
1305         }
1306         return context.toResolved(resolverStyle, resolverFields);
1307     }
1308 
1309     /**
1310      * Parses the text using this formatter, without resolving the result, intended
1311      * for advanced use cases.
1312      * !(p)
1313      * Parsing is implemented as a two-phase operation.
1314      * First, the text is parsed using the layout defined by the formatter, producing
1315      * a {@code Map} of field to value, a {@code ZoneId} and a {@code Chronology}.
1316      * Second, the parsed data is !(em)resolved</em>, by validating, combining and
1317      * simplifying the various fields into more useful ones.
1318      * This method performs the parsing stage but not the resolving stage.
1319      * !(p)
1320      * The result of this method is {@code TemporalAccessor} which represents the
1321      * data as seen _in the input. Values are not validated, thus parsing a date string
1322      * of '2012-00-65' would result _in a temporal with three fields - year of '2012',
1323      * month of '0' and day-of-month of '65'.
1324      * !(p)
1325      * The text will be parsed from the specified start {@code ParsePosition}.
1326      * The entire length of the text does not have to be parsed, the {@code ParsePosition}
1327      * will be updated with the index at the end of parsing.
1328      * !(p)
1329      * Errors are returned using the error index field of the {@code ParsePosition}
1330      * instead of {@code DateTimeParseException}.
1331      * The returned error index will be set to an index indicative of the error.
1332      * Callers must check for errors before using the result.
1333      * !(p)
1334      * If the formatter parses the same field more than once with different values,
1335      * the result will be an error.
1336      * !(p)
1337      * This method is intended for advanced use cases that need access to the
1338      * internal state during parsing. Typical application code should use
1339      * {@link #parse(string, TemporalQuery)} or the parse method on the target type.
1340      *
1341      * @param text  the text to parse, not null
1342      * @param position  the position to parse from, updated with length parsed
1343      *  and the index of any error, not null
1344      * @return the parsed text, null if the parse results _in an error
1345      * @throws DateTimeException if some problem occurs during parsing
1346      * @throws IndexOutOfBoundsException if the position is invalid
1347      */
1348     public TemporalAccessor parseUnresolved(string text, ParsePosition position) {
1349         DateTimeParseContext context = parseUnresolved0(text, position);
1350         if (context is null) {
1351             return null;
1352         }
1353         return context.toUnresolved();
1354     }
1355 
1356     private DateTimeParseContext parseUnresolved0(string text, ParsePosition position) {
1357         assert(text, "text");
1358         assert(position, "position");
1359         DateTimeParseContext context = new DateTimeParseContext(this);
1360         int pos = position.getIndex();
1361         pos = printerParser.parse(context, text, pos);
1362         if (pos < 0) {
1363             position.setErrorIndex(~pos);  // index not updated from input
1364             return null;
1365         }
1366         position.setIndex(pos);  // errorIndex not updated from input
1367         return context;
1368     }
1369 
1370     //-----------------------------------------------------------------------
1371     /**
1372      * Returns the formatter as a composite printer parser.
1373      *
1374      * @param optional  whether the printer/parser should be optional
1375      * @return the printer/parser, not null
1376      */
1377     CompositePrinterParser toPrinterParser(bool optional) {
1378         return printerParser.withOptional(optional);
1379     }
1380 
1381     /**
1382      * Returns this formatter as a {@code java.text.Format} instance.
1383      * !(p)
1384      * The returned {@link Format} instance will format any {@link TemporalAccessor}
1385      * and parses to a resolved {@link TemporalAccessor}.
1386      * !(p)
1387      * Exceptions will follow the definitions of {@code Format}, see those methods
1388      * for details about {@code IllegalArgumentException} during formatting and
1389      * {@code ParseException} or null during parsing.
1390      * The format does not support attributing of the returned format string.
1391      *
1392      * @return this formatter as a classic format instance, not null
1393      */
1394      ///@gxc
1395     // public Format toFormat() {
1396     //     return new ClassicFormat(this, null);
1397     // }
1398 
1399     /**
1400      * Returns this formatter as a {@code java.text.Format} instance that will
1401      * parse using the specified query.
1402      * !(p)
1403      * The returned {@link Format} instance will format any {@link TemporalAccessor}
1404      * and parses to the type specified.
1405      * The type must be one that is supported by {@link #parse}.
1406      * !(p)
1407      * Exceptions will follow the definitions of {@code Format}, see those methods
1408      * for details about {@code IllegalArgumentException} during formatting and
1409      * {@code ParseException} or null during parsing.
1410      * The format does not support attributing of the returned format string.
1411      *
1412      * @param parseQuery  the query defining the type to parse to, not null
1413      * @return this formatter as a classic format instance, not null
1414      */
1415      ///@gxc
1416     // public Format toFormat(TemporalQuery!(Object) parseQuery) {
1417     //     assert(parseQuery, "parseQuery");
1418     //     return new ClassicFormat(this, parseQuery);
1419     // }
1420 
1421     //-----------------------------------------------------------------------
1422     /**
1423      * Returns a description of the underlying formatters.
1424      *
1425      * @return a description of this formatter, not null
1426      */
1427     override
1428     public string toString() {
1429         string pattern = printerParser.toString();
1430         pattern = pattern.startsWith("[") ? pattern : pattern[1 .. pattern.length - 1];
1431         return pattern;
1432         // TODO: Fix tests to not depend on toString()
1433 //        return "DateTimeFormatter[" ~ locale +
1434 //                (chrono !is null ? "," ~ chrono : "") +
1435 //                (zone !is null ? "," ~ zone : "") +
1436 //                pattern ~ "]";
1437     }
1438 
1439     //-----------------------------------------------------------------------
1440     /**
1441      * Implements the classic Java Format API.
1442      * @serial exclude
1443      */
1444     // @SuppressWarnings("serial")  // not actually serializable
1445     ///@gxc
1446     // static class ClassicFormat : Format {
1447     //     /** The formatter. */
1448     //     private final DateTimeFormatter formatter;
1449     //     /** The type to be parsed. */
1450     //     private final TemporalQuery!(Object) parseType;
1451     //     /** Constructor. */
1452     //     public this(DateTimeFormatter formatter, TemporalQuery!(Object) parseType) {
1453     //         this.formatter = formatter;
1454     //         this.parseType = parseType;
1455     //     }
1456 
1457     //     override
1458     //     public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
1459     //         assert(obj, "obj");
1460     //         assert(toAppendTo, "toAppendTo");
1461     //         assert(pos, "pos");
1462     //         if ((cast(TemporalAccessor)(obj) !is null) == false) {
1463     //             throw new IllegalArgumentException("Format target must implement TemporalAccessor");
1464     //         }
1465     //         pos.setBeginIndex(0);
1466     //         pos.setEndIndex(0);
1467     //         try {
1468     //             formatter.formatTo(cast(TemporalAccessor) obj, toAppendTo);
1469     //         } catch (RuntimeException ex) {
1470     //             throw new IllegalArgumentException(ex.getMessage(), ex);
1471     //         }
1472     //         return toAppendTo;
1473     //     }
1474     //     override
1475     //     public Object parseObject(string text) /* throws ParseException */ {
1476     //         assert(text, "text");
1477     //         try {
1478     //             if (parseType is null) {
1479     //                 return formatter.parseResolved0(text, null);
1480     //             }
1481     //             return formatter.parse(text, parseType);
1482     //         } catch (DateTimeParseException ex) {
1483     //             throw new ParseException(ex.getMessage(), ex.getErrorIndex());
1484     //         } catch (RuntimeException ex) {
1485     //             throw cast(ParseException) new ParseException(ex.getMessage(), 0).initCause(ex);
1486     //         }
1487     //     }
1488     //     override
1489     //     public Object parseObject(string text, ParsePosition pos) {
1490     //         assert(text, "text");
1491     //         DateTimeParseContext context;
1492     //         try {
1493     //             context = formatter.parseUnresolved0(text, pos);
1494     //         } catch (IndexOutOfBoundsException ex) {
1495     //             if (pos.getErrorIndex() < 0) {
1496     //                 pos.setErrorIndex(0);
1497     //             }
1498     //             return null;
1499     //         }
1500     //         if (context is null) {
1501     //             if (pos.getErrorIndex() < 0) {
1502     //                 pos.setErrorIndex(0);
1503     //             }
1504     //             return null;
1505     //         }
1506     //         try {
1507     //             TemporalAccessor resolved = context.toResolved(formatter.resolverStyle, formatter.resolverFields);
1508     //             if (parseType is null) {
1509     //                 return resolved;
1510     //             }
1511     //             return resolved.query(parseType);
1512     //         } catch (RuntimeException ex) {
1513     //             pos.setErrorIndex(0);
1514     //             return null;
1515     //         }
1516     //     }
1517     // }
1518 
1519 }