1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /*
  26  * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
  27  *
  28  * All rights reserved.
  29  *
  30  * Redistribution and use in source and binary forms, with or without
  31  * modification, are permitted provided that the following conditions are met:
  32  *
  33  *  * Redistributions of source code must retain the above copyright notice,
  34  *    this list of conditions and the following disclaimer.
  35  *
  36  *  * Redistributions in binary form must reproduce the above copyright notice,
  37  *    this list of conditions and the following disclaimer in the documentation
  38  *    and/or other materials provided with the distribution.
  39  *
  40  *  * Neither the name of JSR-310 nor the names of its contributors
  41  *    may be used to endorse or promote products derived from this software
  42  *    without specific prior written permission.
  43  *
  44  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  45  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  46  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  47  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  48  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  49  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  50  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  51  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  52  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  53  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  54  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  55  */
  56 package build.tools.tzdb;
  57 
  58 import java.util.Objects;
  59 
  60 class Utils {
  61 
  62     // Returns the largest (closest to positive infinity)
  63     public static long floorDiv(long x, long y) {
  64         long r = x / y;
  65         // if the signs are different and modulo not zero, round down
  66         if ((x ^ y) < 0 && (r * y != x)) {
  67             r--;
  68         }
  69         return r;
  70     }
  71 
  72     // Returns the floor modulus of the {@code long} arguments.
  73     public static long floorMod(long x, long y) {
  74         return x - floorDiv(x, y) * y;
  75     }
  76 
  77     // Returns the sum of its arguments,
  78     public static long addExact(long x, long y) {
  79         long r = x + y;
  80         // HD 2-12 Overflow iff both arguments have the opposite sign of the result
  81         if (((x ^ r) & (y ^ r)) < 0) {
  82             throw new ArithmeticException("long overflow");
  83         }
  84         return r;
  85     }
  86 
  87     // Year
  88 
  89     // Returns true if the specified year is a leap year.
  90     public static boolean isLeapYear(int year) {
  91         return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
  92     }
  93 
  94     // The minimum supported year, '-999,999,999'.
  95     public static final int YEAR_MIN_VALUE = -999_999_999;
  96 
  97     // The maximum supported year, '+999,999,999'.
  98     public static final int YEAR_MAX_VALUE = 999_999_999;
  99 
 100 
 101     // Gets the length of the specified month in days.
 102     public static int lengthOfMonth(int month, boolean leapYear) {
 103         switch (month) {
 104             case 2:        //FEBRUARY:
 105                 return (leapYear ? 29 : 28);
 106             case 4:        //APRIL:
 107             case 6:        //JUNE:
 108             case 9:        //SEPTEMBER:
 109             case 11:       //NOVEMBER:
 110                 return 30;
 111             default:
 112                 return 31;
 113         }
 114     }
 115 
 116     // Gets the maximum length of the specified month in days.
 117     public static int maxLengthOfMonth(int month) {
 118         switch (month) {
 119             case 2:           //FEBRUARY:
 120                 return 29;
 121             case 4:           //APRIL:
 122             case 6:           //JUNE:
 123             case 9:           //SEPTEMBER:
 124             case 11:          //NOVEMBER:
 125                 return 30;
 126             default:
 127                 return 31;
 128         }
 129     }
 130 
 131     // DayOfWeek
 132 
 133     // Returns the day-of-week that is the specified number of days after
 134     // this one, from 1 to 7 for Monday to Sunday.
 135     public static int plusDayOfWeek(int dow, long days) {
 136         int amount = (int) (days % 7);
 137         return (dow - 1 + (amount + 7)) % 7 + 1;
 138     }
 139 
 140     // Returns the day-of-week that is the specified number of days before
 141     // this one, from 1 to 7 for Monday to Sunday.
 142     public static int minusDayOfWeek(int dow, long days) {
 143         return plusDayOfWeek(dow, -(days % 7));
 144     }
 145 
 146     // Adjusts the date to the first occurrence of the specified day-of-week
 147     // before the date being adjusted unless it is already on that day in
 148     // which case the same object is returned.
 149     public static LocalDate previousOrSame(LocalDate date, int dayOfWeek) {
 150         return adjust(date, dayOfWeek, 1);
 151     }
 152 
 153     // Adjusts the date to the first occurrence of the specified day-of-week
 154     // after the date being adjusted unless it is already on that day in
 155     // which case the same object is returned.
 156     public static LocalDate nextOrSame(LocalDate date, int dayOfWeek) {
 157         return adjust(date, dayOfWeek, 0);
 158     }
 159 
 160     // Implementation of next, previous or current day-of-week.
 161     // @param relative  whether the current date is a valid answer
 162     private static final LocalDate adjust(LocalDate date, int dow, int relative) {
 163         int calDow = date.getDayOfWeek();
 164         if (relative < 2 && calDow == dow) {
 165             return date;
 166         }
 167         if ((relative & 1) == 0) {
 168             int daysDiff = calDow - dow;
 169             return date.plusDays(daysDiff >= 0 ? 7 - daysDiff : -daysDiff);
 170         } else {
 171             int daysDiff = dow - calDow;
 172             return date.minusDays(daysDiff >= 0 ? 7 - daysDiff : -daysDiff);
 173         }
 174     }
 175 
 176 }