@@ -2,8 +2,13 @@ package java.time
2
2
3
3
import scala .scalajs .js
4
4
5
+ import java .time .Preconditions .requireDateTimeParse
6
+ import java .time .chrono .IsoChronology
7
+ import java .time .format .DateTimeParseException
5
8
import java .time .temporal ._
6
9
10
+ import scala .util .control .NonFatal
11
+
7
12
/** Created by alonsodomin on 26/12/2015. */
8
13
final class Instant private (private val seconds : Long , private val nanos : Int )
9
14
extends TemporalAccessor with Temporal with TemporalAdjuster
@@ -239,16 +244,14 @@ final class Instant private (private val seconds: Long, private val nanos: Int)
239
244
override def hashCode (): Int = (seconds + 51 * nanos).hashCode
240
245
241
246
override def toString : String = {
242
- def tenThousandPartsBasedOnZero : (Long , Long ) = {
247
+ def tenThousandPartsAndRemainder : (Long , Long ) = {
243
248
if (seconds < - secondsFromZeroToEpoch) {
244
- val zeroSecs = seconds + secondsFromZeroToEpoch
245
- val quot = zeroSecs / secondsInTenThousandYears
246
- val rem = zeroSecs % secondsInTenThousandYears
249
+ val quot = seconds / secondsInTenThousandYears
250
+ val rem = seconds % secondsInTenThousandYears
247
251
(quot, rem)
248
252
} else {
249
- val zeroSecs = seconds - secondsInTenThousandYears + secondsFromZeroToEpoch
250
- val quot = Math .floorDiv(zeroSecs, secondsInTenThousandYears) + 1
251
- val rem = Math .floorMod(zeroSecs, secondsInTenThousandYears)
253
+ val quot = Math .floorDiv(seconds, secondsInTenThousandYears)
254
+ val rem = Math .floorMod(seconds, secondsInTenThousandYears)
252
255
(quot, rem)
253
256
}
254
257
}
@@ -259,23 +262,29 @@ final class Instant private (private val seconds: Long, private val nanos: Int)
259
262
(LocalDate .ofEpochDay(epochDay), LocalTime .ofSecondOfDay(secondsOfDay).withNano(nanos))
260
263
}
261
264
262
- val (hi, lo) = tenThousandPartsBasedOnZero
263
- val epochSecond = lo - secondsFromZeroToEpoch
265
+ val (hi, lo) = tenThousandPartsAndRemainder
266
+ val epochSecond = lo
264
267
val (date, time) = dateTime(epochSecond)
265
268
266
- val hiPart = {
267
- if (hi > 0 ) s " + $hi"
268
- else if (hi < 0 ) hi.toString
269
- else " "
269
+ val years = hi * 10000 + date.getYear
270
+
271
+ val yearSegment = {
272
+ if (years > 9999 ) s " + $years"
273
+ else if (years < 0 && years > - 1000 ) " -%04d" .format(Math .abs(years))
274
+ else years.toString
270
275
}
271
276
277
+ val monthSegement = " %02d" .format(date.getMonthValue)
278
+ val daySegment = " %02d" .format(date.getDayOfMonth)
279
+
272
280
val timePart = {
273
281
val timeStr = time.toString
274
282
if (time.getSecond == 0 && time.getNano == 0 ) timeStr + " :00"
275
283
else timeStr
276
284
}
277
285
278
- s " ${hiPart}${date}T ${timePart}Z "
286
+ val dateSegment = s " $yearSegment- $monthSegement- $daySegment"
287
+ s " ${dateSegment}T ${timePart}Z "
279
288
}
280
289
281
290
// Not implemented
@@ -287,12 +296,17 @@ object Instant {
287
296
import Constants ._
288
297
import ChronoField ._
289
298
299
+ private final val iso = IsoChronology .INSTANCE
300
+
290
301
final val EPOCH = new Instant (0 , 0 )
291
302
292
303
private val MinSecond = - 31557014167219200L
293
304
private val MaxSecond = 31556889864403199L
294
305
private val MaxNanosInSecond = 999999999
295
306
307
+ private val MaxYear = 1000000000
308
+ private val MinYear = - 1000000000
309
+
296
310
/*
297
311
* 146097 days in 400 years
298
312
* 86400 seconds in a day
@@ -335,7 +349,90 @@ object Instant {
335
349
ofEpochSecond(temporal.getLong(INSTANT_SECONDS ), temporal.getLong(NANO_OF_SECOND ))
336
350
}
337
351
338
- // Not implemented
339
- // def parse(text: CharSequence): Instant
352
+ private def parseSegment (segment : String , classifier : String ): Int = {
353
+ try {
354
+ segment.toInt
355
+ } catch {
356
+ case _ : NumberFormatException =>
357
+ throw new DateTimeParseException (s " $segment is not a valid $classifier" ,
358
+ segment, 0 )
359
+ }
360
+ }
361
+
362
+ private def toEpochDay (year : Int , month : Int , day : Int ): Long = {
363
+ val leapYear = iso.isLeapYear(year)
364
+
365
+ val extremeLeapYear = 999999996
366
+ val epochDaysToAccountForExtreme = (3 * DAYS_IN_YEAR ) + DAYS_IN_LEAP_YEAR
367
+
368
+ requireDateTimeParse(year <= MaxYear || year >= MinYear ,
369
+ s " $year out of bounds, year > 1000000000 || year < -1000000000 " ,
370
+ year.toString, 0 )
371
+
372
+ val monthDay = MonthDay .of(month, day)
373
+ if (monthDay.getMonth == Month .FEBRUARY && leapYear) {
374
+ requireDateTimeParse(monthDay.getDayOfMonth <= 29 ,
375
+ " Day range out of bounds <= 29 for leap years" , day.toString, 0 )
376
+ }
377
+
378
+ if (year == MaxYear )
379
+ LocalDate .of(extremeLeapYear, month, day).toEpochDay + epochDaysToAccountForExtreme
380
+ else if (year == MinYear )
381
+ LocalDate .of(- extremeLeapYear, month, day).toEpochDay - epochDaysToAccountForExtreme
382
+ else
383
+ LocalDate .of(year, month, day).toEpochDay
384
+ }
340
385
386
+ def parse (text : CharSequence ): Instant = {
387
+ try {
388
+ val pattern = """ (^[-+]?)(\d*)-(\d*)-(\d*)T(\d*):(\d*):(\d*).?(\d*)Z""" .r
389
+ val pattern(sign, yearSegment, monthSegment, daySegment,
390
+ hourSegment, minutesSegment, secondsSegment, nanosecondsSegment) = text
391
+
392
+ val year = parseSegment(sign + yearSegment, " year" )
393
+ val month = parseSegment(monthSegment, " month" )
394
+ val day = parseSegment(daySegment, " day" )
395
+ val nanoPower = 9
396
+
397
+ requireDateTimeParse(! ((sign != " +" ) && (year > 9999 )),
398
+ s " year > 9999 must be preceded by [+] " , text, 0 )
399
+
400
+ val days = toEpochDay(year, month, day)
401
+ val dayOffset = days
402
+
403
+ val hourOffset = parseSegment(hourSegment, " hour" )
404
+ val minuteOffset = parseSegment(minutesSegment, " minutes" )
405
+ val secondsOffset = parseSegment(secondsSegment, " seconds" )
406
+
407
+ requireDateTimeParse(hourOffset <= HOURS_IN_DAY ,
408
+ s " hours are > $HOURS_IN_DAY" , text, 0 )
409
+
410
+ requireDateTimeParse(minuteOffset <= MINUTES_IN_HOUR ,
411
+ s " minutes are > $MINUTES_IN_HOUR" , text, 0 )
412
+
413
+ requireDateTimeParse(secondsOffset <= SECONDS_IN_MINUTE ,
414
+ s " seconds are > $SECONDS_IN_MINUTE" , text, 0 )
415
+
416
+ val nanos = if (nanosecondsSegment != " " ) {
417
+ val scale = Math .pow(10 , nanoPower - nanosecondsSegment.length).toInt
418
+ parseSegment(nanosecondsSegment, " nanoseconds" ) * scale
419
+ } else {
420
+ 0
421
+ }
422
+
423
+ val epochSecondsOffset = {
424
+ dayOffset * SECONDS_IN_DAY +
425
+ hourOffset * SECONDS_IN_HOUR +
426
+ minuteOffset * SECONDS_IN_MINUTE +
427
+ secondsOffset
428
+ }
429
+
430
+ new Instant (epochSecondsOffset, nanos)
431
+ } catch {
432
+ case err : DateTimeParseException =>
433
+ throw err
434
+ case NonFatal (err) =>
435
+ throw new DateTimeParseException (s " Invalid date $text" , text, 0 )
436
+ }
437
+ }
341
438
}
0 commit comments