1/*
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
28 *
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions are met:
33 *
34 *  * Redistributions of source code must retain the above copyright notice,
35 *    this list of conditions and the following disclaimer.
36 *
37 *  * Redistributions in binary form must reproduce the above copyright notice,
38 *    this list of conditions and the following disclaimer in the documentation
39 *    and/or other materials provided with the distribution.
40 *
41 *  * Neither the name of JSR-310 nor the names of its contributors
42 *    may be used to endorse or promote products derived from this software
43 *    without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
48 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
49 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
50 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
53 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
54 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57package tck.java.time.temporal;
58
59import static java.time.format.ResolverStyle.LENIENT;
60import static java.time.format.ResolverStyle.SMART;
61import static java.time.format.ResolverStyle.STRICT;
62import static java.time.temporal.ChronoField.DAY_OF_MONTH;
63import static java.time.temporal.ChronoField.DAY_OF_WEEK;
64import static java.time.temporal.ChronoField.DAY_OF_YEAR;
65import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
66import static java.time.temporal.ChronoField.YEAR;
67import static org.testng.Assert.assertEquals;
68import static org.testng.Assert.assertFalse;
69import static org.testng.Assert.assertNotEquals;
70import static org.testng.Assert.assertSame;
71import static org.testng.Assert.assertTrue;
72
73import java.io.IOException;
74import java.time.DateTimeException;
75import java.time.DayOfWeek;
76import java.time.LocalDate;
77import java.time.format.DateTimeFormatter;
78import java.time.format.DateTimeFormatterBuilder;
79import java.time.temporal.ChronoUnit;
80import java.time.temporal.TemporalField;
81import java.time.temporal.ValueRange;
82import java.time.temporal.WeekFields;
83
84import org.testng.annotations.DataProvider;
85import org.testng.annotations.Test;
86import tck.java.time.AbstractTCKTest;
87
88/**
89 * Test WeekFields.
90 */
91@Test
92public class TCKWeekFields extends AbstractTCKTest {
93
94    @Test(dataProvider="weekFields")
95    public void test_of_DayOfWeek_int_singleton(DayOfWeek firstDayOfWeek, int minDays) {
96        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
97        assertEquals(week.getFirstDayOfWeek(), firstDayOfWeek, "Incorrect firstDayOfWeek");
98        assertEquals(week.getMinimalDaysInFirstWeek(), minDays, "Incorrect MinimalDaysInFirstWeek");
99        assertSame(WeekFields.of(firstDayOfWeek, minDays), week);
100    }
101
102    //-----------------------------------------------------------------------
103    @Test(dataProvider="weekFields")
104    public void test_basics(DayOfWeek firstDayOfWeek, int minDays) {
105        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
106        assertEquals(week.dayOfWeek().isDateBased(), true);
107        assertEquals(week.dayOfWeek().isTimeBased(), false);
108
109        assertEquals(week.weekOfMonth().isDateBased(), true);
110        assertEquals(week.weekOfMonth().isTimeBased(), false);
111
112        assertEquals(week.weekOfYear().isDateBased(), true);
113        assertEquals(week.weekOfYear().isTimeBased(), false);
114
115        assertEquals(week.weekOfWeekBasedYear().isDateBased(), true);
116        assertEquals(week.weekOfWeekBasedYear().isTimeBased(), false);
117
118        assertEquals(week.weekBasedYear().isDateBased(), true);
119        assertEquals(week.weekBasedYear().isTimeBased(), false);
120    }
121
122    //-----------------------------------------------------------------------
123    @Test
124    public void test_dayOfWeekField_simpleGet() {
125        LocalDate date = LocalDate.of(2000, 1, 10);  // Known to be ISO Monday
126        assertEquals(date.get(WeekFields.ISO.dayOfWeek()), 1);
127        assertEquals(date.get(WeekFields.of(DayOfWeek.MONDAY, 1).dayOfWeek()), 1);
128        assertEquals(date.get(WeekFields.of(DayOfWeek.MONDAY, 7).dayOfWeek()), 1);
129        assertEquals(date.get(WeekFields.SUNDAY_START.dayOfWeek()), 2);
130        assertEquals(date.get(WeekFields.of(DayOfWeek.SUNDAY, 1).dayOfWeek()), 2);
131        assertEquals(date.get(WeekFields.of(DayOfWeek.SUNDAY, 7).dayOfWeek()), 2);
132        assertEquals(date.get(WeekFields.of(DayOfWeek.SATURDAY, 1).dayOfWeek()), 3);
133        assertEquals(date.get(WeekFields.of(DayOfWeek.FRIDAY, 1).dayOfWeek()), 4);
134        assertEquals(date.get(WeekFields.of(DayOfWeek.TUESDAY, 1).dayOfWeek()), 7);
135    }
136
137    @Test
138    public void test_dayOfWeekField_simpleSet() {
139        LocalDate date = LocalDate.of(2000, 1, 10);  // Known to be ISO Monday
140        assertEquals(date.with(WeekFields.ISO.dayOfWeek(), 2), LocalDate.of(2000, 1, 11));
141        assertEquals(date.with(WeekFields.ISO.dayOfWeek(), 7), LocalDate.of(2000, 1, 16));
142
143        assertEquals(date.with(WeekFields.SUNDAY_START.dayOfWeek(), 3), LocalDate.of(2000, 1, 11));
144        assertEquals(date.with(WeekFields.SUNDAY_START.dayOfWeek(), 7), LocalDate.of(2000, 1, 15));
145
146        assertEquals(date.with(WeekFields.of(DayOfWeek.SATURDAY, 1).dayOfWeek(), 4), LocalDate.of(2000, 1, 11));
147        assertEquals(date.with(WeekFields.of(DayOfWeek.TUESDAY, 1).dayOfWeek(), 1), LocalDate.of(2000, 1, 4));
148    }
149
150    @Test(dataProvider="weekFields")
151    public void test_dayOfWeekField(DayOfWeek firstDayOfWeek, int minDays) {
152        LocalDate day = LocalDate.of(2000, 1, 10);  // Known to be ISO Monday
153        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
154        TemporalField f = week.dayOfWeek();
155
156        for (int i = 1; i <= 7; i++) {
157            assertEquals(day.get(f), (7 + day.getDayOfWeek().getValue() - firstDayOfWeek.getValue()) % 7 + 1);
158            day = day.plusDays(1);
159        }
160    }
161
162    @Test(dataProvider="weekFields")
163    public void test_weekOfMonthField(DayOfWeek firstDayOfWeek, int minDays) {
164        LocalDate day = LocalDate.of(2012, 12, 31);  // Known to be ISO Monday
165        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
166        TemporalField dowField = week.dayOfWeek();
167        TemporalField womField = week.weekOfMonth();
168
169        for (int i = 1; i <= 15; i++) {
170            int actualDOW = day.get(dowField);
171            int actualWOM = day.get(womField);
172
173            // Verify that the combination of day of week and week of month can be used
174            // to reconstruct the same date.
175            LocalDate day1 = day.withDayOfMonth(1);
176            int offset = - (day1.get(dowField) - 1);
177
178            int week1 = day1.get(womField);
179            if (week1 == 0) {
180                // week of the 1st is partial; start with first full week
181                offset += 7;
182            }
183
184            offset += actualDOW - 1;
185            offset += (actualWOM - 1) * 7;
186            LocalDate result = day1.plusDays(offset);
187
188            assertEquals(result, day, "Incorrect dayOfWeek or weekOfMonth: "
189                    + String.format("%s, ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n",
190                    week, day.getDayOfWeek(), offset, actualDOW, actualWOM, day, result));
191            day = day.plusDays(1);
192        }
193    }
194
195    @Test(dataProvider="weekFields")
196    public void test_weekOfYearField(DayOfWeek firstDayOfWeek, int minDays) {
197        LocalDate day = LocalDate.of(2012, 12, 31);  // Known to be ISO Monday
198        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
199        TemporalField dowField = week.dayOfWeek();
200        TemporalField woyField = week.weekOfYear();
201
202        for (int i = 1; i <= 15; i++) {
203            int actualDOW = day.get(dowField);
204            int actualWOY = day.get(woyField);
205
206            // Verify that the combination of day of week and week of month can be used
207            // to reconstruct the same date.
208            LocalDate day1 = day.withDayOfYear(1);
209            int offset = - (day1.get(dowField) - 1);
210            int week1 = day1.get(woyField);
211            if (week1 == 0) {
212                // week of the 1st is partial; start with first full week
213                offset += 7;
214            }
215            offset += actualDOW - 1;
216            offset += (actualWOY - 1) * 7;
217            LocalDate result = day1.plusDays(offset);
218
219            assertEquals(result, day, "Incorrect dayOfWeek or weekOfYear "
220                    + String.format("%s, ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n",
221                    week, day.getDayOfWeek(), offset, actualDOW, actualWOY, day, result));
222            day = day.plusDays(1);
223        }
224    }
225
226    /**
227     * Verify that the date can be reconstructed from the DOW, WeekOfWeekBasedYear,
228     * and WeekBasedYear for every combination of start of week
229     * and minimal days in week.
230     * @param firstDayOfWeek the first day of the week
231     * @param minDays the minimum number of days in the week
232     */
233    @Test(dataProvider="weekFields")
234    public void test_weekOfWeekBasedYearField(DayOfWeek firstDayOfWeek, int minDays) {
235        LocalDate day = LocalDate.of(2012, 12, 31);  // Known to be ISO Monday
236        WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays);
237        TemporalField dowField = weekDef.dayOfWeek();
238        TemporalField wowbyField = weekDef.weekOfWeekBasedYear();
239        TemporalField yowbyField = weekDef.weekBasedYear();
240
241        for (int i = 1; i <= 15; i++) {
242            int actualDOW = day.get(dowField);
243            int actualWOWBY = day.get(wowbyField);
244            int actualYOWBY = day.get(yowbyField);
245
246            // Verify that the combination of day of week and week of month can be used
247            // to reconstruct the same date.
248            LocalDate day1 = LocalDate.of(actualYOWBY, 1, 1);
249            DayOfWeek isoDOW = day1.getDayOfWeek();
250            int dow = (7 + isoDOW.getValue() - firstDayOfWeek.getValue()) % 7 + 1;
251
252            int weekStart = Math.floorMod(1 - dow, 7);
253            if (weekStart + 1 > weekDef.getMinimalDaysInFirstWeek()) {
254                // The previous week has the minimum days in the current month to be a 'week'
255                weekStart -= 7;
256            }
257            weekStart += actualDOW - 1;
258            weekStart += (actualWOWBY - 1) * 7;
259            LocalDate result = day1.plusDays(weekStart);
260
261            assertEquals(result, day, "Incorrect dayOfWeek or weekOfYear "
262                    + String.format("%s, ISO Dow: %s, weekStart: %s, actualDOW: %s, actualWOWBY: %s, YearOfWBY: %d, expected day: %s, result: %s%n",
263                    weekDef, day.getDayOfWeek(), weekStart, actualDOW, actualWOWBY, actualYOWBY, day, result));
264            day = day.plusDays(1);
265        }
266    }
267
268    @Test(dataProvider="weekFields")
269    public void test_fieldRanges(DayOfWeek firstDayOfWeek, int minDays) {
270        WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays);
271        TemporalField womField = weekDef.weekOfMonth();
272        TemporalField woyField = weekDef.weekOfYear();
273
274        LocalDate day = LocalDate.of(2012, 11, 30);
275        LocalDate endDay = LocalDate.of(2013, 1, 2);
276        while (day.isBefore(endDay)) {
277            LocalDate last = day.with(DAY_OF_MONTH, day.lengthOfMonth());
278            int lastWOM = last.get(womField);
279            LocalDate first = day.with(DAY_OF_MONTH, 1);
280            int firstWOM = first.get(womField);
281            ValueRange rangeWOM = day.range(womField);
282            assertEquals(rangeWOM.getMinimum(), firstWOM,
283                    "Range min should be same as WeekOfMonth for first day of month: "
284                    + first + ", " + weekDef);
285            assertEquals(rangeWOM.getMaximum(), lastWOM,
286                    "Range max should be same as WeekOfMonth for last day of month: "
287                    + last + ", " + weekDef);
288
289            last = day.with(DAY_OF_YEAR, day.lengthOfYear());
290            int lastWOY = last.get(woyField);
291            first = day.with(DAY_OF_YEAR, 1);
292            int firstWOY = first.get(woyField);
293            ValueRange rangeWOY = day.range(woyField);
294            assertEquals(rangeWOY.getMinimum(), firstWOY,
295                    "Range min should be same as WeekOfYear for first day of Year: "
296                    + day + ", " + weekDef);
297            assertEquals(rangeWOY.getMaximum(), lastWOY,
298                    "Range max should be same as WeekOfYear for last day of Year: "
299                    + day + ", " + weekDef);
300
301            day = day.plusDays(1);
302        }
303    }
304
305    //-----------------------------------------------------------------------
306    // withDayOfWeek()
307    //-----------------------------------------------------------------------
308    @Test(dataProvider="weekFields")
309    public void test_withDayOfWeek(DayOfWeek firstDayOfWeek, int minDays) {
310        LocalDate day = LocalDate.of(2012, 12, 15);  // Safely in the middle of a month
311        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
312        TemporalField dowField = week.dayOfWeek();
313        TemporalField womField = week.weekOfMonth();
314        TemporalField woyField = week.weekOfYear();
315
316        int wom = day.get(womField);
317        int woy = day.get(woyField);
318        for (int dow = 1; dow <= 7; dow++) {
319            LocalDate result = day.with(dowField, dow);
320            assertEquals(result.get(dowField), dow, String.format("Incorrect new Day of week: %s", result));
321            assertEquals(result.get(womField), wom, "Week of Month should not change");
322            assertEquals(result.get(woyField), woy, "Week of Year should not change");
323        }
324    }
325
326    @Test(dataProvider="weekFields")
327    public void test_rangeWeekOfWeekBasedYear(DayOfWeek firstDayOfWeek, int minDays) {
328        WeekFields weekFields = WeekFields.of(firstDayOfWeek, minDays);
329        TemporalField dowField = weekFields.dayOfWeek();
330        TemporalField wowByField = weekFields.weekOfWeekBasedYear();
331
332        LocalDate day1 = LocalDate.of(2012, 1, weekFields.getMinimalDaysInFirstWeek());
333        day1 = day1.with(wowByField, 1).with(dowField, 1);
334
335        LocalDate day2 = LocalDate.of(2013, 1, weekFields.getMinimalDaysInFirstWeek());
336        day2 = day2.with(wowByField, 1).with(dowField, 1);
337
338        int expectedWeeks = (int)ChronoUnit.DAYS.between(day1, day2) / 7;
339
340        ValueRange range = day1.range(wowByField);
341        assertEquals(range.getMaximum(), expectedWeeks, "Range incorrect");
342    }
343
344    @Test(dataProvider="weekFields")
345    public void test_withWeekOfWeekBasedYear(DayOfWeek firstDayOfWeek, int minDays) {
346        LocalDate day = LocalDate.of(2012, 12, 31);
347        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
348        TemporalField dowField = week.dayOfWeek();
349        TemporalField wowbyField = week.weekOfWeekBasedYear();
350        TemporalField yowbyField = week.weekBasedYear();
351
352        int dowExpected = (day.get(dowField) - 1) % 7 + 1;
353        LocalDate dowDate = day.with(dowField, dowExpected);
354        int dowResult = dowDate.get(dowField);
355        assertEquals(dowResult, dowExpected, "Localized DayOfWeek not correct; " + day + " -->" + dowDate);
356
357        int weekExpected = day.get(wowbyField) + 1;
358        ValueRange range = day.range(wowbyField);
359        weekExpected = ((weekExpected - 1) % (int)range.getMaximum()) + 1;
360        LocalDate weekDate = day.with(wowbyField, weekExpected);
361        int weekResult = weekDate.get(wowbyField);
362        assertEquals(weekResult, weekExpected, "Localized WeekOfWeekBasedYear not correct; " + day + " -->" + weekDate);
363
364        int yearExpected = day.get(yowbyField) + 1;
365
366        LocalDate yearDate = day.with(yowbyField, yearExpected);
367        int yearResult = yearDate.get(yowbyField);
368        assertEquals(yearResult, yearExpected, "Localized WeekBasedYear not correct; " + day  + " --> " + yearDate);
369
370        range = yearDate.range(wowbyField);
371        weekExpected = Math.min(day.get(wowbyField), (int)range.getMaximum());
372
373        int weekActual = yearDate.get(wowbyField);
374        assertEquals(weekActual, weekExpected, "Localized WeekOfWeekBasedYear week should not change; " + day + " --> " + yearDate + ", actual: " + weekActual + ", weekExpected: " + weekExpected);
375    }
376
377    //-----------------------------------------------------------------------
378    @Test(dataProvider="weekFields")
379    public void test_parse_resolve_localizedWom(DayOfWeek firstDayOfWeek, int minDays) {
380        LocalDate date = LocalDate.of(2012, 12, 15);
381        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
382        TemporalField womField = week.weekOfMonth();
383
384        for (int i = 1; i <= 60; i++) {
385            DateTimeFormatter f = new DateTimeFormatterBuilder()
386                    .appendValue(YEAR).appendLiteral(':')
387                    .appendValue(MONTH_OF_YEAR).appendLiteral(':')
388                    .appendValue(womField).appendLiteral(':')
389                    .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(SMART);
390            String str = date.getYear() + ":" + date.getMonthValue() + ":" +
391                    date.get(womField) + ":" + date.get(DAY_OF_WEEK);
392            LocalDate parsed = LocalDate.parse(str, f);
393            assertEquals(parsed, date, " ::" + str + "::" + i);
394
395            date = date.plusDays(1);
396        }
397    }
398
399    @Test(dataProvider="weekFields")
400    public void test_parse_resolve_localizedWom_lenient(DayOfWeek firstDayOfWeek, int minDays) {
401        LocalDate date = LocalDate.of(2012, 12, 15);
402        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
403        TemporalField womField = week.weekOfMonth();
404
405        for (int i = 1; i <= 60; i++) {
406            DateTimeFormatter f = new DateTimeFormatterBuilder()
407                    .appendValue(YEAR).appendLiteral(':')
408                    .appendValue(MONTH_OF_YEAR).appendLiteral(':')
409                    .appendValue(womField).appendLiteral(':')
410                    .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(LENIENT);
411            int wom = date.get(womField);
412            int dow = date.get(DAY_OF_WEEK);
413            for (int j = wom - 10; j < wom + 10; j++) {
414                String str = date.getYear() + ":" + date.getMonthValue() + ":" + j + ":" + dow;
415                LocalDate parsed = LocalDate.parse(str, f);
416                assertEquals(parsed, date.plusWeeks(j - wom), " ::" + str + ": :" + i + "::" + j);
417            }
418
419            date = date.plusDays(1);
420        }
421    }
422
423    @Test(dataProvider="weekFields")
424    public void test_parse_resolve_localizedWom_strict(DayOfWeek firstDayOfWeek, int minDays) {
425        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
426        TemporalField womField = week.weekOfMonth();
427        DateTimeFormatter f = new DateTimeFormatterBuilder()
428                .appendValue(YEAR).appendLiteral(':')
429                .appendValue(MONTH_OF_YEAR).appendLiteral(':')
430                .appendValue(womField).appendLiteral(':')
431                .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(STRICT);
432        String str = "2012:1:0:1";
433        try {
434            LocalDate date = LocalDate.parse(str, f);
435            assertEquals(date.getYear(), 2012);
436            assertEquals(date.getMonthValue(), 1);
437            assertEquals(date.get(womField), 0);
438            assertEquals(date.get(DAY_OF_WEEK), 1);
439        } catch (DateTimeException ex) {
440            // expected
441        }
442    }
443
444    //-----------------------------------------------------------------------
445    @Test(dataProvider="weekFields")
446    public void test_parse_resolve_localizedWomDow(DayOfWeek firstDayOfWeek, int minDays) {
447        LocalDate date = LocalDate.of(2012, 12, 15);
448        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
449        TemporalField dowField = week.dayOfWeek();
450        TemporalField womField = week.weekOfMonth();
451
452        for (int i = 1; i <= 15; i++) {
453            DateTimeFormatter f = new DateTimeFormatterBuilder()
454                    .appendValue(YEAR).appendLiteral(':')
455                    .appendValue(MONTH_OF_YEAR).appendLiteral(':')
456                    .appendValue(womField).appendLiteral(':')
457                    .appendValue(dowField).toFormatter();
458            String str = date.getYear() + ":" + date.getMonthValue() + ":" +
459                    date.get(womField) + ":" + date.get(dowField);
460            LocalDate parsed = LocalDate.parse(str, f);
461            assertEquals(parsed, date, " :: " + str + " " + i);
462
463            date = date.plusDays(1);
464        }
465    }
466
467    @Test(dataProvider="weekFields")
468    public void test_parse_resolve_localizedWomDow_lenient(DayOfWeek firstDayOfWeek, int minDays) {
469        LocalDate date = LocalDate.of(2012, 12, 15);
470        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
471        TemporalField dowField = week.dayOfWeek();
472        TemporalField womField = week.weekOfMonth();
473
474        for (int i = 1; i <= 60; i++) {
475            DateTimeFormatter f = new DateTimeFormatterBuilder()
476                    .appendValue(YEAR).appendLiteral(':')
477                    .appendValue(MONTH_OF_YEAR).appendLiteral(':')
478                    .appendValue(womField).appendLiteral(':')
479                    .appendValue(dowField).toFormatter().withResolverStyle(LENIENT);
480            int wom = date.get(womField);
481            int dow = date.get(dowField);
482            for (int j = wom - 10; j < wom + 10; j++) {
483                String str = date.getYear() + ":" + date.getMonthValue() + ":" + j + ":" + dow;
484                LocalDate parsed = LocalDate.parse(str, f);
485                assertEquals(parsed, date.plusWeeks(j - wom), " ::" + str + ": :" + i + "::" + j);
486            }
487
488            date = date.plusDays(1);
489        }
490    }
491
492    //-----------------------------------------------------------------------
493    @Test(dataProvider="weekFields")
494    public void test_parse_resolve_localizedWoy(DayOfWeek firstDayOfWeek, int minDays) {
495        LocalDate date = LocalDate.of(2012, 12, 15);
496        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
497        TemporalField woyField = week.weekOfYear();
498
499        for (int i = 1; i <= 60; i++) {
500            DateTimeFormatter f = new DateTimeFormatterBuilder()
501                    .appendValue(YEAR).appendLiteral(':')
502                    .appendValue(woyField).appendLiteral(':')
503                    .appendValue(DAY_OF_WEEK).toFormatter();
504            String str = date.getYear() + ":" +
505                    date.get(woyField) + ":" + date.get(DAY_OF_WEEK);
506            LocalDate parsed = LocalDate.parse(str, f);
507            assertEquals(parsed, date, " :: " + str + " " + i);
508
509            date = date.plusDays(1);
510        }
511    }
512
513    @Test(dataProvider="weekFields")
514    public void test_parse_resolve_localizedWoy_lenient(DayOfWeek firstDayOfWeek, int minDays) {
515        LocalDate date = LocalDate.of(2012, 12, 15);
516        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
517        TemporalField woyField = week.weekOfYear();
518
519        for (int i = 1; i <= 60; i++) {
520            DateTimeFormatter f = new DateTimeFormatterBuilder()
521                    .appendValue(YEAR).appendLiteral(':')
522                    .appendValue(woyField).appendLiteral(':')
523                    .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(LENIENT);
524            int woy = date.get(woyField);
525            int dow = date.get(DAY_OF_WEEK);
526            for (int j = woy - 60; j < woy + 60; j++) {
527                String str = date.getYear() + ":" + j + ":" + dow;
528                LocalDate parsed = LocalDate.parse(str, f);
529                assertEquals(parsed, date.plusWeeks(j - woy), " ::" + str + ": :" + i + "::" + j);
530            }
531
532            date = date.plusDays(1);
533        }
534    }
535
536    @Test(dataProvider="weekFields")
537    public void test_parse_resolve_localizedWoy_strict(DayOfWeek firstDayOfWeek, int minDays) {
538        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
539        TemporalField woyField = week.weekOfYear();
540        DateTimeFormatter f = new DateTimeFormatterBuilder()
541                .appendValue(YEAR).appendLiteral(':')
542                .appendValue(woyField).appendLiteral(':')
543                .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(STRICT);
544        String str = "2012:0:1";
545        try {
546            LocalDate date = LocalDate.parse(str, f);
547            assertEquals(date.getYear(), 2012);
548            assertEquals(date.get(woyField), 0);
549            assertEquals(date.get(DAY_OF_WEEK), 1);
550        } catch (DateTimeException ex) {
551            // expected
552        }
553    }
554
555    //-----------------------------------------------------------------------
556    @Test(dataProvider="weekFields")
557    public void test_parse_resolve_localizedWoyDow(DayOfWeek firstDayOfWeek, int minDays) {
558        LocalDate date = LocalDate.of(2012, 12, 15);
559        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
560        TemporalField dowField = week.dayOfWeek();
561        TemporalField woyField = week.weekOfYear();
562
563        for (int i = 1; i <= 60; i++) {
564            DateTimeFormatter f = new DateTimeFormatterBuilder()
565                    .appendValue(YEAR).appendLiteral(':')
566                    .appendValue(MONTH_OF_YEAR).appendLiteral(':')
567                    .appendValue(woyField).appendLiteral(':')
568                    .appendValue(dowField).toFormatter();
569            String str = date.getYear() + ":" + date.getMonthValue() + ":" +
570                    date.get(woyField) + ":" + date.get(dowField);
571            LocalDate parsed = LocalDate.parse(str, f);
572            assertEquals(parsed, date, " :: " + str + " " + i);
573
574            date = date.plusDays(1);
575        }
576    }
577
578    @Test(dataProvider="weekFields")
579    public void test_parse_resolve_localizedWoyDow_lenient(DayOfWeek firstDayOfWeek, int minDays) {
580        LocalDate date = LocalDate.of(2012, 12, 15);
581        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
582        TemporalField dowField = week.dayOfWeek();
583        TemporalField woyField = week.weekOfYear();
584
585        for (int i = 1; i <= 60; i++) {
586            DateTimeFormatter f = new DateTimeFormatterBuilder()
587                    .appendValue(YEAR).appendLiteral(':')
588                    .appendValue(woyField).appendLiteral(':')
589                    .appendValue(dowField).toFormatter().withResolverStyle(LENIENT);
590            int woy = date.get(woyField);
591            int dow = date.get(dowField);
592            for (int j = woy - 60; j < woy + 60; j++) {
593                String str = date.getYear() + ":" + j + ":" + dow;
594                LocalDate parsed = LocalDate.parse(str, f);
595                assertEquals(parsed, date.plusWeeks(j - woy), " ::" + str + ": :" + i + "::" + j);
596            }
597
598            date = date.plusDays(1);
599        }
600    }
601
602    //-----------------------------------------------------------------------
603    @Test(dataProvider="weekFields")
604    public void test_parse_resolve_localizedWoWBY(DayOfWeek firstDayOfWeek, int minDays) {
605        LocalDate date = LocalDate.of(2012, 12, 31);
606        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
607        TemporalField wowbyField = week.weekOfWeekBasedYear();
608        TemporalField yowbyField = week.weekBasedYear();
609
610        for (int i = 1; i <= 60; i++) {
611            DateTimeFormatter f = new DateTimeFormatterBuilder()
612                    .appendValue(yowbyField).appendLiteral(':')
613                    .appendValue(wowbyField).appendLiteral(':')
614                    .appendValue(DAY_OF_WEEK).toFormatter();
615            String str = date.get(yowbyField) + ":" + date.get(wowbyField) + ":" +
616                    date.get(DAY_OF_WEEK);
617            LocalDate parsed = LocalDate.parse(str, f);
618            assertEquals(parsed, date, " :: " + str + " " + i);
619
620            date = date.plusDays(1);
621        }
622    }
623
624    @Test(dataProvider="weekFields")
625    public void test_parse_resolve_localizedWoWBY_lenient(DayOfWeek firstDayOfWeek, int minDays) {
626        LocalDate date = LocalDate.of(2012, 12, 31);
627        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
628        TemporalField wowbyField = week.weekOfWeekBasedYear();
629        TemporalField yowbyField = week.weekBasedYear();
630
631        for (int i = 1; i <= 60; i++) {
632            DateTimeFormatter f = new DateTimeFormatterBuilder()
633                    .appendValue(yowbyField).appendLiteral(':')
634                    .appendValue(wowbyField).appendLiteral(':')
635                    .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(LENIENT);
636            int wowby = date.get(wowbyField);
637            int dow = date.get(DAY_OF_WEEK);
638            for (int j = wowby - 60; j < wowby + 60; j++) {
639                String str = date.get(yowbyField) + ":" + j + ":" + dow;
640                LocalDate parsed = LocalDate.parse(str, f);
641                assertEquals(parsed, date.plusWeeks(j - wowby), " ::" + str + ": :" + i + "::" + j);
642            }
643
644            date = date.plusDays(1);
645        }
646    }
647
648    @Test(dataProvider="weekFields")
649    public void test_parse_resolve_localizedWoWBY_strict(DayOfWeek firstDayOfWeek, int minDays) {
650        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
651        TemporalField wowbyField = week.weekOfWeekBasedYear();
652        TemporalField yowbyField = week.weekBasedYear();
653        DateTimeFormatter f = new DateTimeFormatterBuilder()
654                .appendValue(yowbyField).appendLiteral(':')
655                .appendValue(wowbyField).appendLiteral(':')
656                .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(STRICT);
657        String str = "2012:0:1";
658        try {
659            LocalDate date = LocalDate.parse(str, f);
660            assertEquals(date.get(yowbyField), 2012);
661            assertEquals(date.get(wowbyField), 0);
662            assertEquals(date.get(DAY_OF_WEEK), 1);
663        } catch (DateTimeException ex) {
664            // expected
665        }
666    }
667
668    //-----------------------------------------------------------------------
669    @Test(dataProvider="weekFields")
670    public void test_parse_resolve_localizedWoWBYDow(DayOfWeek firstDayOfWeek, int minDays) {
671        LocalDate date = LocalDate.of(2012, 12, 31);
672        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
673        TemporalField dowField = week.dayOfWeek();
674        TemporalField wowbyField = week.weekOfWeekBasedYear();
675        TemporalField yowbyField = week.weekBasedYear();
676
677        for (int i = 1; i <= 60; i++) {
678            DateTimeFormatter f = new DateTimeFormatterBuilder()
679                    .appendValue(yowbyField).appendLiteral(':')
680                    .appendValue(wowbyField).appendLiteral(':')
681                    .appendValue(dowField).toFormatter();
682            String str = date.get(yowbyField) + ":" + date.get(wowbyField) + ":" +
683                    date.get(dowField);
684            LocalDate parsed = LocalDate.parse(str, f);
685            assertEquals(parsed, date, " :: " + str + " " + i);
686
687            date = date.plusDays(1);
688        }
689    }
690
691    @Test(dataProvider="weekFields")
692    public void test_parse_resolve_localizedWoWBYDow_lenient(DayOfWeek firstDayOfWeek, int minDays) {
693        LocalDate date = LocalDate.of(2012, 12, 31);
694        WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
695        TemporalField dowField = week.dayOfWeek();
696        TemporalField wowbyField = week.weekOfWeekBasedYear();
697        TemporalField yowbyField = week.weekBasedYear();
698
699        for (int i = 1; i <= 60; i++) {
700            DateTimeFormatter f = new DateTimeFormatterBuilder()
701                    .appendValue(yowbyField).appendLiteral(':')
702                    .appendValue(wowbyField).appendLiteral(':')
703                    .appendValue(dowField).toFormatter().withResolverStyle(LENIENT);
704            int wowby = date.get(wowbyField);
705            int dow = date.get(dowField);
706            for (int j = wowby - 60; j < wowby + 60; j++) {
707                String str = date.get(yowbyField) + ":" + j + ":" + dow;
708                LocalDate parsed = LocalDate.parse(str, f);
709                assertEquals(parsed, date.plusWeeks(j - wowby), " ::" + str + ": :" + i + "::" + j);
710            }
711
712            date = date.plusDays(1);
713        }
714    }
715
716
717    //-----------------------------------------------------------------------
718    @DataProvider(name="weekFields")
719    Object[][] data_weekFields() {
720        Object[][] objects = new Object[49][];
721        int i = 0;
722        for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) {
723            for (int minDays = 1; minDays <= 7; minDays++) {
724                objects[i++] = new Object[] {firstDayOfWeek, minDays};
725            }
726        }
727        return objects;
728    }
729
730    //-----------------------------------------------------------------------
731    @DataProvider(name="WeekBasedYearData")
732    Object[][] provider_WeekBasedYearData() {
733        return new Object[][] {
734            {WeekFields.of(DayOfWeek.SUNDAY, 1),  2008, 52, 7, LocalDate.of(2008, 12, 27)},
735            {WeekFields.of(DayOfWeek.SUNDAY, 1),  2009,  1, 1, LocalDate.of(2008, 12, 28)},
736            {WeekFields.of(DayOfWeek.SUNDAY, 1),  2009,  1, 2, LocalDate.of(2008, 12, 29)},
737            {WeekFields.of(DayOfWeek.SUNDAY, 1),  2009,  1, 3, LocalDate.of(2008, 12, 30)},
738            {WeekFields.of(DayOfWeek.SUNDAY, 1),  2009,  1, 4, LocalDate.of(2008, 12, 31)},
739            {WeekFields.of(DayOfWeek.SUNDAY, 1),  2009,  1, 5, LocalDate.of(2009, 1, 1)},
740            {WeekFields.of(DayOfWeek.SUNDAY, 1),  2009,  2, 1, LocalDate.of(2009, 1, 4)},
741            {WeekFields.of(DayOfWeek.SUNDAY, 1),  2009,  2, 2, LocalDate.of(2009, 1, 5)},
742            {WeekFields.of(DayOfWeek.SUNDAY, 1),  2009,  2, 3, LocalDate.of(2009, 1, 6)},
743       };
744    }
745
746    @Test(dataProvider="WeekBasedYearData")
747    public void test_weekBasedYears(WeekFields weekDef, int weekBasedYear,
748            int weekOfWeekBasedYear, int dayOfWeek, LocalDate date) {
749        TemporalField dowField = weekDef.dayOfWeek();
750        TemporalField wowbyField = weekDef.weekOfWeekBasedYear();
751        TemporalField yowbyField = weekDef.weekBasedYear();
752        assertEquals(date.get(dowField), dayOfWeek, "DayOfWeek mismatch");
753        assertEquals(date.get(wowbyField), weekOfWeekBasedYear, "Week of WeekBasedYear mismatch");
754        assertEquals(date.get(yowbyField), weekBasedYear, "Year of WeekBasedYear mismatch");
755    }
756
757
758    //-----------------------------------------------------------------------
759    @DataProvider(name="IsoWeekData")
760    Object[][] data_week() {
761        return new Object[][] {
762                {LocalDate.of(1969, 12, 29), DayOfWeek.MONDAY, 1, 1970},
763                {LocalDate.of(2012, 12, 23), DayOfWeek.SUNDAY, 51, 2012},
764                {LocalDate.of(2012, 12, 24), DayOfWeek.MONDAY, 52, 2012},
765                {LocalDate.of(2012, 12, 27), DayOfWeek.THURSDAY, 52, 2012},
766                {LocalDate.of(2012, 12, 28), DayOfWeek.FRIDAY, 52, 2012},
767                {LocalDate.of(2012, 12, 29), DayOfWeek.SATURDAY, 52, 2012},
768                {LocalDate.of(2012, 12, 30), DayOfWeek.SUNDAY, 52, 2012},
769                {LocalDate.of(2012, 12, 31), DayOfWeek.MONDAY, 1, 2013},
770                {LocalDate.of(2013, 1, 1), DayOfWeek.TUESDAY, 1, 2013},
771                {LocalDate.of(2013, 1, 2), DayOfWeek.WEDNESDAY, 1, 2013},
772                {LocalDate.of(2013, 1, 6), DayOfWeek.SUNDAY, 1, 2013},
773                {LocalDate.of(2013, 1, 7), DayOfWeek.MONDAY, 2, 2013},
774        };
775    }
776
777    //-----------------------------------------------------------------------
778    // WEEK_OF_WEEK_BASED_YEAR
779    // Validate with the same data used by IsoFields.
780    //-----------------------------------------------------------------------
781    @Test(dataProvider="IsoWeekData")
782    public void test_WOWBY(LocalDate date, DayOfWeek dow, int week, int wby) {
783        WeekFields weekDef = WeekFields.ISO;
784        TemporalField dowField = weekDef.dayOfWeek();
785        TemporalField wowbyField = weekDef.weekOfWeekBasedYear();
786        TemporalField yowbyField = weekDef.weekBasedYear();
787
788        assertEquals(date.get(dowField), dow.getValue());
789        assertEquals(date.get(wowbyField), week);
790        assertEquals(date.get(yowbyField), wby);
791    }
792
793    //-----------------------------------------------------------------------
794    // equals() and hashCode().
795    //-----------------------------------------------------------------------
796    @Test
797    public void test_equals() {
798        WeekFields weekDef_iso = WeekFields.ISO;
799        WeekFields weekDef_sundayStart = WeekFields.SUNDAY_START;
800
801        assertTrue(weekDef_iso.equals(WeekFields.of(DayOfWeek.MONDAY, 4)));
802        assertTrue(weekDef_sundayStart.equals(WeekFields.of(DayOfWeek.SUNDAY, 1)));
803        assertEquals(weekDef_iso.hashCode(), WeekFields.of(DayOfWeek.MONDAY, 4).hashCode());
804        assertEquals(weekDef_sundayStart.hashCode(), WeekFields.of(DayOfWeek.SUNDAY, 1).hashCode());
805
806        assertFalse(weekDef_iso.equals(weekDef_sundayStart));
807        assertNotEquals(weekDef_iso.hashCode(), weekDef_sundayStart.hashCode());
808    }
809
810}
811