Skip to content

Commit

Permalink
Merge 3d17b20 into ec21fff
Browse files Browse the repository at this point in the history
  • Loading branch information
mlopes committed May 2, 2019
2 parents ec21fff + 3d17b20 commit f618a49
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 11 deletions.
8 changes: 8 additions & 0 deletions README.md
Expand Up @@ -584,6 +584,8 @@ val time3 = Time(Hour(7), Minute(5))
val time4 = Time(Hour(7))
// time4: wen.datetime.Time = Time(Hour(7),Minute(0),Second(0),Millisecond(0))

import java.time.LocalTime

val time5 = Time(LocalTime.now)
// time5: wen.datetime.Time = Time(Hour(7),Minute(2),Second(48),Millisecond(159))
```
Expand Down Expand Up @@ -713,6 +715,7 @@ zoneTime1 === zoneTime4
| Constructors |
| ------------ |
| Date(day: [Day](#Day), month: [Month](#Month), year: [Year](#Year)): Option[Date] |
| Date(localDate: LocalDate): Date |
| Date.unsafe(day: [Day](#Day), month: [Month](#Month), year: [Year](#Year)): Date |

| Instances |
Expand Down Expand Up @@ -742,6 +745,11 @@ val unsafeDate = Date.unsafe(Day(31), August, Year(2019, AD))
// This creates an invalid date
val unsafeNotDate = Date.unsafe(Day(31), February, Year(2018, AD))
// unsafeNotDate: wen.datetime.Date = Date(Day(31),February,Year(2018,AD))

import java.time.LocalDate

val date2 = Date(LocalDate.now)
// date2: wen.datetime.Date = Date(Day(2),May,Year(2019,AD))
```

Because instances of cats's `Eq`, `Order` and `Show` are available, we can also do the following:
Expand Down
20 changes: 20 additions & 0 deletions src/main/scala/wen/datetime/Date.scala
@@ -1,6 +1,9 @@
package wen.datetime

import java.time.LocalDate

import wen.types._
import wen.refine.{refineDay, refineMonth, refineYear}

final case class Date private (day: Day, month: Month, year: Year)

Expand All @@ -21,5 +24,22 @@ object Date {
}
}

def apply(localDate: LocalDate): Date = {
val eitherDate: Either[String, Option[Date]] = for {
day <- refineDay(localDate.getDayOfMonth)
month <- refineMonth(localDate.getMonthValue)
year <-
if (localDate.getYear > 0)
refineYear(localDate.getYear).map[Year](Year(_))
else
refineYear(Math.abs(localDate.getYear - 1)).map[Year](Year(_, BC))
} yield Date(Day(day),Month(month), year)

// We run an unsafe operation here, because unless there's a bug in java.time.LocalDate
// we'll always have a Right, and we don't want the user to have to deal with an Option
// that is never a None.
eitherDate.toOption.flatten.get
}

def unsafe(day: Day, month: Month, year: Year): Date = new Date(day, month, year)
}
15 changes: 12 additions & 3 deletions src/test/scala/wen/datetime/DateSpec.scala
@@ -1,11 +1,15 @@
package wen.datetime

import wen.types._
import java.time.LocalDate

import eu.timepit.refined.auto._
import org.scalactic.TypeCheckedTripleEquals
import org.scalatest.{Matchers, WordSpec}
import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks
import wen.types._
import wen.test.Arbitraries._

class DateSpec extends WordSpec with Matchers with TypeCheckedTripleEquals {
class DateSpec extends WordSpec with Matchers with TypeCheckedTripleEquals with ScalaCheckDrivenPropertyChecks {
"Date" should {
"be created for a valid date" in {
val date1 = Date(Day(31), January, Year(2012, AD))
Expand Down Expand Up @@ -33,13 +37,18 @@ class DateSpec extends WordSpec with Matchers with TypeCheckedTripleEquals {
date5 should ===(None)
}

"created from an invalid date using unsafe" in {
"be created from an invalid date using unsafe" in {
val date = Date.unsafe(Day(31), April, Year(2019, AD))

date.day.day.value should ===(31)
date.month should ===(April)
date.year.year.value should ===(2019)
date.year.epoch should ===(AD)
}

"be created from a LocalDate" in forAll { localDate: LocalDate =>
val date = Date(localDate)
date shouldBe a[Date]
}
}
}
9 changes: 1 addition & 8 deletions src/test/scala/wen/datetime/TimeSpec.scala
Expand Up @@ -8,10 +8,10 @@ import org.scalacheck.Prop.forAll
import org.scalactic.TypeCheckedTripleEquals
import org.scalatest.{Matchers, WordSpec}
import org.scalatestplus.scalacheck.Checkers
import wen.test.Arbitraries._
import wen.types._

class TimeSpec extends WordSpec with Matchers with TypeCheckedTripleEquals with Checkers {
import TimeSpec._

"Time" should {
"be created from hour with everything else defaulting to 0" in {
Expand Down Expand Up @@ -68,10 +68,3 @@ class TimeSpec extends WordSpec with Matchers with TypeCheckedTripleEquals with
}
}

object TimeSpec {
implicit val localTimeArb: Arbitrary[LocalTime] = Arbitrary {
val rangeStart = LocalTime.MIN.toNanoOfDay
val rangeEnd = LocalTime.MAX.toNanoOfDay
Gen.choose(rangeStart, rangeEnd).map(i => LocalTime.ofNanoOfDay(i))
}
}
19 changes: 19 additions & 0 deletions src/test/scala/wen/test/Arbitraries.scala
@@ -0,0 +1,19 @@
package wen.test

import java.time.{LocalDate, LocalTime}

import org.scalacheck.{Arbitrary, Gen}

object Arbitraries {
implicit val localTimeArb: Arbitrary[LocalTime] = Arbitrary {
val rangeStart = LocalTime.MIN.toNanoOfDay
val rangeEnd = LocalTime.MAX.toNanoOfDay
Gen.choose(rangeStart, rangeEnd).map(i => LocalTime.ofNanoOfDay(i))
}

implicit val localDateArb: Arbitrary[LocalDate] = Arbitrary {
val rangeStart = LocalDate.MIN.toEpochDay
val rangeEnd = LocalDate.MAX.toEpochDay
Gen.choose(rangeStart, rangeEnd).map(i => LocalDate.ofEpochDay(i))
}
}

0 comments on commit f618a49

Please sign in to comment.