Libraries for integration between the java.time
classes and common Scala libraries.
intime-coreprovides integration with the core Scala libraryintime-catsprovides instances for the Cats FP libraryintime-argonautprovides encoders and decoders for the Argonaut JSON libraryintime-scalacheckprovides instances for the Scalacheck property-based-testing library
Add the following to your build.sbt file:
val intimeVersion = "2.2.0"
libraryDependencies += "au.id.tmm.intime" %% "intime-core" % intimeVersion
libraryDependencies += "au.id.tmm.intime" %% "intime-cats" % intimeVersion // Cats integration
libraryDependencies += "au.id.tmm.intime" %% "intime-argonaut" % intimeVersion // Argonaut integration
libraryDependencies += "au.id.tmm.intime" %% "intime-scalacheck" % intimeVersion % Test // Scalacheck integrationintime-core adds integrations with the Scala standard library. Add it to your project with:
libraryDependencies += "au.id.tmm.intime" %% "intime-core" % "1.0.2"intime-core provides Ordering instances for all classes in the java.time package for which an ordering can be
defined. This includes the most common classes like Instant and LocalDate.
import java.time._
import au.id.tmm.intime.std.implicits._
val dates: List[LocalDate] = List(
LocalDate.of(2003, 3, 23),
LocalDate.of(2015, 3, 29),
LocalDate.of(2007, 4, 28),
)
dates.sorted // Sorts list of datesPeriod presents some problems when it comes to defining an Ordering instance, as any two instances cannot
necessarily be compared (is 1 month longer or shorter than 30 days?). intime-core provides a PartialOrdering for
each, handling those cases where an ordering can be computed.
intime-core provides overloaded operators for arithmetic and comparison operations on java.time classes:
import java.time._
import au.id.tmm.intime.std.implicits._
LocalDate.of(1999, 6, 20) + Period.ofDays(3) // 1999-06-23
Instant.EPOCH - Duration.ofSeconds(5) // 1969-12-31T23:59:55Z
Period.ofDays(5) * 3 // P15D
- Duration.ofHours(42) // PT-42H
Duration.ofDays(30) / 10 // P3D
Instant.MAX > Instant.EPOCH // trueintime-cats adds integrations with Cats. Add it to your project with:
libraryDependencies += "au.id.tmm.intime" %% "intime-cats" % "1.0.2"All instances are tested with discipline.
intime-cats provides Hash and Show instances for all classes in java.time.
import java.time._
import au.id.tmm.intime.cats.implicits._
import cats.syntax.show._
import cats.syntax.eq._
LocalDate.of(1999, 6, 20).show // 1999-06-20
Instant.EPOCH === Instant.EPOCH // trueintime-cats uses the orderings in intime-core to define Cats Order instances (PartialOrder for Period).
import java.time._
import au.id.tmm.intime.cats.implicits._
import cats.syntax.partialOrder._
LocalDate.of(2003, 3, 23) < LocalDate.of(2015, 3, 29) // true
Period.ofYears(1) < Period.ofMonths(13) // true
Period.ofDays(30) partialCompare Period.ofMonths(1) // NaNimport java.time._
import au.id.tmm.intime.cats.implicits._
import cats.syntax.group._
Duration.ofDays(1) |+| Duration.ofHours(2) // P1DT2H
Duration.ofDays(1) |-| Duration.ofHours(2) // PT22Hintime-scalacheck adds integrations with Scalacheck. Add it to your project
with:
libraryDependencies += "au.id.tmm.intime" %% "intime-scalacheck" % "1.0.2" % "test"intime-scalacheck provides instances of Arbitrary for all classes in java.time. These can be used to generate
arbitrary instances for property-based testing.
import java.time._
import au.id.tmm.intime.scalacheck._
import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks._
forAll { localDate: LocalDate =>
assert(localDate.plusDays(1) isAfter localDate)
}intime-scalacheck provides generators for "sensible" values of java.time classes. The generated values are all
between 1900 and 2100, allowing property-based-tests that don't have to worry about peculiarities like
year zero or durations that overflow.
import java.time._
import au.id.tmm.intime.scalacheck._
import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks._
forAll(genSensibleLocalDate) { localDate: LocalDate =>
assert(localDate.getYear >= 1900)
}intime-scalacheck provides instances of Choose, which let you define your own generators that produce values within
a range.
import java.time._
import au.id.tmm.intime.scalacheck._
import org.scalacheck.Gen
import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks._
val rangeGenerator: Gen[LocalDate] = Gen.choose(
min = LocalDate.of(2019, 5, 30),
max = LocalDate.of(2019, 7, 14),
)
forAll(rangeGenerator) { localDate: LocalDate =>
assert(localDate.getYear == 2019)
}intime-scalacheck provides instances for Shrink, which Scalacheck will use to try to identify the smallest value for
which a test fails. These are used automatically as long as you have the import:
import au.id.tmm.intime.scalacheck._intime-argonaut provides integration with the Argonaut library for JSON
handling. Add it to your project with:
libraryDependencies += "au.id.tmm.intime" %% "intime-argonaut" % "1.0.2"intime-argonaut defines EncodeJson and DecodeJson instances for all classes in the java.time package. They are
encoded and decoded to JSON strings according to the most obvious format (see
StandardCodecs.
import java.time._
import au.id.tmm.intime.argonaut._
import argonaut.Argonaut._
LocalDate.of(2019, 7, 14).asJson // jString("2019-07-14")
jString("2019-07-14").as[LocalDate] // DecodeResult.ok(LocalDate.of(2019, 7, 14))intime-argonaut allows for the definition of custom EncodeJson and DecodeJson instances using instances of
DateTimeFormatter.
import java.time._
import au.id.tmm.intime.argonaut._
import argonaut.Argonaut._
val formatter = DateTimeFormatter.ofPattern("MM-dd-uuuu")
implicit val customCodec = DateTimeFormatterCodecs.localDateCodecFrom(formatter)
LocalDate.of(2019, 7, 14).asJson // jString("07-14-2019")
jString("07-14-2019").as[LocalDate] // DecodeResult.ok(LocalDate.of(2019, 7, 14))- In Java 8, the standard codec for
ZonedDateTimewill fail to decode when the zone isGMT. This is fixed in Java 11. - In Java 8, the standard codec for
Durationwill drop the negative sign for durations between 0 and -1 seconds. This is fixed in Java 11.