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

lucuma.core.model.ObservingNight.scala Maven / Gradle / Ivy

There is a newer version: 0.108.0
Show newest version
// Copyright (c) 2016-2023 Association of Universities for Research in Astronomy, Inc. (AURA)
// For license information see LICENSE or https://opensource.org/licenses/BSD-3-Clause

package lucuma.core.model

import cats.*
import lucuma.core.enums.Site
import lucuma.core.enums.TwilightType
import lucuma.core.math.BoundedInterval
import monocle.Focus
import monocle.Lens
import org.typelevel.cats.time.*

import java.time.*

/**
 * An observing night is defined as the period of time from 14:00 on one day
 * until 14:00 on the following day.  In a timezone that honors daylight saving,
 * it is sometimes longer and sometimes shorter than a period of 24 hours.
 *
 * An `ObservingNight` pairs a `Site` with a `LocalObservingNight` to obtain
 * precise start/end `Instant`s.
 */
final case class ObservingNight(site: Site, toLocalObservingNight: LocalObservingNight)
    extends Night {

  /**
   * Constructs a [[TwilightBoundedNight]] for this observing night
   * according to the specified [[lucuma.core.enums.TwilightType]].
   *
   * Returns None if there's no sunset or sunrise for the specified
   * [[lucuma.core.enums.TwilightType]].
   */
  def twilightBounded(twilightType: TwilightType): Option[TwilightBoundedNight] =
    TwilightBoundedNight.fromTwilightTypeAndObservingNight(twilightType, this)

  /**
   * Constructs a [[TwilightBoundedNight]] for this observing night
   * according to the specified [[lucuma.core.enums.TwilightType]].
   *
   * Throws and exeception if there's no sunset or sunrise for the specified
   * [[lucuma.core.enums.TwilightType]].
   */
  def twilightBoundedUnsafe(twilightType: TwilightType): TwilightBoundedNight =
    twilightBounded(twilightType).get

  /** The `Interval`for the the observing night at the associated site. */
  override lazy val interval: BoundedInterval[Instant] =
    BoundedInterval.unsafeOpenUpper(
      toLocalObservingNight.start.atZone(site.timezone).toInstant,
      toLocalObservingNight.end.atZone(site.timezone).toInstant
    )

  /** The previous observing night. */
  def previous: ObservingNight =
    ObservingNight(site, toLocalObservingNight.previous)

  /** The next observing night. */
  def next: ObservingNight =
    ObservingNight(site, toLocalObservingNight.next)

  /** Returns the local date on which this observing night ends. */
  def toLocalDate: LocalDate =
    toLocalObservingNight.toLocalDate
}

object ObservingNight extends ObservingNightOptics {

  /**
   * Constructs the observing night that ends on the given local date for
   * for the given site.
   *
   * @group Constructors
   */
  def fromSiteAndLocalDate(s: Site, d: LocalDate): ObservingNight =
    ObservingNight(s, LocalObservingNight(d))

  /**
   * Constructs the observing night for the given site and local date time.
   *
   * @group Constructors
   */
  def fromSiteAndLocalDateTime(s: Site, d: LocalDateTime): ObservingNight =
    ObservingNight(s, LocalObservingNight.fromLocalDateTime(d))

  /**
   * Constructs the observing night that includes the given time at the
   * specified site.
   *
   * @group Constructors
   */
  def fromSiteAndInstant(s: Site, i: Instant): ObservingNight =
    ObservingNight(s, LocalObservingNight.fromSiteAndInstant(s, i))

  /** @group Typeclass Instances. */
  given Show[ObservingNight] =
    Show.fromToString

  /**
   * ObservingNight is ordered by site and local observing night.
   *
   * @group Typeclass Instances
   */
  given Order[ObservingNight] =
    Order.by(n => (n.site, n.toLocalObservingNight))

}

trait ObservingNightOptics {

  /** @group Optics */
  val site: Lens[ObservingNight, Site] =
    Focus[ObservingNight](_.site)

  /** @group Optics */
  val localObservingNight: Lens[ObservingNight, LocalObservingNight] =
    Focus[ObservingNight](_.toLocalObservingNight)

  /** @group Optics */
  val localDate: Lens[ObservingNight, LocalDate] =
    localObservingNight.andThen(LocalObservingNight.localDate)

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy