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

tofu.time.TimeData.scala Maven / Gradle / Ivy

package tofu.time

import java.time._
import cats.Monad
import scala.annotation.tailrec

/** typeclass for the types describing some time moment information possibly respecting timezone
  */
trait TimeData[A] {

  /** construct an instance from moment in time and time zone */
  def fromInstant(instant: Instant, zoneId: ZoneId): A

  final def map[B](f: A => B): TimeData[B] = (instant, zoneId) => f(fromInstant(instant, zoneId))
}

object TimeData {

  def apply[A](implicit td: TimeData[A]): TimeData[A] = td

  implicit val timeDataMonad: Monad[TimeData] = new Monad[TimeData] {
    def pure[A](x: A): TimeData[A] = (_, _) => x

    override def map[A, B](fa: TimeData[A])(f: A => B): TimeData[B] = fa.map(f)

    def flatMap[A, B](fa: TimeData[A])(f: A => TimeData[B]): TimeData[B] =
      (instant, zoneId) => f(fa.fromInstant(instant, zoneId)).fromInstant(instant, zoneId)

    def tailRecM[A, B](a: A)(f: A => TimeData[Either[A, B]]): TimeData[B] =
      (instant, zoneId) => {
        @tailrec def go(a: A): B = f(a).fromInstant(instant, zoneId) match {
          case Left(a)  => go(a)
          case Right(b) => b
        }
        go(a)
      }
  }

  implicit val instant: TimeData[Instant]               = (inst, _) => inst
  implicit val zonedDateTime: TimeData[ZonedDateTime]   = ZonedDateTime.ofInstant(_, _)
  implicit val localDateTime: TimeData[LocalDateTime]   = LocalDateTime.ofInstant(_, _)
  implicit val localDate: TimeData[LocalDate]           = localDateTime.map(_.toLocalDate)
  implicit val localTime: TimeData[LocalTime]           = localDateTime.map(_.toLocalTime)
  implicit val offsetDateTime: TimeData[OffsetDateTime] = OffsetDateTime.ofInstant(_, _)
  implicit val offsetTime: TimeData[OffsetTime]         = OffsetTime.ofInstant(_, _)
  implicit val month: TimeData[Month]                   = zonedDateTime.map(_.getMonth)
  implicit val monthDay: TimeData[MonthDay]             = zonedDateTime.map(zdt => MonthDay.of(zdt.getMonth, zdt.getDayOfMonth))
  implicit val dayOfWeek: TimeData[DayOfWeek]           = zonedDateTime.map(_.getDayOfWeek)
  implicit val year: TimeData[Year]                     = zonedDateTime.map(zdt => Year.of(zdt.getYear))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy