Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Instant.parse and LocalDate.parse. #36

Merged
merged 1 commit into from
Mar 28, 2018
Merged

Implement Instant.parse and LocalDate.parse. #36

merged 1 commit into from
Mar 28, 2018

Conversation

chrisshafer
Copy link
Contributor

  • Implemented parse method for java.time.Instant
  • Implemented parse method for java.time.LocalDate
  • Fixed bug with toString method in java.time.Instant

Fixes: #35

@chrisshafer
Copy link
Contributor Author

Hi! I wasn't quite sure what path to take when implementing the parsing functionality. Please let me know if this is not the right approach.

@sjrd
Copy link
Member

sjrd commented Nov 16, 2017

Thank you for your contribution.

Before I take a look at your PR, could you please confirm that you did not look at the source code of java.time of OpenJDK nor OracleJDK? See https://github.com/scala-js/scala-js-java-time/blob/master/CONTRIBUTING.md

@chrisshafer
Copy link
Contributor Author

Of Course!
I did not look at the source code of java.time of either OpenJDK or OracleJDK.

@chrisshafer
Copy link
Contributor Author

@sjrd Would it be possible to get a review please 😄 ?

@sjrd
Copy link
Member

sjrd commented Dec 17, 2017

Ah sorry, I forgot about this. I'll try to fit it sometime this week.

@chrisshafer chrisshafer reopened this Jan 15, 2018
@chrisshafer
Copy link
Contributor Author

chrisshafer commented Jan 15, 2018

Sorry, this got closed accidentally by a bad reference in another project.

Copy link
Member

@sjrd sjrd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I have finally found some time for this.

I have a few comments, mostly coding style things. I have only reported each kind of coding style issue once, so make sure to look for other places in your PR where the same comments apply.

case years if years > 9999 => s"+$years"
case years if years < 0 && years > -1000 =>
"-%04d".format(Math.abs(years))
case years => years.toString
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We typically do not use match constructs for what would otherwise be a chain an if/else chain. The style would be more like:

val years = hi * 10000 + date.getYear
val yearSegment = {
  if (years > 9999) s"+$years"
  else if (years < 0 && years > -1000) "-%04d".format(-years)
  else years.toString
}

(also, Math.abs(years) is advantageously replaced by -years since we already it is < 0 at that point)

}

val monthSegement = "%02d".format(date.getMonthValue)
val daySegment = "%02d".format(date.getDayOfMonth)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In our coding style, we do not use vertical alignment (except for arrows of single-line cases).

final val EPOCH = new Instant(0, 0)

private val MinSecond = -31557014167219200L
private val MaxSecond = 31556889864403199L
private val MaxNanosInSecond = 999999999

private val MaxYear = 1000000000
private val MinYear = -1000000000
/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing blank line above this line.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still relevant.

private def handleSegmentParse(segment: String)(classifier: String) = {
Try(segment.toInt).getOrElse(
throw new DateTimeParseException(s"$segment is not a valid $classifier")
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coding style: either

    Try(segment.toInt).getOrElse {
      throw new DateTimeParseException(s"$segment is not a valid $classifier")
    }

or

    Try(segment.toInt).getOrElse(
        throw new DateTimeParseException(s"$segment is not a valid $classifier"))

)

val monthDay = MonthDay.of(month, day)
if(monthDay.getMonth == Month.FEBRUARY && leapYear) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coding style: space between if and (


// TODO
// def getErrorIndex(): Int
//def getParsedString(): String = parsedData.toString
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no reason not to implement those trivial methods.

assertEquals(Instant.parse("1999-06-03T06:56:23.942Z"), somePositiveInstant)
assertEquals(Instant.parse("-0687-08-07T23:38:33.088936253Z"), someNegativeInstant)


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double blank line.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should also test one non-String CharSequence, e.g., a java.nio.CharBuffer.wrap(...). Same in LocalDateTest.

expectThrows(classOf[DateTimeParseException], parse("0000-01-99"))
expectThrows(classOf[DateTimeParseException], parse("0000-01-900"))
expectThrows(classOf[DateTimeParseException], parse("10000-01-30"))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spurious blank line.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this is under-tested. For example, I would definitely want to see exceptional cases for non-digits, for Feb 29 on a non-leap year, and stuff like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed! In fact it looks like the previous version wouldn't catch the case of a Fed 29 on a non-leap year.

expectThrows(classOf[DateTimeParseException], Instant.parse("+1000000001-12-31T23:59:59.999999999Z"))
expectThrows(classOf[DateTimeParseException], Instant.parse("-0687-99-07T23:38:33.088936253Z"))
expectThrows(classOf[DateTimeParseException], Instant.parse("-ABCD-08-07T23:38:33.088936253Z"))
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exceptional cases are under-tested here too. For example, what about ...T24:... or T13:65:...?


def parse(text: CharSequence): LocalDate = {

val potentialLocalDate = Try {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comments as those for Instant.parse() apply here.

@chrisshafer
Copy link
Contributor Author

Hey @sjrd Thanks for the review! Let me know if there is anything else I missed!

Copy link
Member

@sjrd sjrd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I have a couple more comments.

As I'm leaving on vacation for 3 weeks starting tomorrow, I probably won't have time to look at this PR again before the week of March 5-9.


println(hi)
println(date.getYear)
println(years)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover printlns :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my... Sorry I totally missed these.

}


println(yearSegment)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another one here.

final val EPOCH = new Instant(0, 0)

private val MinSecond = -31557014167219200L
private val MaxSecond = 31556889864403199L
private val MaxNanosInSecond = 999999999

private val MaxYear = 1000000000
private val MinYear = -1000000000
/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still relevant.

// expectThrows(classOf[DateTimeParseException], parse("0000-01-900"))
// expectThrows(classOf[DateTimeParseException], parse("aaaa-01-30"))
// expectThrows(classOf[DateTimeParseException], parse("2012-13-30"))
// expectThrows(classOf[DateTimeParseException], parse("2012-01-34"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are those commented out?

LocalDate.of(extremeLeapYear * -1, month, day).toEpochDay - epochDaysToAccountForExtreme
} else {
LocalDate.of(year, month, day).toEpochDay
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question still stands ;)

@chrisshafer
Copy link
Contributor Author

Ok, thanks for the heads up!

Copy link
Member

@sjrd sjrd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates. I've reformatted the code for you, so that it's good to merge, now.

@sjrd sjrd changed the title LocalDate and Instant parsers Implement Instant.parse and LocalDate.parse. Mar 28, 2018
@sjrd sjrd merged commit 24f76a4 into scala-js:master Mar 28, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants