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  * This file is available under and governed by the GNU General Public
  28  * License version 2 only, as published by the Free Software Foundation.
  29  * However, the following notice accompanied the original version of this
  30  * file:
  31  *
  32  * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
  33  *
  34  * All rights reserved.
  35  *
  36  * Redistribution and use in source and binary forms, with or without
  37  * modification, are permitted provided that the following conditions are met:
  38  *
  39  *  * Redistributions of source code must retain the above copyright notice,
  40  *    this list of conditions and the following disclaimer.
  41  *
  42  *  * Redistributions in binary form must reproduce the above copyright notice,
  43  *    this list of conditions and the following disclaimer in the documentation
  44  *    and/or other materials provided with the distribution.
  45  *
  46  *  * Neither the name of JSR-310 nor the names of its contributors
  47  *    may be used to endorse or promote products derived from this software
  48  *    without specific prior written permission.
  49  *
  50  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  51  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  52  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  53  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  54  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  55  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  56  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  57  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  58  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  59  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  60  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61  */
  62 package build.tools.tzdb;
  63 
  64 import static build.tools.tzdb.ChronoField.HOUR_OF_DAY;
  65 import static build.tools.tzdb.ChronoField.MINUTE_OF_HOUR;
  66 import static build.tools.tzdb.ChronoField.SECOND_OF_MINUTE;
  67 import static build.tools.tzdb.ChronoField.SECOND_OF_DAY;
  68 
  69 import java.util.Objects;
  70 
  71 /**
  72  * A time without time-zone in the ISO-8601 calendar system,
  73  * such as {@code 10:15:30}.
  74  *
  75  */
  76 final class LocalTime {
  77 
  78     /**
  79      * The minimum supported {@code LocalTime}, '00:00'.
  80      * This is the time of midnight at the start of the day.
  81      */
  82     public static final LocalTime MIN;
  83     /**
  84      * The minimum supported {@code LocalTime}, '23:59:59.999999999'.
  85      * This is the time just before midnight at the end of the day.
  86      */
  87     public static final LocalTime MAX;
  88     /**
  89      * The time of midnight at the start of the day, '00:00'.
  90      */
  91     public static final LocalTime MIDNIGHT;
  92     /**
  93      * The time of noon in the middle of the day, '12:00'.
  94      */
  95     public static final LocalTime NOON;
  96     /**
  97      * Constants for the local time of each hour.
  98      */
  99     private static final LocalTime[] HOURS = new LocalTime[24];
 100     static {
 101         for (int i = 0; i < HOURS.length; i++) {
 102             HOURS[i] = new LocalTime(i, 0, 0);
 103         }
 104         MIDNIGHT = HOURS[0];
 105         NOON = HOURS[12];
 106         MIN = HOURS[0];
 107         MAX = new LocalTime(23, 59, 59);
 108     }
 109 
 110     /**
 111      * Hours per day.
 112      */
 113     static final int HOURS_PER_DAY = 24;
 114     /**
 115      * Minutes per hour.
 116      */
 117     static final int MINUTES_PER_HOUR = 60;
 118     /**
 119      * Minutes per day.
 120      */
 121     static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
 122     /**
 123      * Seconds per minute.
 124      */
 125     static final int SECONDS_PER_MINUTE = 60;
 126     /**
 127      * Seconds per hour.
 128      */
 129     static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
 130     /**
 131      * Seconds per day.
 132      */
 133     static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
 134     /**
 135      * Milliseconds per day.
 136      */
 137     static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
 138     /**
 139      * Microseconds per day.
 140      */
 141     static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
 142 
 143     /**
 144      * The hour.
 145      */
 146     private final byte hour;
 147     /**
 148      * The minute.
 149      */
 150     private final byte minute;
 151     /**
 152      * The second.
 153      */
 154     private final byte second;
 155 
 156     /**
 157      * Obtains an instance of {@code LocalTime} from an hour and minute.
 158      * <p>
 159      * The second and nanosecond fields will be set to zero by this factory method.
 160      * <p>
 161      * This factory may return a cached value, but applications must not rely on this.
 162      *
 163      * @param hour  the hour-of-day to represent, from 0 to 23
 164      * @param minute  the minute-of-hour to represent, from 0 to 59
 165      * @return the local time, not null
 166      * @throws DateTimeException if the value of any field is out of range
 167      */
 168     public static LocalTime of(int hour, int minute) {
 169         HOUR_OF_DAY.checkValidValue(hour);
 170         if (minute == 0) {
 171             return HOURS[hour];  // for performance
 172         }
 173         MINUTE_OF_HOUR.checkValidValue(minute);
 174         return new LocalTime(hour, minute, 0);
 175     }
 176 
 177     /**
 178      * Obtains an instance of {@code LocalTime} from an hour, minute and second.
 179      * <p>
 180      * The nanosecond field will be set to zero by this factory method.
 181      * <p>
 182      * This factory may return a cached value, but applications must not rely on this.
 183      *
 184      * @param hour  the hour-of-day to represent, from 0 to 23
 185      * @param minute  the minute-of-hour to represent, from 0 to 59
 186      * @param second  the second-of-minute to represent, from 0 to 59
 187      * @return the local time, not null
 188      * @throws DateTimeException if the value of any field is out of range
 189      */
 190     public static LocalTime of(int hour, int minute, int second) {
 191         HOUR_OF_DAY.checkValidValue(hour);
 192         if ((minute | second) == 0) {
 193             return HOURS[hour];  // for performance
 194         }
 195         MINUTE_OF_HOUR.checkValidValue(minute);
 196         SECOND_OF_MINUTE.checkValidValue(second);
 197         return new LocalTime(hour, minute, second);
 198     }
 199 
 200     /**
 201      * Obtains an instance of {@code LocalTime} from a second-of-day value.
 202      * <p>
 203      * This factory may return a cached value, but applications must not rely on this.
 204      *
 205      * @param secondOfDay  the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1}
 206      * @return the local time, not null
 207      * @throws DateTimeException if the second-of-day value is invalid
 208      */
 209     public static LocalTime ofSecondOfDay(int secondOfDay) {
 210         SECOND_OF_DAY.checkValidValue(secondOfDay);
 211         int hours = secondOfDay / SECONDS_PER_HOUR;
 212         secondOfDay -= hours * SECONDS_PER_HOUR;
 213         int minutes = secondOfDay / SECONDS_PER_MINUTE;
 214         secondOfDay -= minutes * SECONDS_PER_MINUTE;
 215         return create(hours, minutes, secondOfDay);
 216     }
 217 
 218 
 219     /**
 220      * Creates a local time from the hour, minute, second and nanosecond fields.
 221      * <p>
 222      * This factory may return a cached value, but applications must not rely on this.
 223      *
 224      * @param hour  the hour-of-day to represent, validated from 0 to 23
 225      * @param minute  the minute-of-hour to represent, validated from 0 to 59
 226      * @param second  the second-of-minute to represent, validated from 0 to 59
 227      * @return the local time, not null
 228      */
 229     private static LocalTime create(int hour, int minute, int second) {
 230         if ((minute | second) == 0) {
 231             return HOURS[hour];
 232         }
 233         return new LocalTime(hour, minute, second);
 234     }
 235 
 236     /**
 237      * Constructor, previously validated.
 238      *
 239      * @param hour  the hour-of-day to represent, validated from 0 to 23
 240      * @param minute  the minute-of-hour to represent, validated from 0 to 59
 241      * @param second  the second-of-minute to represent, validated from 0 to 59
 242      */
 243     private LocalTime(int hour, int minute, int second) {
 244         this.hour = (byte) hour;
 245         this.minute = (byte) minute;
 246         this.second = (byte) second;
 247     }
 248 
 249     /**
 250      * Gets the hour-of-day field.
 251      *
 252      * @return the hour-of-day, from 0 to 23
 253      */
 254     public int getHour() {
 255         return hour;
 256     }
 257 
 258     /**
 259      * Gets the minute-of-hour field.
 260      *
 261      * @return the minute-of-hour, from 0 to 59
 262      */
 263     public int getMinute() {
 264         return minute;
 265     }
 266 
 267     /**
 268      * Gets the second-of-minute field.
 269      *
 270      * @return the second-of-minute, from 0 to 59
 271      */
 272     public int getSecond() {
 273         return second;
 274     }
 275 
 276     /**
 277      * Returns a copy of this {@code LocalTime} with the specified period in seconds added.
 278      * <p>
 279      * This adds the specified number of seconds to this time, returning a new time.
 280      * The calculation wraps around midnight.
 281      * <p>
 282      * This instance is immutable and unaffected by this method call.
 283      *
 284      * @param secondstoAdd  the seconds to add, may be negative
 285      * @return a {@code LocalTime} based on this time with the seconds added, not null
 286      */
 287     public LocalTime plusSeconds(long secondstoAdd) {
 288         if (secondstoAdd == 0) {
 289             return this;
 290         }
 291         int sofd = hour * SECONDS_PER_HOUR +
 292                     minute * SECONDS_PER_MINUTE + second;
 293         int newSofd = ((int) (secondstoAdd % SECONDS_PER_DAY) + sofd + SECONDS_PER_DAY) % SECONDS_PER_DAY;
 294         if (sofd == newSofd) {
 295             return this;
 296         }
 297         int newHour = newSofd / SECONDS_PER_HOUR;
 298         int newMinute = (newSofd / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
 299         int newSecond = newSofd % SECONDS_PER_MINUTE;
 300         return create(newHour, newMinute, newSecond);
 301     }
 302 
 303     /**
 304      * Returns a copy of this {@code LocalTime} with the specified period in seconds subtracted.
 305      * <p>
 306      * This subtracts the specified number of seconds from this time, returning a new time.
 307      * The calculation wraps around midnight.
 308      * <p>
 309      * This instance is immutable and unaffected by this method call.
 310      *
 311      * @param secondsToSubtract  the seconds to subtract, may be negative
 312      * @return a {@code LocalTime} based on this time with the seconds subtracted, not null
 313      */
 314     public LocalTime minusSeconds(long secondsToSubtract) {
 315         return plusSeconds(-(secondsToSubtract % SECONDS_PER_DAY));
 316     }
 317 
 318     /**
 319      * Extracts the time as seconds of day,
 320      * from {@code 0} to {@code 24 * 60 * 60 - 1}.
 321      *
 322      * @return the second-of-day equivalent to this time
 323      */
 324     public int toSecondOfDay() {
 325         int total = hour * SECONDS_PER_HOUR;
 326         total += minute * SECONDS_PER_MINUTE;
 327         total += second;
 328         return total;
 329     }
 330 
 331      /**
 332      * Compares this {@code LocalTime} to another time.
 333      * <p>
 334      * The comparison is based on the time-line position of the local times within a day.
 335      * It is "consistent with equals", as defined by {@link Comparable}.
 336      *
 337      * @param other  the other time to compare to, not null
 338      * @return the comparator value, negative if less, positive if greater
 339      * @throws NullPointerException if {@code other} is null
 340      */
 341     public int compareTo(LocalTime other) {
 342         int cmp = Integer.compare(hour, other.hour);
 343         if (cmp == 0) {
 344             cmp = Integer.compare(minute, other.minute);
 345             if (cmp == 0) {
 346                 cmp = Integer.compare(second, other.second);
 347              }
 348         }
 349         return cmp;
 350     }
 351 
 352     /**
 353      * Checks if this time is equal to another time.
 354      * <p>
 355      * The comparison is based on the time-line position of the time within a day.
 356      * <p>
 357      * Only objects of type {@code LocalTime} are compared, other types return false.
 358      * To compare the date of two {@code TemporalAccessor} instances, use
 359      * {@link ChronoField#NANO_OF_DAY} as a comparator.
 360      *
 361      * @param obj  the object to check, null returns false
 362      * @return true if this is equal to the other time
 363      */
 364     @Override
 365     public boolean equals(Object obj) {
 366         if (this == obj) {
 367             return true;
 368         }
 369         if (obj instanceof LocalTime) {
 370             LocalTime other = (LocalTime) obj;
 371             return hour == other.hour && minute == other.minute &&
 372                     second == other.second;
 373         }
 374         return false;
 375     }
 376 
 377     /**
 378      * A hash code for this time.
 379      *
 380      * @return a suitable hash code
 381      */
 382     @Override
 383     public int hashCode() {
 384         long sod = toSecondOfDay();
 385         return (int) (sod ^ (sod >>> 32));
 386     }
 387 
 388 }