Skip to content

Commit 6ecc420

Browse files
committed
Duration converters #85
1 parent 2030bfa commit 6ecc420

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (C) 2012-2017 Typesafe Inc. <http://www.typesafe.com>
3+
*/
4+
package scala.compat.java8
5+
6+
import java.time.temporal.ChronoUnit
7+
import java.util.concurrent.TimeUnit
8+
import java.time.{Duration => JavaDuration}
9+
10+
import scala.concurrent.duration.{FiniteDuration, Duration => ScalaDuration}
11+
12+
13+
/**
14+
* This class contains static methods which convert between Java Durations
15+
* and the durations from the Scala concurrency package. This is useful when mediating between Scala and Java
16+
* libraries with asynchronous APIs where timeouts for example are often expressed as durations.
17+
*/
18+
object DurationConverters {
19+
20+
/**
21+
* Transform a Java duration into a Scala duration. If the nanosecond part of the Java duration is zero the returned
22+
* duration will have a time unit of seconds and if there is a nanoseconds part the Scala duration will have a time
23+
* unit of nanoseconds.
24+
*
25+
* @throws IllegalArgumentException If the given Java Duration is out of bounds of what can be expressed with the
26+
* Scala Durations.
27+
*/
28+
final def toScala(duration: java.time.Duration): scala.concurrent.duration.Duration = {
29+
if (duration.getNano == 0) {
30+
if (duration.getSeconds == 0) ScalaDuration.Zero
31+
else FiniteDuration(duration.getSeconds, TimeUnit.SECONDS)
32+
} else {
33+
FiniteDuration(
34+
duration.getSeconds * 1000000000 + duration.getNano,
35+
TimeUnit.NANOSECONDS
36+
)
37+
}
38+
}
39+
40+
/**
41+
* Transform a Scala duration into a Java duration. Note that the Scala duration keeps the time unit it was created
42+
* with while a Java duration always is a pair of seconds and nanos, so the unit it lost.
43+
*
44+
* @throws IllegalArgumentException If the Scala duration express a amount of time for the time unit that
45+
* a Java Duration can not express (infinite durations and undefined durations)
46+
*/
47+
final def toJava(duration: scala.concurrent.duration.Duration): java.time.Duration = {
48+
require(duration.isFinite(), s"Got [$duration] but only finite Scala durations can be expressed as a Java Durations")
49+
if (duration.length == 0) JavaDuration.ZERO
50+
else duration.unit match {
51+
case TimeUnit.NANOSECONDS => JavaDuration.ofNanos(duration.length)
52+
case TimeUnit.MICROSECONDS => JavaDuration.of(duration.length, ChronoUnit.MICROS)
53+
case TimeUnit.MILLISECONDS => JavaDuration.ofMillis(duration.length)
54+
case TimeUnit.SECONDS => JavaDuration.ofSeconds(duration.length)
55+
case TimeUnit.MINUTES => JavaDuration.ofMinutes(duration.length)
56+
case TimeUnit.HOURS => JavaDuration.ofHours(duration.length)
57+
case TimeUnit.DAYS => JavaDuration.ofDays(duration.length)
58+
}
59+
}
60+
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
3+
*/
4+
package scala.compat.java8
5+
6+
import org.junit.Test
7+
import org.junit.Assert._
8+
import java.time.{Duration => JavaDuration}
9+
10+
import scala.util.Try
11+
12+
class DurationConvertersTest {
13+
14+
import DurationConverters._
15+
import scala.concurrent.duration._
16+
17+
@Test
18+
def scalaNanosToJavaDuration(): Unit = {
19+
Seq[(Long, (Long, Int))](
20+
(Long.MinValue + 1) -> (-9223372037L, 145224193), // because java duration nanos are offset from the "wrong" direction
21+
-1000000001L -> (-2, 999999999),
22+
-1L -> (-1, 999999999),
23+
0L -> (0, 0),
24+
1L -> (0, 1),
25+
1000000001L -> (1,1),
26+
Long.MaxValue -> (9223372036L, 854775807)
27+
).foreach { case (n, (expSecs, expNanos)) =>
28+
val result = toJava(n.nanos)
29+
assertEquals(s"toJava($n nanos) -> $expSecs s)", expSecs, result.getSeconds)
30+
assertEquals(s"toJava($n nanos) -> $expNanos n)", expNanos, result.getNano)
31+
}
32+
}
33+
34+
@Test
35+
def scalaMilliSecondsToJavaDuration(): Unit = {
36+
Seq[(Long, (Long, Int))](
37+
-9223372036854L -> (-9223372037L, 146000000),
38+
-1L -> (-1L, 999000000),
39+
0L -> (0L, 0),
40+
1L -> (0L, 1000000),
41+
9223372036854L -> (9223372036L, 854000000)
42+
).foreach { case (n, (expSecs, expNanos)) =>
43+
val result = toJava(n.millis)
44+
assertEquals(s"toJava($n millis) -> $expSecs s)", expSecs, result.getSeconds)
45+
assertEquals(s"toJava($n millis) -> $expNanos n)", expNanos, result.getNano)
46+
}
47+
}
48+
49+
@Test
50+
def scalaMicroSecondsToJavaDuration(): Unit = {
51+
Seq[(Long, (Long, Int))](
52+
-9223372036854775L -> (-9223372037L, 145225000),
53+
-1L -> (-1L, 999999000),
54+
0L -> (0L, 0),
55+
1L -> (0L, 1000),
56+
9223372036854775L -> (9223372036L, 854775000)
57+
).foreach { case (n, (expSecs, expNanos)) =>
58+
val result = toJava(n.micros)
59+
assertEquals(s"toJava($n micros) -> $expSecs s)", expSecs, result.getSeconds)
60+
assertEquals(s"toJava($n micros) -> $expNanos n)", expNanos, result.getNano)
61+
}
62+
}
63+
64+
@Test
65+
def scalaSecondsToJavaDuration(): Unit = {
66+
Seq[(Long, (Long, Int))](
67+
-9223372036L -> (-9223372036L, 0),
68+
-1L -> (-1L, 0),
69+
0L -> (0L, 0),
70+
1L -> (1L, 0),
71+
9223372036L -> (9223372036L, 0)
72+
).foreach { case (n, (expSecs, expNanos)) =>
73+
val result = toJava(n.seconds)
74+
assertEquals(expSecs, result.getSeconds)
75+
assertEquals(expNanos, result.getNano)
76+
}
77+
}
78+
79+
80+
@Test
81+
def javaSecondsToScalaDuration(): Unit = {
82+
Seq[Long](-9223372036L, -1L, 0L, 1L, 9223372036L).foreach { n =>
83+
assertEquals(n, toScala(JavaDuration.ofSeconds(n)).toSeconds)
84+
}
85+
}
86+
87+
88+
@Test
89+
def javaNanosPartToScalaDuration(): Unit = {
90+
Seq[Long](Long.MinValue + 1L, -1L, 0L, 1L, Long.MaxValue).foreach { n =>
91+
assertEquals(n, toScala(JavaDuration.ofNanos(n)).toNanos)
92+
}
93+
}
94+
95+
@Test
96+
def unsupportedScalaDurationThrows(): Unit = {
97+
Seq(Duration.Inf, Duration.MinusInf, Duration.Undefined).foreach { d =>
98+
val res = Try { toJava(d) }
99+
assertTrue(s"Expected exception for $d but got success", res.isFailure)
100+
}
101+
}
102+
103+
@Test
104+
def unsupportedJavaDurationThrows(): Unit = {
105+
Seq(JavaDuration.ofSeconds(-9223372037L), JavaDuration.ofSeconds(9223372037L)).foreach { d =>
106+
val res = Try { toScala(d) }
107+
assertTrue(s"Expected exception for $d but got success", res.isFailure)
108+
}
109+
}
110+
111+
112+
}

0 commit comments

Comments
 (0)