Skip to content

Commit

Permalink
Fixed zio#1012 - added zoneId to Clock (zio#1116)
Browse files Browse the repository at this point in the history
* Fixed zio#1012 - added zoneId to Clock

* Fixes zio#1012 change zoneId for OffsetDateTime

* zio#1012 respond to comments and abandon zoneId due to scalajs unavailability

* zio#1012 minor formatting

* need to retrigger build due to flaky test

* revert change to retrigger build but no changes since last push
  • Loading branch information
spf3000 authored and jdegoes committed Jul 7, 2019
1 parent d4fee2d commit 42f3553
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 10 deletions.
8 changes: 8 additions & 0 deletions core/shared/src/main/scala-2.12+/clock.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package zio
import zio.duration.Duration

import java.util.concurrent.TimeUnit
import java.time.OffsetDateTime

package object clock extends Clock.Service[Clock] {
final val clockService: ZIO[Clock, Nothing, Clock.Service[Any]] =
Expand All @@ -30,6 +31,12 @@ package object clock extends Clock.Service[Clock] {
final def currentTime(unit: TimeUnit): ZIO[Clock, Nothing, Long] =
ZIO.accessM(_.clock currentTime unit)

/**
* Get the current time, represented in the current timezone.
*/
def currentDateTime: ZIO[Clock, Nothing, OffsetDateTime] =
ZIO.accessM(_.clock.currentDateTime)

/**
* Returns the system nano time, which is not relative to any date.
*/
Expand All @@ -41,4 +48,5 @@ package object clock extends Clock.Service[Clock] {
*/
final def sleep(duration: Duration): ZIO[Clock, Nothing, Unit] =
ZIO.accessM(_.clock sleep duration)

}
9 changes: 9 additions & 0 deletions core/shared/src/main/scala/zio/clock/Clock.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import java.util.concurrent.TimeUnit
import zio.duration.Duration
import zio.scheduler.SchedulerLive
import zio.{ IO, UIO, ZIO }
import java.time.{ Instant, OffsetDateTime, ZoneId }

trait Clock extends Serializable {
val clock: Clock.Service[Any]
Expand All @@ -29,6 +30,7 @@ trait Clock extends Serializable {
object Clock extends Serializable {
trait Service[R] extends Serializable {
def currentTime(unit: TimeUnit): ZIO[R, Nothing, Long]
def currentDateTime: ZIO[R, Nothing, OffsetDateTime]
val nanoTime: ZIO[R, Nothing, Long]
def sleep(duration: Duration): ZIO[R, Nothing, Unit]
}
Expand All @@ -50,6 +52,13 @@ object Clock extends Serializable {
Left(ZIO.effectTotal(canceler()))
}
)

def currentDateTime: ZIO[Any, Nothing, OffsetDateTime] =
for {
millis <- currentTime(TimeUnit.MILLISECONDS)
zone <- ZIO.effectTotal(ZoneId.systemDefault)
} yield OffsetDateTime.ofInstant(Instant.ofEpochMilli(millis), zone)

}
}
object Live extends Live
Expand Down
24 changes: 21 additions & 3 deletions testkit/jvm/src/main/scala/zio/testkit/TestClock.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,22 @@
package zio.testkit

import java.util.concurrent.TimeUnit
import java.time.ZoneId

import zio._
import zio.duration.Duration
import zio.clock.Clock
import zio.testkit.TestClock.Data
import java.time.{ Instant, OffsetDateTime }

case class TestClock(ref: Ref[TestClock.Data]) extends Clock.Service[Any] {

final def currentTime(unit: TimeUnit): UIO[Long] =
ref.get.map(data => unit.convert(data.currentTimeMillis, TimeUnit.MILLISECONDS))

final def currentDateTime: UIO[OffsetDateTime] =
ref.get.map(data => TestClock.offset(data.currentTimeMillis, data.timeZone))

final val nanoTime: IO[Nothing, Long] =
ref.get.map(_.nanoTime)

Expand All @@ -38,13 +43,26 @@ case class TestClock(ref: Ref[TestClock.Data]) extends Clock.Service[Any] {

final def adjust(duration: Duration): UIO[Unit] =
ref.update { data =>
Data(data.nanoTime + duration.toNanos, data.currentTimeMillis + duration.toMillis, data.sleeps0)
Data(
data.nanoTime + duration.toNanos,
data.currentTimeMillis + duration.toMillis,
data.sleeps0,
data.timeZone
)
}.unit

}

object TestClock {
val Zero = Data(0, 0, Nil)
val Zero = Data(0, 0, Nil, ZoneId.of("UTC"))

def offset(millis: Long, timeZone: ZoneId): OffsetDateTime =
OffsetDateTime.ofInstant(Instant.ofEpochMilli(millis), timeZone)

case class Data(nanoTime: Long, currentTimeMillis: Long, sleeps0: List[Duration])
case class Data(
nanoTime: Long,
currentTimeMillis: Long,
sleeps0: List[Duration],
timeZone: ZoneId
)
}
38 changes: 31 additions & 7 deletions testkit/jvm/src/test/scala/zio/testkit/ClockSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ class ClockSpec(implicit ee: org.specs2.concurrent.ExecutionEnv) extends TestRun
Sleep does sleep instantly $e1
Sleep passes nanotime correctly $e2
Sleep passes currentTime correctly $e3
Sleep correctly records sleeps $e4
Adjust correctly advances nanotime $e5
Adjust correctly advances currentTime $e6
Adjust does not produce sleeps $e7
Sleep passes currentDateTime correctly $e4
Sleep correctly records sleeps $e5
Adjust correctly advances nanotime $e6
Adjust correctly advances currentTime $e7
Adjust correctly advances currentDateTime $e8
Adjust does not produce sleeps $e9
"""

def e1 =
Expand Down Expand Up @@ -49,6 +51,17 @@ class ClockSpec(implicit ee: org.specs2.concurrent.ExecutionEnv) extends TestRun
)

def e4 =
unsafeRun(
for {
ref <- Ref.make(TestClock.Zero)
testClock = TestClock(ref)
time1 <- testClock.currentDateTime
_ <- testClock.sleep(1.millis)
time2 <- testClock.currentDateTime
} yield (time2.toInstant.toEpochMilli - time1.toInstant.toEpochMilli) must_== 1L
)

def e5 =
unsafeRun(
for {
ref <- Ref.make(TestClock.Zero)
Expand All @@ -58,7 +71,7 @@ class ClockSpec(implicit ee: org.specs2.concurrent.ExecutionEnv) extends TestRun
} yield sleeps must_== List(1.milliseconds)
)

def e5 =
def e6 =
unsafeRun(
for {
ref <- Ref.make(TestClock.Zero)
Expand All @@ -69,7 +82,7 @@ class ClockSpec(implicit ee: org.specs2.concurrent.ExecutionEnv) extends TestRun
} yield (time2 - time1) must_== 1000000L
)

def e6 =
def e7 =
unsafeRun(
for {
ref <- Ref.make(TestClock.Zero)
Expand All @@ -80,7 +93,18 @@ class ClockSpec(implicit ee: org.specs2.concurrent.ExecutionEnv) extends TestRun
} yield (time2 - time1) must_== 1L
)

def e7 =
def e8 =
unsafeRun(
for {
ref <- Ref.make(TestClock.Zero)
testClock = TestClock(ref)
time1 <- testClock.currentDateTime
_ <- testClock.adjust(1.millis)
time2 <- testClock.currentDateTime
} yield (time2.toInstant.toEpochMilli - time1.toInstant.toEpochMilli) must_== 1L
)

def e9 =
unsafeRun(
for {
ref <- Ref.make(TestClock.Zero)
Expand Down

0 comments on commit 42f3553

Please sign in to comment.