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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * This file is available under and governed by the GNU General Public
26  * License version 2 only, as published by the Free Software Foundation.
27  * However, the following notice accompanied the original version of this
28  * file:
29  *
30  * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos
31  *
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions are met:
36  *
37  *  * Redistributions of source code must retain the above copyright notice,
38  *    this list of conditions and the following disclaimer.
39  *
40  *  * Redistributions in binary form must reproduce the above copyright notice,
41  *    this list of conditions and the following disclaimer in the documentation
42  *    and/or other materials provided with the distribution.
43  *
44  *  * Neither the name of JSR-310 nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
51  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
52  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
53  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
54  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
55  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
56  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
57  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
58  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59  */
60 package tck.java.time.format;
61 
62 import static org.testng.Assert.assertEquals;
63 
64 import java.time.LocalDateTime;
65 import java.time.OffsetDateTime;
66 import java.time.ZoneId;
67 import java.time.ZoneOffset;
68 import java.time.ZonedDateTime;
69 import java.time.format.DateTimeFormatter;
70 import java.time.format.DateTimeFormatterBuilder;
71 import java.time.format.TextStyle;
72 
73 import org.testng.annotations.BeforeMethod;
74 import org.testng.annotations.DataProvider;
75 import org.testng.annotations.Test;
76 
77 /**
78  * Test DateTimeFormatterBuilder.appendOffset().
79  */
80 @Test
81 public class TCKOffsetPrinterParser {
82 
83     private static final ZoneOffset OFFSET_UTC = ZoneOffset.UTC;
84     private static final ZoneOffset OFFSET_P0100 = ZoneOffset.ofHours(1);
85     private static final ZoneOffset OFFSET_P0123 = ZoneOffset.ofHoursMinutes(1, 23);
86     private static final ZoneOffset OFFSET_P0023 = ZoneOffset.ofHoursMinutes(0, 23);
87     private static final ZoneOffset OFFSET_P012345 = ZoneOffset.ofHoursMinutesSeconds(1, 23, 45);
88     private static final ZoneOffset OFFSET_P000045 = ZoneOffset.ofHoursMinutesSeconds(0, 0, 45);
89     private static final ZoneOffset OFFSET_M0100 = ZoneOffset.ofHours(-1);
90     private static final ZoneOffset OFFSET_M0123 = ZoneOffset.ofHoursMinutes(-1, -23);
91     private static final ZoneOffset OFFSET_M0023 = ZoneOffset.ofHoursMinutes(0, -23);
92     private static final ZoneOffset OFFSET_M012345 = ZoneOffset.ofHoursMinutesSeconds(-1, -23, -45);
93     private static final ZoneOffset OFFSET_M000045 = ZoneOffset.ofHoursMinutesSeconds(0, 0, -45);
94     private static final LocalDateTime DT_2012_06_30_12_30_40 = LocalDateTime.of(2012, 6, 30, 12, 30, 40);
95 
96     private DateTimeFormatterBuilder builder;
97 
98     @BeforeMethod
setUp()99     public void setUp() {
100         builder = new DateTimeFormatterBuilder();
101     }
102 
103     //-----------------------------------------------------------------------
104     @DataProvider(name="print")
data_print()105     Object[][] data_print() {
106         return new Object[][] {
107                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"},
108                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01"},
109                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+01"},
110                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "Z"},
111                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+01"},
112                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "Z"},
113                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01"},
114                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-01"},
115                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "Z"},
116                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01"},
117                 {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "Z"},
118 
119                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"},
120                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01"},
121                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+0123"},
122                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+0023"},
123                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+0123"},
124                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "Z"},
125                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01"},
126                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-0123"},
127                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-0023"},
128                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-0123"},
129                 {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "Z"},
130 
131                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"},
132                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+0100"},
133                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+0123"},
134                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+0023"},
135                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+0123"},
136                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "Z"},
137                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-0100"},
138                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-0123"},
139                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-0023"},
140                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-0123"},
141                 {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "Z"},
142 
143                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"},
144                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01:00"},
145                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+01:23"},
146                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+00:23"},
147                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+01:23"},
148                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "Z"},
149                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01:00"},
150                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-01:23"},
151                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-00:23"},
152                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01:23"},
153                 {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "Z"},
154 
155                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"},
156                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+0100"},
157                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+0123"},
158                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+0023"},
159                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+012345"},
160                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "+000045"},
161                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-0100"},
162                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-0123"},
163                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-0023"},
164                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-012345"},
165                 {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-000045"},
166 
167                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"},
168                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01:00"},
169                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+01:23"},
170                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+00:23"},
171                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+01:23:45"},
172                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"},
173                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01:00"},
174                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-01:23"},
175                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-00:23"},
176                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01:23:45"},
177                 {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"},
178 
179                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"},
180                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+010000"},
181                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+012300"},
182                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+002300"},
183                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+012345"},
184                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-000045"},
185                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-010000"},
186                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-012300"},
187                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-002300"},
188                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-012345"},
189                 {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-000045"},
190 
191                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"},
192                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01:00:00"},
193                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+01:23:00"},
194                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+00:23:00"},
195                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+01:23:45"},
196                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"},
197                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01:00:00"},
198                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-01:23:00"},
199                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-00:23:00"},
200                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01:23:45"},
201                 {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"},
202         };
203     }
204 
205     @DataProvider(name="print_localized")
data_print_localized()206     Object[][] data_print_localized() {
207         return new Object[][] {
208                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_UTC, "GMT"},
209                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_P0100, "GMT+01:00"},
210                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_P0123, "GMT+01:23"},
211                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_P0023, "GMT+00:23"},
212                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_P012345, "GMT+01:23:45"},
213                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_M000045, "GMT-00:00:45"},
214                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_M0100, "GMT-01:00"},
215                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_M0123, "GMT-01:23"},
216                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_M0023, "GMT-00:23"},
217                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_M012345, "GMT-01:23:45"},
218                 {TextStyle.FULL, DT_2012_06_30_12_30_40, OFFSET_M000045, "GMT-00:00:45"},
219                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_UTC, "GMT"},
220                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_P0100, "GMT+1"},
221                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_P0123, "GMT+1:23"},
222                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_P0023, "GMT+0:23"},
223                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_P012345, "GMT+1:23:45"},
224                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_M000045, "GMT-0:00:45"},
225                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_M0100, "GMT-1"},
226                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_M0123, "GMT-1:23"},
227                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_M0023, "GMT-0:23"},
228                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_M012345, "GMT-1:23:45"},
229                 {TextStyle.SHORT, DT_2012_06_30_12_30_40, OFFSET_M000045, "GMT-0:00:45"},
230         };
231     }
232 
233     @Test(dataProvider="print")
test_print(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected)234     public void test_print(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected) {
235         ZonedDateTime zdt = ldt.atZone(zone);
236         builder.appendOffset(offsetPattern, noOffset);
237         String output = builder.toFormatter().format(zdt);
238         assertEquals(output, expected);
239     }
240 
241     //-----------------------------------------------------------------------
242     @Test(dataProvider="print")
test_print_pattern_X(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected)243     public void test_print_pattern_X(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected) {
244         String pattern = null;
245         if (offsetPattern.equals("+HHmm") && noOffset.equals("Z")) {
246             pattern = "X";
247         } else if (offsetPattern.equals("+HHMM") && noOffset.equals("Z")) {
248             pattern = "XX";
249         } else if (offsetPattern.equals("+HH:MM") && noOffset.equals("Z")) {
250             pattern = "XXX";
251         } else if (offsetPattern.equals("+HHMMss") && noOffset.equals("Z")) {
252             pattern = "XXXX";
253         } else if (offsetPattern.equals("+HH:MM:ss") && noOffset.equals("Z")) {
254             pattern = "XXXXX";
255         }
256         if (pattern != null) {
257             ZonedDateTime zdt = ldt.atZone(zone);
258             builder.appendPattern(pattern);
259             String output = builder.toFormatter().format(zdt);
260             assertEquals(output, expected);
261         }
262     }
263 
264     @Test(dataProvider="print")
test_print_pattern_x(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected)265     public void test_print_pattern_x(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected) {
266         String pattern = null;
267         String zero = null;
268         if (offsetPattern.equals("+HHmm") && noOffset.equals("Z")) {
269             pattern = "x";
270             zero = "+00";
271         } else if (offsetPattern.equals("+HHMM") && noOffset.equals("Z")) {
272             pattern = "xx";
273             zero = "+0000";
274         } else if (offsetPattern.equals("+HH:MM") && noOffset.equals("Z")) {
275             pattern = "xxx";
276             zero = "+00:00";
277         } else if (offsetPattern.equals("+HHMMss") && noOffset.equals("Z")) {
278             pattern = "xxxx";
279             zero = "+0000";
280         } else if (offsetPattern.equals("+HH:MM:ss") && noOffset.equals("Z")) {
281             pattern = "xxxxx";
282             zero = "+00:00";
283         }
284         if (pattern != null) {
285             ZonedDateTime zdt = ldt.atZone(zone);
286             builder.appendPattern(pattern);
287             String output = builder.toFormatter().format(zdt);
288             assertEquals(output, (expected.equals("Z") ? zero : expected));
289         }
290     }
291 
292     @Test(dataProvider="print")
test_print_pattern_Z(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected)293     public void test_print_pattern_Z(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected) {
294         String pattern = null;
295         if (offsetPattern.equals("+HHMM") && noOffset.equals("Z")) {
296             ZonedDateTime zdt = ldt.atZone(zone);
297             DateTimeFormatter f1 = new DateTimeFormatterBuilder().appendPattern("Z").toFormatter();
298             String output1 = f1.format(zdt);
299             assertEquals(output1, (expected.equals("Z") ? "+0000" : expected));
300 
301             DateTimeFormatter f2 = new DateTimeFormatterBuilder().appendPattern("ZZ").toFormatter();
302             String output2 = f2.format(zdt);
303             assertEquals(output2, (expected.equals("Z") ? "+0000" : expected));
304 
305             DateTimeFormatter f3 = new DateTimeFormatterBuilder().appendPattern("ZZZ").toFormatter();
306             String output3 = f3.format(zdt);
307             assertEquals(output3, (expected.equals("Z") ? "+0000" : expected));
308         } else if (offsetPattern.equals("+HH:MM:ss") && noOffset.equals("Z")) {
309             ZonedDateTime zdt = ldt.atZone(zone);
310             DateTimeFormatter f = new DateTimeFormatterBuilder().appendPattern("ZZZZZ").toFormatter();
311             String output = f.format(zdt);
312             assertEquals(output, expected);
313         }
314     }
315 
316     @Test(dataProvider="print_localized")
test_print_localized(TextStyle style, LocalDateTime ldt, ZoneOffset offset, String expected)317     public void test_print_localized(TextStyle style, LocalDateTime ldt, ZoneOffset offset, String expected) {
318         OffsetDateTime odt = OffsetDateTime.of(ldt, offset);
319         ZonedDateTime zdt = ldt.atZone(offset);
320 
321         DateTimeFormatter f = new DateTimeFormatterBuilder().appendLocalizedOffset(style)
322                                                             .toFormatter();
323         assertEquals(f.format(odt), expected);
324         assertEquals(f.format(zdt), expected);
325         assertEquals(f.parse(expected, ZoneOffset::from), offset);
326 
327         if (style == TextStyle.FULL) {
328             f = new DateTimeFormatterBuilder().appendPattern("ZZZZ")
329                                               .toFormatter();
330             assertEquals(f.format(odt), expected);
331             assertEquals(f.format(zdt), expected);
332             assertEquals(f.parse(expected, ZoneOffset::from), offset);
333 
334             f = new DateTimeFormatterBuilder().appendPattern("OOOO")
335                                               .toFormatter();
336             assertEquals(f.format(odt), expected);
337             assertEquals(f.format(zdt), expected);
338             assertEquals(f.parse(expected, ZoneOffset::from), offset);
339         }
340 
341         if (style == TextStyle.SHORT) {
342             f = new DateTimeFormatterBuilder().appendPattern("O")
343                                               .toFormatter();
344             assertEquals(f.format(odt), expected);
345             assertEquals(f.format(zdt), expected);
346             assertEquals(f.parse(expected, ZoneOffset::from), offset);
347         }
348     }
349 
350     //-----------------------------------------------------------------------
351     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_X6rejected()352     public void test_print_pattern_X6rejected() {
353         builder.appendPattern("XXXXXX");
354     }
355 
356     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_x6rejected()357     public void test_print_pattern_x6rejected() {
358         builder.appendPattern("xxxxxx");
359     }
360 
361     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_Z6rejected()362     public void test_print_pattern_Z6rejected() {
363         builder.appendPattern("ZZZZZZ");
364     }
365 
366     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_O2rejected()367     public void test_print_pattern_O2rejected() {
368         builder.appendPattern("OO");
369     }
370 
371     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_O3rejected()372     public void test_print_pattern_O3rejected() {
373         builder.appendPattern("OOO");
374     }
375 
376     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_O5rejected()377     public void test_print_pattern_O5rejected() {
378         builder.appendPattern("OOOOO");
379     }
380 
381     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_localzed_full_standline()382     public void test_print_pattern_localzed_full_standline() {
383         builder.appendLocalizedOffset(TextStyle.FULL_STANDALONE);
384     }
385 
386     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_localzed_short_standalone()387     public void test_print_pattern_localzed_short_standalone() {
388         builder.appendLocalizedOffset(TextStyle.SHORT_STANDALONE);
389     }
390 
391     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_localzed_narrow()392     public void test_print_pattern_localzed_narrow() {
393         builder.appendLocalizedOffset(TextStyle.NARROW);
394     }
395 
396     @Test(expectedExceptions=IllegalArgumentException.class)
test_print_pattern_localzed_narrow_standalone()397     public void test_print_pattern_localzed_narrow_standalone() {
398         builder.appendLocalizedOffset(TextStyle.NARROW_STANDALONE);
399     }
400 
401 }
402