All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.time.Period.scala Maven / Gradle / Ivy

package java.time

import scala.collection.JavaConverters._

import java.time.chrono.{IsoChronology, ChronoPeriod}
import java.time.temporal._
import java.{util => ju}

final class Period private (years: Int, months: Int, days: Int)
    extends ChronoPeriod with Serializable {
  import ChronoUnit._

  def get(unit: TemporalUnit): Long = unit match {
    case YEARS  => years
    case MONTHS => months
    case DAYS   => days

    case _ =>
      throw new UnsupportedTemporalTypeException(s"Unsupported unit: $unit")
  }

  def getUnits(): ju.List[TemporalUnit] =
    Seq[TemporalUnit](YEARS, MONTHS, DAYS).asJava

  def getChronology(): IsoChronology = IsoChronology.INSTANCE

  override def isZero(): Boolean =
    years == 0 && months == 0 && days == 0

  override def isNegative(): Boolean =
    years < 0 || months < 0 || days < 0

  def getYears(): Int = years

  def getMonths(): Int = months

  def getDays(): Int = days

  def withYears(years: Int): Period = new Period(years, months, days)

  def withMonths(months: Int): Period = new Period(years, months, days)

  def withDays(days: Int): Period = new Period(years, months, days)

  def plus(amount: TemporalAmount): Period = {
    val other = Period.from(amount)
    val years1 = Math.addExact(years, other.getYears)
    val months1 = Math.addExact(months, other.getMonths)
    val days1 = Math.addExact(days, other.getDays)
    new Period(years1, months1, days1)
  }

  def plusYears(yearsToAdd: Long): Period = {
    val years1 = Math.addExact(years, yearsToAdd)
    new Period(Math.toIntExact(years1), months, days)
  }

  def plusMonths(monthsToAdd: Long): Period = {
    val months1 = Math.addExact(months, monthsToAdd)
    new Period(years, Math.toIntExact(months1), days)
  }

  def plusDays(daysToAdd: Long): Period = {
    val days1 = Math.addExact(days, daysToAdd)
    new Period(years, months, Math.toIntExact(days1))
  }

  def minus(amount: TemporalAmount): Period = {
    val other = Period.from(amount)
    val years1 = Math.subtractExact(years, other.getYears)
    val months1 = Math.subtractExact(months, other.getMonths)
    val days1 = Math.subtractExact(days, other.getDays)
    new Period(years1, months1, days1)
  }

  def minusYears(yearsToSubtract: Long): Period = {
    val years1 = Math.subtractExact(years, yearsToSubtract)
    new Period(Math.toIntExact(years1), months, days)
  }

  def minusMonths(monthsToSubtract: Long): Period = {
    val months1 = Math.subtractExact(months, monthsToSubtract)
    new Period(years, Math.toIntExact(months1), days)
  }

  def minusDays(daysToSubtract: Long): Period = {
    val days1 = Math.subtractExact(days, daysToSubtract)
    new Period(years, months, Math.toIntExact(days1))
  }

  def multipliedBy(scalar: Int): Period = {
    val years1 = Math.multiplyExact(years, scalar)
    val months1 = Math.multiplyExact(months, scalar)
    val days1 = Math.multiplyExact(days, scalar)
    new Period(years1, months1, days1)
  }

  override def negated(): Period = multipliedBy(-1)

  def normalized(): Period = {
    val quot = months / 12
    val months1 = months % 12
    val years1 = Math.addExact(years, quot)
    if (years1 > 0 && months1 < 0)
      new Period(years1 - 1, months1 + 12, days)
    else if (years1 < 0 && months1 > 0)
      new Period(years1 + 1, months1 - 12, days)
    else
      new Period(years1, months1, days)
  }

  def toTotalMonths(): Long = years.toLong * 12 + months

  def addTo(temporal: Temporal): Temporal = {
    // TODO: Check chronology (needs TemporalQuery)
    val t1 = {
      if (months == 0 && years != 0) temporal.plus(years, YEARS)
      else if (months != 0) temporal.plus(toTotalMonths, MONTHS)
      else temporal
    }
    if (days != 0) t1.plus(days, DAYS) else t1
  }

  def subtractFrom(temporal: Temporal): Temporal = {
    // TODO: Check chronology (needs TemporalQueries)
    val t1 = {
      if (months == 0 && years != 0) temporal.minus(years, YEARS)
      else if (months != 0) temporal.minus(toTotalMonths, MONTHS)
      else temporal
    }
    if (days != 0) t1.minus(days, DAYS) else t1
  }

  override def equals(other: Any): Boolean = other match {
    case that: Period =>
      years == that.getYears && months == that.getMonths && days == that.getDays

    case _ => false
  }

  override def hashCode(): Int =
    31 * (31 * years.hashCode + months.hashCode) + days.hashCode

  override def toString(): String = {
    if (isZero) "P0D"
    else {
      val yearPart = if (years != 0) years.toString + "Y" else ""
      val monthPart = if (months != 0) months.toString + "M" else ""
      val dayPart = if (days != 0) days.toString + "D" else ""
      "P" + yearPart + monthPart + dayPart
    }
  }
}

object Period {
  final lazy val ZERO = of(0, 0, 0)

  def ofYears(years: Int): Period = of(years, 0, 0)

  def ofMonths(months: Int): Period = of(0, months, 0)

  def ofWeeks(weeks: Int): Period = ofDays(weeks * 7)

  def ofDays(days: Int): Period = of(0, 0, days)

  def of(years: Int, months: Int, days: Int): Period =
    new Period(years, months, days)

  def from(amount: TemporalAmount): Period = amount match {
    case amount: Period => amount

    case _ =>
      amount.getUnits().asScala.foldLeft(ZERO) { (p, unit) =>
        unit match {
          case ChronoUnit.YEARS =>
            p.withYears(Math.toIntExact(amount.get(unit)))

          case ChronoUnit.MONTHS =>
            p.withMonths(Math.toIntExact(amount.get(unit)))

          case ChronoUnit.DAYS =>
            p.withDays(Math.toIntExact(amount.get(unit)))

          case _ =>
            throw new DateTimeException(s"Unit not allowed: $unit")
        }
      }
  }

  def between(start: LocalDate, end: LocalDate): Period = start.until(end)

  // TODO
  // def parse(text: CharSequence): Period
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy