Skip to content

Commit 007b2c7

Browse files
committed
Initial implementation of Instant
1 parent 7445b3b commit 007b2c7

File tree

2 files changed

+387
-0
lines changed

2 files changed

+387
-0
lines changed
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
package java.time
2+
3+
import java.time.Preconditions._
4+
import java.time.temporal._
5+
import scala.scalajs.js
6+
7+
final class Instant(epochSecond:Long, nanoInSecond:Int) extends Temporal with TemporalAdjuster with Comparable[Instant]{
8+
9+
import ChronoUnit._
10+
import ChronoField._
11+
import Constants._
12+
import Instant._
13+
14+
requireDateTime(epochSecond >= MIN_EPOCH_SECOND && epochSecond <= MAX_EPOCH_SECOND, s"epochSecond out of range [$MIN_EPOCH_SECOND, $MAX_EPOCH_SECOND]")
15+
requireDateTime(nanoInSecond >= 0 && nanoInSecond <= 999999999, s"nanoInSecond out of range [0, 999999999]")
16+
17+
private def nanos(i:Instant):Long = i.getEpochSecond * NANOS_IN_SECOND + i.getNano
18+
19+
private val totalNanos: Long = nanos(this)
20+
21+
22+
def isBefore(o:Instant):Boolean = compareTo(o) < 0
23+
def isAfter(o:Instant):Boolean = compareTo(o) > 0
24+
25+
override def adjustInto(temporal: Temporal): Temporal = temporal.`with`(INSTANT_SECONDS, epochSecond).`with`(NANO_OF_SECOND, nanoInSecond)
26+
27+
override def compareTo(o: Instant): Int = totalNanos.compareTo(nanos(o))
28+
29+
override def isSupported(unit: TemporalUnit): Boolean = unit match {
30+
case _:ChronoUnit => unit == NANOS || unit == MICROS || unit == MILLIS || unit == SECONDS || unit == MINUTES || unit ==HOURS || unit == HALF_DAYS || unit == DAYS
31+
case null => false
32+
case _ => unit.isSupportedBy(this)
33+
}
34+
35+
def plus(amount: Long, unit: TemporalUnit): Instant = unit match {
36+
case _:ChronoUnit => unit match {
37+
case NANOS => plusNanos(amount)
38+
case MICROS => plusNanos(amount * NANOS_IN_MICRO)
39+
case MILLIS => plusNanos(amount * NANOS_IN_MILLI)
40+
case SECONDS => plusSeconds(amount)
41+
case MINUTES => plusSeconds(amount * SECONDS_IN_MINUTE)
42+
case HOURS => plusSeconds(amount * SECONDS_IN_HOUR)
43+
case HALF_DAYS => plusSeconds(amount * SECONDS_IN_HOUR * 12)
44+
case DAYS => plusSeconds(amount * SECONDS_IN_DAY)
45+
case _ => throw new UnsupportedTemporalTypeException(s"Unit not supported: $unit")
46+
}
47+
case _ => unit.addTo(this, amount)
48+
}
49+
50+
def plusNanos(nanosToAdd:Long):Instant = {
51+
Instant.ofEpochSecond(epochSecond + nanosToAdd/NANOS_IN_SECOND, (nanoInSecond + nanosToAdd) % NANOS_IN_SECOND)
52+
}
53+
54+
def plusMillis(millisToAdd:Long):Instant = plusNanos(millisToAdd * NANOS_IN_MILLI)
55+
56+
def plusSeconds(secondsToAdd:Long):Instant = Instant.ofEpochSecond(epochSecond + secondsToAdd, nanoInSecond)
57+
58+
override def until(end: Temporal, unit: TemporalUnit): Long = unit match {
59+
case _:ChronoUnit =>
60+
val endInstant = from(end)
61+
unit match {
62+
case NANOS => diffNanos(endInstant)
63+
case MICROS => diffNanos(endInstant) / NANOS_IN_MICRO
64+
case MILLIS => diffNanos(endInstant) / NANOS_IN_MILLI
65+
case SECONDS => diffSeconds(endInstant)
66+
case MINUTES => diffSeconds(endInstant) / SECONDS_IN_MINUTE
67+
case HOURS => diffSeconds(endInstant) / SECONDS_IN_HOUR
68+
case HALF_DAYS => diffSeconds(endInstant) / (SECONDS_IN_HOUR * 12)
69+
case DAYS => diffSeconds(endInstant) / SECONDS_IN_DAY
70+
case _ => throw new UnsupportedTemporalTypeException(s"Unit not supported: $unit")
71+
}
72+
case _ => unit.between(this, end)
73+
}
74+
75+
private def diffNanos(end: Instant): Long = end.totalNanos - totalNanos
76+
private def diffSeconds(end: Instant): Long = end.getEpochSecond - epochSecond
77+
78+
79+
def `with`(field: TemporalField, newValue: Long): Instant = field match {
80+
case _:ChronoField => field match {
81+
case NANO_OF_SECOND => new Instant(epochSecond, newValue.toInt)
82+
case MICRO_OF_SECOND => new Instant(epochSecond, (newValue * NANOS_IN_MICRO).toInt)
83+
case MILLI_OF_SECOND => new Instant(epochSecond, (newValue * NANOS_IN_MILLI).toInt)
84+
case INSTANT_SECONDS => new Instant(newValue, nanoInSecond)
85+
case _ => throw new UnsupportedTemporalTypeException(s"Field not supported: $field")
86+
}
87+
case _ => field.adjustInto(this, newValue)
88+
}
89+
override def isSupported(field: TemporalField): Boolean = field match {
90+
case _:ChronoField => field == NANO_OF_SECOND || field == MICRO_OF_SECOND || field == MILLI_OF_SECOND || field == INSTANT_SECONDS
91+
case null => false
92+
case _ => field.isSupportedBy(this)
93+
}
94+
override def getLong(field: TemporalField): Long = field match {
95+
case NANO_OF_SECOND => nanoInSecond
96+
case MICRO_OF_SECOND => nanoInSecond / NANOS_IN_MICRO
97+
case MILLI_OF_SECOND => nanoInSecond / NANOS_IN_MILLI
98+
case INSTANT_SECONDS => epochSecond
99+
case _ => throw new UnsupportedTemporalTypeException(s"Field not supported: $field")
100+
}
101+
102+
override def range(field: TemporalField): ValueRange = field match {
103+
case NANO_OF_SECOND => ValueRange.of(0, NANOS_IN_SECOND-1)
104+
case MICRO_OF_SECOND => ValueRange.of(0, MICROS_IN_SECOND-1)
105+
case MILLI_OF_SECOND => ValueRange.of(0, MILLIS_IN_SECOND-1)
106+
case INSTANT_SECONDS => ValueRange.of(Long.MinValue,Long.MaxValue)
107+
case _ =>
108+
throw new UnsupportedTemporalTypeException(s"Field not supported: $field")
109+
}
110+
111+
def minusNanos(nanosToSubstract:Long):Instant = plusNanos(-nanosToSubstract)
112+
113+
def minusMillis(millisToSubstract:Long):Instant = plusMillis(-millisToSubstract)
114+
115+
def minusSeconds(secondsToSubstract:Long):Instant = plusSeconds(-secondsToSubstract)
116+
117+
override def get(field: TemporalField): Int = field match {
118+
case INSTANT_SECONDS => throw new DateTimeException(s"$INSTANT_SECONDS is too large to fit in an Int")
119+
case _ => getLong(field).toInt
120+
}
121+
122+
def minus(amountToSubtract: Long, unit: TemporalUnit): Instant =
123+
if (amountToSubtract == Long.MinValue) plus(Long.MaxValue, unit).plus(1, unit)
124+
else plus(-amountToSubtract, unit)
125+
126+
def getNano():Int = nanoInSecond
127+
128+
def getEpochSecond():Long = epochSecond
129+
130+
def toEpochMilli():Long = epochSecond * MICROS_IN_SECOND + (nanoInSecond / NANOS_IN_MILLI)
131+
132+
override def toString: String = s"Instant(seconds:$epochSecond, nanoInSecond:$nanoInSecond"
133+
134+
override def equals(obj: scala.Any): Boolean = obj match {
135+
case o:Instant => epochSecond == o.getEpochSecond && nanoInSecond == o.getNano
136+
case _ => false
137+
}
138+
override def hashCode(): Int = totalNanos.hashCode()
139+
140+
def truncatedTo(unit:TemporalUnit):Instant = {
141+
if (unit == NANOS) this
142+
else if (unit.isTimeBased || unit == DAYS) {
143+
val duration = unit.getDuration
144+
val seconds = duration.getSeconds
145+
if (seconds > 0) Instant.ofEpochSecond(epochSecond - (epochSecond % seconds))
146+
else Instant.ofEpochSecond(epochSecond, nanoInSecond - (nanoInSecond % duration.getNano))
147+
} else throw new UnsupportedTemporalTypeException(s"Unit not supported: $unit")
148+
}
149+
}
150+
object Instant {
151+
import ChronoUnit._
152+
import ChronoField._
153+
import Constants._
154+
155+
private val MIN_EPOCH_SECOND: Long = -31557014167219200L
156+
private val MAX_EPOCH_SECOND: Long = 31556889864403199L
157+
158+
val MIN:Instant = new Instant(MIN_EPOCH_SECOND,0)
159+
val MAX:Instant = new Instant(MAX_EPOCH_SECOND,999999999)
160+
161+
val EPOCH:Instant = new Instant(0,0)
162+
163+
164+
def now():Instant = {
165+
val d = new js.Date()
166+
val millis: Double = d.getTime
167+
new Instant((millis / 1000).toLong, (millis % 1000 * 1000).toInt)
168+
}
169+
170+
def ofEpochSecond(epochSecond:Long):Instant = new Instant(epochSecond,0)
171+
172+
def ofEpochSecond(epochSecond:Long, nanoAdjustment:Long):Instant = {
173+
val mod = nanoAdjustment % NANOS_IN_SECOND
174+
if (mod <0) new Instant(epochSecond - (nanoAdjustment/NANOS_IN_SECOND) - 1, (NANOS_IN_SECOND + mod).toInt)
175+
else new Instant(epochSecond + (nanoAdjustment/NANOS_IN_SECOND), mod.toInt)
176+
}
177+
178+
private def ofNano(nanos:Long):Instant = {
179+
ofEpochSecond(nanos / NANOS_IN_SECOND, nanos % NANOS_IN_SECOND)
180+
}
181+
182+
def ofEpochMilli(epochMilli:Long):Instant =
183+
new Instant(epochMilli / MILLIS_IN_SECOND, ((epochMilli % MILLIS_IN_SECOND) * NANOS_IN_MILLI).toInt)
184+
185+
def from(temporal:TemporalAccessor): Instant = {
186+
Instant.ofEpochSecond(temporal.getLong(INSTANT_SECONDS), temporal.getLong(NANO_OF_SECOND))
187+
}
188+
189+
//Not implemented
190+
//def parse(text:CharSequence):Instant
191+
192+
}
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package org.scalajs.testsuite.javalib.time
2+
3+
import java.time.temporal.{ChronoField, ChronoUnit, UnsupportedTemporalTypeException}
4+
import java.time.{DateTimeException, Instant}
5+
6+
import org.junit.Assert._
7+
import org.junit.Test
8+
import org.scalajs.testsuite.utils.AssertThrows
9+
10+
class InstantTest extends TemporalTest[Instant]{
11+
12+
import AssertThrows._
13+
import DateTimeTestUtil._
14+
import Instant._
15+
import ChronoField._
16+
import ChronoUnit._
17+
18+
override def isSupported(unit: ChronoUnit): Boolean = unit == NANOS || unit == MICROS || unit == MILLIS ||
19+
unit == SECONDS || unit == MINUTES || unit ==HOURS || unit == HALF_DAYS || unit == DAYS
20+
override def isSupported(field: ChronoField): Boolean = field == NANO_OF_SECOND ||
21+
field == MICRO_OF_SECOND || field == MILLI_OF_SECOND || field == INSTANT_SECONDS
22+
23+
override val samples: Seq[Instant] = Seq(MIN, MAX, EPOCH)
24+
25+
@Test def test_getLong():Unit = {
26+
assertEquals(0L, MIN.getLong(NANO_OF_SECOND))
27+
assertEquals(0L, MIN.getLong(MICRO_OF_SECOND))
28+
assertEquals(0L, MIN.getLong(MILLI_OF_SECOND))
29+
assertEquals(-31557014167219200L, MIN.getLong(INSTANT_SECONDS))
30+
31+
assertEquals(999999999L, MAX.getLong(NANO_OF_SECOND))
32+
assertEquals(999999L, MAX.getLong(MICRO_OF_SECOND))
33+
assertEquals(999L, MAX.getLong(MILLI_OF_SECOND))
34+
assertEquals(31556889864403199L, MAX.getLong(INSTANT_SECONDS))
35+
36+
assertEquals(0L, EPOCH.getLong(NANO_OF_SECOND))
37+
assertEquals(0L, EPOCH.getLong(MICRO_OF_SECOND))
38+
assertEquals(0L, EPOCH.getLong(MILLI_OF_SECOND))
39+
assertEquals(0L, EPOCH.getLong(INSTANT_SECONDS))
40+
41+
}
42+
@Test def test_now():Unit = {
43+
assertNotNull(now())
44+
}
45+
46+
@Test def test_ofEpochSecond():Unit = {
47+
testDateTime(ofEpochSecond(0))(EPOCH)
48+
testDateTime(ofEpochSecond(0, 0))(EPOCH)
49+
testDateTime(ofEpochSecond(31556889864403199L, 999999999))(MAX)
50+
testDateTime(ofEpochSecond(-31557014167219200L, 0))(MIN)
51+
testDateTime(ofEpochSecond(123))(ofEpochSecond(123,0))
52+
testDateTime(ofEpochSecond(3, 1))(ofEpochSecond(4, -999999999))
53+
testDateTime(ofEpochSecond(3, 1))(ofEpochSecond(2, 1000000001))
54+
55+
expectThrows(classOf[DateTimeException], ofEpochSecond(31556889864403199L + 1))
56+
expectThrows(classOf[DateTimeException], ofEpochSecond(31556889864403199L, 999999999 + 1))
57+
expectThrows(classOf[DateTimeException], ofEpochSecond(-31557014167219200L - 1))
58+
expectThrows(classOf[DateTimeException], ofEpochSecond(-31557014167219200L - 1, -1))
59+
}
60+
61+
@Test def test_getNano():Unit = {
62+
assertEquals(0, EPOCH.getNano)
63+
assertEquals(0, MIN.getNano)
64+
assertEquals(999999999, MAX.getNano)
65+
assertEquals(1, ofEpochSecond(4, -999999999).getNano)
66+
assertEquals(1, ofEpochSecond(2, 1000000001).getNano)
67+
assertEquals(234567890, ofEpochSecond(1, 234567890).getNano)
68+
}
69+
70+
@Test def test_with():Unit = {
71+
val supportedFields = Set(NANO_OF_SECOND, MICRO_OF_SECOND, MILLI_OF_SECOND, INSTANT_SECONDS)
72+
for (t <- samples) {
73+
for (n <- Seq(0, 999, 999999, 999999999))
74+
testDateTime(t.`with`(NANO_OF_SECOND, n))(ofEpochSecond(t.getEpochSecond(), n))
75+
for (n <- Seq(0, 999, 999999))
76+
testDateTime(t.`with`(MICRO_OF_SECOND, n))(ofEpochSecond(t.getEpochSecond(), n * 1000))
77+
for (n <- Seq(0, 500, 999))
78+
testDateTime(t.`with`(MILLI_OF_SECOND, n))(ofEpochSecond(t.getEpochSecond(), n * 1000000))
79+
for (n <- Seq(-1000000000L, -86400L, -3600L, -60L, -1L, 0L, 1L, 60L, 3600L, 86400L, 1000000000L))
80+
testDateTime(t.`with`(INSTANT_SECONDS, n))(ofEpochSecond(n, t.getNano()))
81+
82+
for (f <- ChronoField.values()) {
83+
if (!supportedFields(f)) expectThrows(classOf[UnsupportedTemporalTypeException], t.`with`(f, 1))
84+
}
85+
86+
expectThrows(classOf[DateTimeException], t.`with`(NANO_OF_SECOND, -1))
87+
expectThrows(classOf[DateTimeException], t.`with`(NANO_OF_SECOND, 999999999+1))
88+
expectThrows(classOf[DateTimeException], t.`with`(MICRO_OF_SECOND, -1))
89+
expectThrows(classOf[DateTimeException], t.`with`(MICRO_OF_SECOND, 999999+1))
90+
expectThrows(classOf[DateTimeException], t.`with`(MILLI_OF_SECOND, -1))
91+
expectThrows(classOf[DateTimeException], t.`with`(MILLI_OF_SECOND, 999+1))
92+
expectThrows(classOf[DateTimeException], t.`with`(INSTANT_SECONDS, MIN.getEpochSecond-1))
93+
expectThrows(classOf[DateTimeException], t.`with`(INSTANT_SECONDS, MAX.getEpochSecond+1))
94+
}
95+
}
96+
97+
@Test def test_truncatedTo():Unit = {
98+
testDateTime(MIN.truncatedTo(NANOS))(MIN)
99+
testDateTime(MIN.truncatedTo(MICROS))(MIN)
100+
testDateTime(MIN.truncatedTo(MILLIS))(MIN)
101+
testDateTime(MIN.truncatedTo(SECONDS))(MIN)
102+
testDateTime(MIN.truncatedTo(MINUTES))(MIN)
103+
testDateTime(MIN.truncatedTo(HOURS))(MIN)
104+
testDateTime(MIN.truncatedTo(HALF_DAYS))(MIN)
105+
testDateTime(MIN.truncatedTo(DAYS))(MIN)
106+
107+
testDateTime(MAX.truncatedTo(NANOS))(MAX)
108+
testDateTime(MAX.truncatedTo(MICROS))(MAX.minusNanos(999))
109+
testDateTime(MAX.truncatedTo(MILLIS))(MAX.minusNanos(999999))
110+
testDateTime(MAX.truncatedTo(SECONDS))(MAX.minusNanos(999999999))
111+
testDateTime(MAX.truncatedTo(MINUTES))(MAX.minusNanos(999999999).minusSeconds(59))
112+
testDateTime(MAX.truncatedTo(HOURS))(MAX.minusNanos(999999999).minusSeconds(59).minus(59, MINUTES))
113+
testDateTime(MAX.truncatedTo(HALF_DAYS))(MAX.minusNanos(999999999).minusSeconds(59).minus(59, MINUTES).minus(11, HOURS))
114+
testDateTime(MAX.truncatedTo(DAYS))(MAX.minusNanos(999999999).minusSeconds(59).minus(59, MINUTES).minus(23, HOURS))
115+
}
116+
117+
118+
@Test def test_ofEpochMilli():Unit = {
119+
testDateTime(ofEpochMilli(0))(EPOCH)
120+
testDateTime(ofEpochMilli(1234))(ofEpochSecond(1,234000000))
121+
}
122+
123+
@Test def test_from():Unit = {
124+
for (t <- samples)
125+
testDateTime(from(t))(t)
126+
}
127+
128+
@Test def test_compareTto():Unit = {
129+
assertEquals(0, MIN.compareTo(MIN))
130+
assertEquals(0, MAX.compareTo(MAX))
131+
assertTrue(MAX.compareTo(MIN) > 0)
132+
assertTrue(MIN.compareTo(MAX) < 0)
133+
}
134+
135+
@Test def test_isAfter(): Unit = {
136+
assertFalse(MIN.isAfter(MIN))
137+
assertFalse(MIN.isAfter(MAX))
138+
assertTrue(MAX.isAfter(MIN))
139+
assertFalse(MAX.isAfter(MAX))
140+
}
141+
142+
@Test def test_isBefore(): Unit = {
143+
assertFalse(MIN.isBefore(MIN))
144+
assertTrue(MIN.isBefore(MAX))
145+
assertFalse(MAX.isBefore(MIN))
146+
assertFalse(MAX.isBefore(MAX))
147+
}
148+
149+
@Test def test_adjustInto():Unit = {
150+
for {
151+
t1 <- samples
152+
t2 <- samples
153+
} {
154+
testDateTime(t1.adjustInto(t2))(t1)
155+
}
156+
}
157+
158+
159+
@Test def test_until(): Unit = {
160+
assertEquals(63113904031622399L, MIN.until(MAX, SECONDS) )
161+
assertEquals(1051898400527039L, MIN.until(MAX, MINUTES))
162+
assertEquals(17531640008783L, MIN.until(MAX, HOURS))
163+
assertEquals(1460970000731L, MIN.until(MAX, HALF_DAYS))
164+
assertEquals(730485000365L, MIN.until(MAX, DAYS))
165+
166+
for (u <- timeBasedUnits) {
167+
assertEquals(-MIN.until(MAX, u), MAX.until(MIN, u))
168+
assertEquals(0L, MIN.until(MIN, u))
169+
assertEquals(0L, MAX.until(MAX, u))
170+
}
171+
for (u <- dateBasedUnits) {
172+
if (u != DAYS)
173+
expectThrows(classOf[UnsupportedTemporalTypeException], MIN.until(MIN, u))
174+
}
175+
}
176+
177+
@Test def test_plus():Unit = {
178+
val values = Seq(Long.MinValue, -1000000000L, -86400L, -3600L, -60L, -1L, 0L,
179+
1L, 60L, 3600L, 86400L, 1000000000L, Long.MaxValue)
180+
181+
for {
182+
t <- samples
183+
n <- values
184+
} {
185+
testDateTime(t.plus(n, NANOS))(t.plusNanos(n))
186+
testDateTime(t.plus(n, MICROS))(t.plusNanos(n * 1000))
187+
testDateTime(t.plus(n, MILLIS))(t.plusNanos(n * 1000000))
188+
testDateTime(t.plus(n, SECONDS))(t.plusSeconds(n))
189+
testDateTime(t.plus(n, MINUTES))(t.plusSeconds(n * 60))
190+
testDateTime(t.plus(n, HOURS))(t.plusSeconds(n * 60 * 60))
191+
testDateTime(t.plus(n, HALF_DAYS))(t.plusSeconds(n * 60 * 60 * 12))
192+
testDateTime(t.plus(n, DAYS))(t.plusSeconds(n * 60 * 60 * 24))
193+
}
194+
}
195+
}

0 commit comments

Comments
 (0)