Skip to content

Commit

Permalink
Provide a working local time impl but returns UTC - no time zone (#52)
Browse files Browse the repository at this point in the history
* Provide a working local time impl but returns UTC - no time zone

* Replace return type of LocalDate.getEra() to IsoEra for Java 11

* Workaround for added functions in Java 9

* Filter out some tests for JDK > 8

* Fix truncatedTo and tests to match JDK > 8

* Ignore 3 tests only on JDK8, Fixed in JDK9+

* Remove print on InstantTest

* Fix special toMillis cases

* Put old JDK8 tests back
  • Loading branch information
ekrich authored Dec 31, 2021
1 parent 7103737 commit 4436731
Show file tree
Hide file tree
Showing 17 changed files with 118 additions and 101 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
java: [ '8' ] #, '11', '17' ]
java: [ '8', '11', '17' ]
name: Test using Java ${{ matrix.java }}
steps:
- uses: actions/checkout@v2
Expand Down
11 changes: 0 additions & 11 deletions .scalafmt.conf

This file was deleted.

22 changes: 10 additions & 12 deletions sjavatime/native/src/main/scala/java/time/PlatformSpecific.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,17 @@ private[time] object PlatformSpecific extends PlatformCommon {
}

def localTime(): LocalTime = {
val epochSeconds = Instant.toEpochSecond(System.currentTimeMillis())
val now = Instant.now()
val epochSeconds = now.getEpochSecond()
val nanos = now.getNano()
// sec/yr, sec/day, sec/hr, sec/min
val currentSeconds =
Math.floor(((((epochSeconds % 31536000) % 86400) % 3600) % 60).toDouble).toLong
LocalTime.ofSecondOfDay(currentSeconds)
// From https://github.com/akka-js/scalanative-java-time
// val currentHours = Math.floor(((seconds % 31536000) % 86400) / 3600).toInt
// val currentMinutes =
// Math.floor((((seconds % 31536000) % 86400) % 3600) / 60).toInt
// val currentSeconds =
// Math.floor((((seconds % 31536000) % 86400) % 3600) % 60).toInt
// LocalTime.of(currentHours, currentMinutes, currentSeconds)

val secPerDay = ((epochSeconds % 31536000) % 86400)
val currentHours = Math.floor((secPerDay / 3600).toDouble).toInt
val secPerHour = secPerDay % 3600
val currentMinutes = Math.floor((secPerHour / 60).toDouble).toInt
val currentSeconds = Math.floor((secPerHour % 60).toDouble).toInt
// this would need a timezone offset - currently UTC
LocalTime.of(currentHours, currentMinutes, currentSeconds, nanos)
}

def minDay(day: Int, lastDayOfMonth: Int): Int = {
Expand Down
16 changes: 11 additions & 5 deletions sjavatime/shared/src/main/scala/java/time/Duration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ final class Duration private (seconds: Long, nanos: Int)
def multipliedBy(multiplicand: Long): Duration = {
val (prodNanosQuot, prodNanosRem) = {
try {
val prodNanos = Math.multiplyExact(normalizedNanos, multiplicand)
val prodNanos = Math.multiplyExact(normalizedNanos.toLong, multiplicand)
(prodNanos / NANOS_IN_SECOND, (prodNanos % NANOS_IN_SECOND).toInt)
} catch {
case _: ArithmeticException =>
Expand Down Expand Up @@ -140,7 +140,7 @@ final class Duration private (seconds: Long, nanos: Int)
val nanos = {
try {
val total = Math.addExact(
Math.multiplyExact(secondsRem, NANOS_IN_SECOND),
Math.multiplyExact(secondsRem, NANOS_IN_SECOND.toLong),
normalizedNanos)
total / divisor
} catch {
Expand Down Expand Up @@ -179,14 +179,20 @@ final class Duration private (seconds: Long, nanos: Int)
def toMinutes(): Long = seconds / SECONDS_IN_MINUTE

def toMillis(): Long = {
val millis1 = Math.multiplyExact(seconds, MILLIS_IN_SECOND)
val millis2 = nanos / NANOS_IN_MILLI
val (secs, nos) =
if (normalizedSeconds == 0) {
(normalizedSeconds, normalizedNanos)
} else {
(seconds, nanos)
}
val millis1 = Math.multiplyExact(secs, MILLIS_IN_SECOND.toLong)
val millis2 = nos / NANOS_IN_MILLI
Math.addExact(millis1, millis2)
}

def toNanos(): Long =
Math.addExact(
Math.multiplyExact(seconds, NANOS_IN_SECOND), nanos)
Math.multiplyExact(seconds, NANOS_IN_SECOND.toLong), nanos)

def compareTo(that: Duration): Int = {
val secCmp = seconds.compareTo(that.getSeconds())
Expand Down
36 changes: 18 additions & 18 deletions sjavatime/shared/src/main/scala/java/time/Instant.scala
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,20 @@ final class Instant private (private val seconds: Long, private val nanos: Int)
throw new UnsupportedTemporalTypeException("Unit must be a multiple of a standard day")

val extraNanos = (seconds % SECONDS_IN_DAY) * NANOS_IN_SECOND + nanos
val extraNanosPerUnit = (extraNanos / unitNanos) * unitNanos
val extraNanosPerUnit = Math.floorDiv(extraNanos, unitNanos) * unitNanos
plusNanos(extraNanosPerUnit - extraNanos)
}
}

def plus(amount: Long, unit: TemporalUnit): Instant = unit match {
case NANOS => plusNanos(amount)
case MICROS => plusNanos(Math.multiplyExact(amount, NANOS_IN_MICRO))
case MICROS => plusNanos(Math.multiplyExact(amount, NANOS_IN_MICRO.toLong))
case MILLIS => plusMillis(amount)
case SECONDS => plusSeconds(amount)
case MINUTES => plusSeconds(Math.multiplyExact(amount, SECONDS_IN_MINUTE))
case HOURS => plusSeconds(Math.multiplyExact(amount, SECONDS_IN_HOUR))
case HALF_DAYS => plusSeconds(Math.multiplyExact(amount, SECONDS_IN_DAY) / 2)
case DAYS => plusSeconds(Math.multiplyExact(amount, SECONDS_IN_DAY))
case MINUTES => plusSeconds(Math.multiplyExact(amount, SECONDS_IN_MINUTE.toLong))
case HOURS => plusSeconds(Math.multiplyExact(amount, SECONDS_IN_HOUR.toLong))
case HALF_DAYS => plusSeconds(Math.multiplyExact(amount, SECONDS_IN_DAY.toLong) / 2)
case DAYS => plusSeconds(Math.multiplyExact(amount, SECONDS_IN_DAY.toLong))

case _: ChronoUnit =>
throw new UnsupportedTemporalTypeException(s"Unit not supported: $unit")
Expand All @@ -132,16 +132,16 @@ final class Instant private (private val seconds: Long, private val nanos: Int)
def plusSeconds(secs: Long): Instant = plus(secs, 0)

def plusMillis(millis: Long): Instant =
plusNanos(Math.multiplyExact(millis, NANOS_IN_MILLI))
plusNanos(Math.multiplyExact(millis, NANOS_IN_MILLI.toLong))

def plusNanos(nans: Long): Instant = plus(0, nans)

private def plus(secs: Long, nans: Long): Instant = {
if (secs == 0 && nans == 0) {
this
} else {
val secondsFromNanos = Math.floorDiv(nans, NANOS_IN_SECOND)
val remainingNanos = Math.floorMod(nans, NANOS_IN_SECOND)
val secondsFromNanos = Math.floorDiv(nans, NANOS_IN_SECOND.toLong)
val remainingNanos = Math.floorMod(nans, NANOS_IN_SECOND.toLong)
val additionalSecs = Math.addExact(secs, secondsFromNanos)
ofEpochSecond(
Math.addExact(seconds, additionalSecs),
Expand Down Expand Up @@ -175,7 +175,7 @@ final class Instant private (private val seconds: Long, private val nanos: Int)

def nanosUntil: Long = {
val secsDiff: Long = Math.subtractExact(endInstant.seconds, seconds)
val nanosBase: Long = Math.multiplyExact(secsDiff, NANOS_IN_SECOND)
val nanosBase: Long = Math.multiplyExact(secsDiff, NANOS_IN_SECOND.toLong)
Math.addExact(nanosBase, endInstant.nanos - nanos)
}

Expand Down Expand Up @@ -256,7 +256,7 @@ final class Instant private (private val seconds: Long, private val nanos: Int)

def dateTime(epochSecond: Long): (LocalDate, LocalTime) = {
val epochDay = toEpochDay(epochSecond)
val secondsOfDay = Math.floorMod(epochSecond, SECONDS_IN_DAY).toInt
val secondsOfDay = Math.floorMod(epochSecond, SECONDS_IN_DAY.toLong).toInt
(LocalDate.ofEpochDay(epochDay), LocalTime.ofSecondOfDay(secondsOfDay).withNano(nanos))
}

Expand All @@ -272,7 +272,7 @@ final class Instant private (private val seconds: Long, private val nanos: Int)
else years.toString
}

val monthSegement = "%02d".format(date.getMonthValue())
val monthSegment = "%02d".format(date.getMonthValue())
val daySegment = "%02d".format(date.getDayOfMonth())

val timePart = {
Expand All @@ -281,7 +281,7 @@ final class Instant private (private val seconds: Long, private val nanos: Int)
else timeStr
}

val dateSegment = s"$yearSegment-$monthSegement-$daySegment"
val dateSegment = s"$yearSegment-$monthSegment-$daySegment"
s"${dateSegment}T${timePart}Z"
}

Expand Down Expand Up @@ -328,22 +328,22 @@ object Instant {

def ofEpochSecond(epochSecond: Long, nanos: Long): Instant = {
val adjustedSeconds = Math.addExact(epochSecond,
Math.floorDiv(nanos, NANOS_IN_SECOND))
val adjustedNanos = Math.floorMod(nanos, NANOS_IN_SECOND).toInt
Math.floorDiv(nanos, NANOS_IN_SECOND.toLong))
val adjustedNanos = Math.floorMod(nanos, NANOS_IN_SECOND.toLong).toInt
new Instant(adjustedSeconds, adjustedNanos)
}

def ofEpochMilli(epochMilli: Long): Instant = {
val seconds = toEpochSecond(epochMilli)
val nanos = Math.floorMod(epochMilli, MILLIS_IN_SECOND)
val nanos = Math.floorMod(epochMilli, MILLIS_IN_SECOND.toLong)
new Instant(seconds, nanos.toInt * NANOS_IN_MILLI)
}

private[time] def toEpochSecond(epochMilli: Long): Long =
Math.floorDiv(epochMilli, MILLIS_IN_SECOND)
Math.floorDiv(epochMilli, MILLIS_IN_SECOND.toLong)

private[time] def toEpochDay(epochSecond: Long): Long =
Math.floorDiv(epochSecond, SECONDS_IN_DAY)
Math.floorDiv(epochSecond, SECONDS_IN_DAY.toLong)

def from(temporal: TemporalAccessor): Instant = temporal match {
case temporal: Instant => temporal
Expand Down
25 changes: 13 additions & 12 deletions sjavatime/shared/src/main/scala/java/time/LocalDate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
}

private lazy val dayOfWeek =
Math.floorMod(epochDay + 3, 7).toInt + 1
Math.floorMod(epochDay + 3, 7L).toInt + 1

private def prolepticMonth = year.toLong * 12 + getMonthValue() - 1

Expand Down Expand Up @@ -82,7 +82,8 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)

def getChronology(): IsoChronology = iso

override def getEra(): Era = if (year > 0) IsoEra.CE else IsoEra.BCE
// Return type was changed from Era (Java 8) to IsoEra (Java 11)
override def getEra(): IsoEra = if (year > 0) IsoEra.CE else IsoEra.BCE

def getYear(): Int = year

Expand Down Expand Up @@ -138,8 +139,8 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)

case PROLEPTIC_MONTH =>
requireDateTime(value >= -11999999988L && value <= 11999999999L, msg)
val year = Math.floorDiv(value, 12).toInt
val month = Math.floorMod(value, 12).toInt + 1
val year = Math.floorDiv(value, 12L).toInt
val month = Math.floorMod(value, 12L).toInt + 1
val day = dayOfMonth min Month.of(month).length(iso.isLeapYear(year))
LocalDate.of(year, month, day)

Expand Down Expand Up @@ -194,15 +195,15 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
case YEARS => plusYears(amount)

case DECADES =>
val years = Math.multiplyExact(amount, 10)
val years = Math.multiplyExact(amount, 10L)
plusYears(years)

case CENTURIES =>
val years = Math.multiplyExact(amount, 100)
val years = Math.multiplyExact(amount, 100L)
plusYears(years)

case MILLENNIA =>
val years = Math.multiplyExact(amount, 1000)
val years = Math.multiplyExact(amount, 1000L)
plusYears(years)

case ERAS =>
Expand All @@ -226,8 +227,8 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
}

def plusMonths(months: Long): LocalDate = {
val month1 = getMonthValue() + Math.floorMod(months, 12).toInt
val year1 = year + Math.floorDiv(months, 12) +
val month1 = getMonthValue() + Math.floorMod(months, 12L).toInt
val year1 = year + Math.floorDiv(months, 12L) +
(if (month1 > 12) 1 else 0)
requireDateTime(year1 >= Year.MIN_VALUE && year1 <= Year.MAX_VALUE,
s"Invalid value for year: $year1")
Expand All @@ -237,7 +238,7 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
}

def plusWeeks(weeks: Long): LocalDate =
plusDays(Math.multiplyExact(weeks, 7))
plusDays(Math.multiplyExact(weeks, 7L))

def plusDays(days: Long): LocalDate = {
val epochDay1 = Math.addExact(epochDay, days)
Expand Down Expand Up @@ -411,8 +412,8 @@ object LocalDate {
}

def ofEpochDay(epochDay: Long): LocalDate = {
val quot = Math.floorDiv(epochDay, daysInFourHundredYears)
val rem = Math.floorMod(epochDay, daysInFourHundredYears).toInt
val quot = Math.floorDiv(epochDay, daysInFourHundredYears.toLong)
val rem = Math.floorMod(epochDay, daysInFourHundredYears.toLong).toInt
val (year1, start) = daysBeforeYears.takeWhile(_._2 <= rem).last
val year2 = year1 + quot * 400
requireDateTime(year2 >= Year.MIN_VALUE && year2 <= Year.MAX_VALUE,
Expand Down
6 changes: 3 additions & 3 deletions sjavatime/shared/src/main/scala/java/time/Year.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ final class Year private (year: Int)

def plus(amount: Long, unit: TemporalUnit): Year = unit match {
case YEARS => plusYears(amount)
case DECADES => plusYears(Math.multiplyExact(amount, 10))
case CENTURIES => plusYears(Math.multiplyExact(amount, 100))
case MILLENNIA => plusYears(Math.multiplyExact(amount, 1000))
case DECADES => plusYears(Math.multiplyExact(amount, 10L))
case CENTURIES => plusYears(Math.multiplyExact(amount, 100L))
case MILLENNIA => plusYears(Math.multiplyExact(amount, 1000L))

case ERAS =>
val era = get(ERA)
Expand Down
10 changes: 5 additions & 5 deletions sjavatime/shared/src/main/scala/java/time/YearMonth.scala
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ final class YearMonth private (year: Int, month: Int)
def plus(amount: Long, unit: TemporalUnit): YearMonth = unit match {
case MONTHS => plusMonths(amount)
case YEARS => plusYears(amount)
case DECADES => plusYears(Math.multiplyExact(amount, 10))
case CENTURIES => plusYears(Math.multiplyExact(amount, 100))
case MILLENNIA => plusYears(Math.multiplyExact(amount, 1000))
case DECADES => plusYears(Math.multiplyExact(amount, 10L))
case CENTURIES => plusYears(Math.multiplyExact(amount, 100L))
case MILLENNIA => plusYears(Math.multiplyExact(amount, 1000L))

case ERAS =>
val era = getLong(ERA)
Expand Down Expand Up @@ -139,8 +139,8 @@ final class YearMonth private (year: Int, month: Int)
} else {
// Allowing the Long to overflow to align with JDK implementation
val newProlepticMonth = prolepticMonth + months
val newYear = Math.floorDiv(newProlepticMonth, 12)
val newMonth = Math.floorMod(newProlepticMonth, 12) + 1
val newYear = Math.floorDiv(newProlepticMonth, 12L)
val newMonth = Math.floorMod(newProlepticMonth, 12L) + 1
new YearMonth(
YEAR.checkValidIntValue(newYear),
MONTH_OF_YEAR.checkValidIntValue(newMonth)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,8 @@ object Platform {
*/
final val executingInJVM = false

final val executingInJVMOnJDK6 = false
final val executingInJVMOnJDK8 = false

final val executingInJVMOnJDK7OrLower = false
final val executingInJVMOnHigherThanJDK8 = false

// Members that are only accessible from testSuite/js
// (i.e. do no link on the JVM).

def areTypedArraysSupported: Boolean =
js.typeOf(js.constructorOf[js.typedarray.ArrayBuffer]) != "undefined"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ object Platform {
*/
final val executingInJVM = true

def executingInJVMOnJDK6: Boolean = jdkVersion == 6
def executingInJVMOnJDK8 = jdkVersion == 8

def executingInJVMOnJDK7OrLower: Boolean = jdkVersion <= 7
def executingInJVMOnHigherThanJDK8 = jdkVersion > 8

private lazy val jdkVersion = {
val v = System.getProperty("java.version")
if (v.startsWith("1.")) Integer.parseInt(v.drop(2).takeWhile(_.isDigit))
else throw new Exception("Unknown java.version format")
else Integer.parseInt(v.takeWhile(_.isDigit))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ object Platform {
*/
final val executingInJVM = false

final val executingInJVMOnJDK6 = false
final val executingInJVMOnJDK8 = false

final val executingInJVMOnJDK7OrLower = false
final val executingInJVMOnHigherThanJDK8 = false

}
Loading

0 comments on commit 4436731

Please sign in to comment.