Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Licensed to the Apache Software Foundation (ASF) under one or more
0003  * contributor license agreements.  See the NOTICE file distributed with
0004  * this work for additional information regarding copyright ownership.
0005  * The ASF licenses this file to You under the Apache License, Version 2.0
0006  * (the "License"); you may not use this file except in compliance with
0007  * the License.  You may obtain a copy of the License at
0008  *
0009  *    http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS,
0013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014  * See the License for the specific language governing permissions and
0015  * limitations under the License.
0016  */
0017 
0018 package org.apache.spark.unsafe.types;
0019 
0020 import org.apache.spark.annotation.Unstable;
0021 
0022 import java.io.Serializable;
0023 import java.math.BigDecimal;
0024 import java.time.Duration;
0025 import java.time.Period;
0026 import java.time.temporal.ChronoUnit;
0027 import java.util.Objects;
0028 
0029 import static org.apache.spark.sql.catalyst.util.DateTimeConstants.*;
0030 
0031 /**
0032  * The class representing calendar intervals. The calendar interval is stored internally in
0033  * three components:
0034  * <ul>
0035  *   <li>an integer value representing the number of `months` in this interval,</li>
0036  *   <li>an integer value representing the number of `days` in this interval,</li>
0037  *   <li>a long value representing the number of `microseconds` in this interval.</li>
0038  * </ul>
0039  *
0040  * The `months` and `days` are not units of time with a constant length (unlike hours, seconds), so
0041  * they are two separated fields from microseconds. One month may be equal to 28, 29, 30 or 31 days
0042  * and one day may be equal to 23, 24 or 25 hours (daylight saving).
0043  *
0044  * @since 3.0.0
0045  */
0046 @Unstable
0047 public final class CalendarInterval implements Serializable {
0048   // NOTE: If you're moving or renaming this file, you should also update Unidoc configuration
0049   // specified in 'SparkBuild.scala'.
0050   public final int months;
0051   public final int days;
0052   public final long microseconds;
0053 
0054   // CalendarInterval is represented by months, days and microseconds. Months and days are not
0055   // units of time with a constant length (unlike hours, seconds), so they are two separated fields
0056   // from microseconds. One month may be equal to 29, 30 or 31 days and one day may be equal to
0057   // 23, 24 or 25 hours (daylight saving)
0058   public CalendarInterval(int months, int days, long microseconds) {
0059     this.months = months;
0060     this.days = days;
0061     this.microseconds = microseconds;
0062   }
0063 
0064   @Override
0065   public boolean equals(Object o) {
0066     if (this == o) return true;
0067     if (o == null || getClass() != o.getClass()) return false;
0068     CalendarInterval that = (CalendarInterval) o;
0069     return months == that.months &&
0070       days == that.days &&
0071       microseconds == that.microseconds;
0072   }
0073 
0074   @Override
0075   public int hashCode() {
0076     return Objects.hash(months, days, microseconds);
0077   }
0078 
0079   @Override
0080   public String toString() {
0081     if (months == 0 && days == 0 && microseconds == 0) {
0082       return "0 seconds";
0083     }
0084 
0085     StringBuilder sb = new StringBuilder();
0086 
0087     if (months != 0) {
0088       appendUnit(sb, months / 12, "years");
0089       appendUnit(sb, months % 12, "months");
0090     }
0091 
0092     appendUnit(sb, days, "days");
0093 
0094     if (microseconds != 0) {
0095       long rest = microseconds;
0096       appendUnit(sb, rest / MICROS_PER_HOUR, "hours");
0097       rest %= MICROS_PER_HOUR;
0098       appendUnit(sb, rest / MICROS_PER_MINUTE, "minutes");
0099       rest %= MICROS_PER_MINUTE;
0100       if (rest != 0) {
0101         String s = BigDecimal.valueOf(rest, 6).stripTrailingZeros().toPlainString();
0102         sb.append(s).append(" seconds ");
0103       }
0104     }
0105 
0106     sb.setLength(sb.length() - 1);
0107     return sb.toString();
0108   }
0109 
0110   private void appendUnit(StringBuilder sb, long value, String unit) {
0111     if (value != 0) {
0112       sb.append(value).append(' ').append(unit).append(' ');
0113     }
0114   }
0115 
0116   /**
0117    * Extracts the date part of the interval.
0118    * @return an instance of {@code java.time.Period} based on the months and days fields
0119    *         of the given interval, not null.
0120    */
0121   public Period extractAsPeriod() { return Period.of(0, months, days); }
0122 
0123   /**
0124    * Extracts the time part of the interval.
0125    * @return an instance of {@code java.time.Duration} based on the microseconds field
0126    *         of the given interval, not null.
0127    * @throws ArithmeticException if a numeric overflow occurs
0128    */
0129   public Duration extractAsDuration() { return Duration.of(microseconds, ChronoUnit.MICROS); }
0130 }