1 /*
   2  * Copyright (c) 2004, 2016, 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  * @test
  26  * @bug 5090555 5091805
  27  * @summary Make sure that rolling DAY_OF_WEEK stays in the same week
  28  * around year boundaries.
  29  * @run main/othervm RollDayOfWeekTest 5 5
  30  */
  31 
  32 import java.util.*;
  33 
  34 import static java.util.Calendar.*;
  35 
  36 // Usage: java RollDayOfWeekTest [pastYears futureYears]
  37 public class RollDayOfWeekTest {
  38     public static void main(String[] args) {
  39         int pastYears = 5, futureYears = 23;
  40         if (args.length == 2) {
  41             pastYears = Integer.parseInt(args[0]);
  42             pastYears = Math.max(1, Math.min(pastYears, 5));
  43             futureYears = Integer.parseInt(args[1]);
  44             futureYears = Math.max(1, Math.min(futureYears, 28));
  45         }
  46 
  47         System.out.printf("Test [%d .. %+d] year range.%n", -pastYears, futureYears);
  48         Calendar cal = new GregorianCalendar();
  49         int year = cal.get(YEAR) - pastYears;
  50 
  51         // Use the all combinations of firstDayOfWeek and
  52         // minimalDaysInFirstWeek values in the year range current
  53         // year - pastYears to current year + futureYears.
  54         for (int fdw = SUNDAY; fdw <= SATURDAY; fdw++) {
  55             for (int mdifw = 1; mdifw <= 7; mdifw++) {
  56                 cal.clear();
  57                 cal.setFirstDayOfWeek(fdw);
  58                 cal.setMinimalDaysInFirstWeek(mdifw);
  59                 cal.set(year, JANUARY, 1);
  60                 checkRoll(cal, futureYears);
  61             }
  62         }
  63 
  64         // testing roll from BCE to CE
  65         year = -1;
  66         for (int fdw = SUNDAY; fdw <= SATURDAY; fdw++) {
  67             for (int mdifw = 1; mdifw <= 7; mdifw++) {
  68                 cal.clear();
  69                 cal.setFirstDayOfWeek(fdw);
  70                 cal.setMinimalDaysInFirstWeek(mdifw);
  71                 cal.set(year, JANUARY, 1);
  72                 checkRoll(cal, 4);
  73             }
  74         }
  75     }
  76 
  77 
  78     static void checkRoll(Calendar cal, int years) {
  79         Calendar cal2 = null, cal3 = null, prev = null;
  80         // Check 28 years
  81         for (int x = 0; x < (int)(365.2425*years); x++) {
  82             cal2 = (Calendar) cal.clone();
  83             cal3 = (Calendar) cal.clone();
  84 
  85             // roll foreword
  86             for (int i = 0; i < 10; i++) {
  87                 prev = (Calendar) cal2.clone();
  88                 cal2.roll(Calendar.DAY_OF_WEEK, +1);
  89                 roll(cal3, +1);
  90                 long t2 = cal2.getTimeInMillis();
  91                 long t3 = cal3.getTimeInMillis();
  92                 if (t2 != t3) {
  93                     System.err.println("prev: " + prev.getTime() + "\n" + prev);
  94                     System.err.println("cal2: " + cal2.getTime() + "\n" + cal2);
  95                     System.err.println("cal3: " + cal3.getTime() + "\n" + cal3);
  96                     throw new RuntimeException("+1: t2=" + t2 + ", t3=" + t3);
  97                 }
  98             }
  99 
 100             // roll backward
 101             for (int i = 0; i < 10; i++) {
 102                 prev = (Calendar) cal2.clone();
 103                 cal2.roll(Calendar.DAY_OF_WEEK, -1);
 104                 roll(cal3, -1);
 105                 long t2 = cal2.getTimeInMillis();
 106                 long t3 = cal3.getTimeInMillis();
 107                 if (t2 != t3) {
 108                     System.err.println("prev: " + prev.getTime() + "\n" + prev);
 109                     System.err.println("cal2: " + cal2.getTime() + "\n" + cal2);
 110                     System.err.println("cal3: " + cal3.getTime() + "\n" + cal3);
 111                     throw new RuntimeException("-1: t2=" + t2 + ", t3=" + t3);
 112                 }
 113             }
 114             cal.add(DAY_OF_YEAR, +1);
 115         }
 116     }
 117 
 118     // Another way to roll within the same week.
 119     static void roll(Calendar cal, int n) {
 120         int doy = cal.get(DAY_OF_YEAR);
 121         int diff = cal.get(DAY_OF_WEEK) - cal.getFirstDayOfWeek();
 122         if (diff < 0) {
 123             diff += 7;
 124         }
 125 
 126         // dow1: first day of the week
 127         int dow1 = doy - diff;
 128         n %= 7;
 129         doy += n;
 130         if (doy < dow1) {
 131             doy += 7;
 132         } else if (doy >= dow1 + 7) {
 133             doy -= 7;
 134         }
 135         cal.set(DAY_OF_YEAR, doy);
 136     }
 137 }