-
Notifications
You must be signed in to change notification settings - Fork 38
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
Conversation
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. |
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 |
Of Course! |
@sjrd Would it be possible to get a review please 😄 ? |
Ah sorry, I forgot about this. I'll try to fit it sometime this week. |
Sorry, this got closed accidentally by a bad reference in another project. |
There was a problem hiding this 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 |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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 case
s).
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 | ||
/* |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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") | ||
) |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double blank line.
There was a problem hiding this comment.
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")) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spurious blank line.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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")) | ||
} |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
Hey @sjrd Thanks for the review! Let me know if there is anything else I missed! |
There was a problem hiding this 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover printlns :)
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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 | ||
/* |
There was a problem hiding this comment.
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")) |
There was a problem hiding this comment.
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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The question still stands ;)
Ok, thanks for the heads up! |
There was a problem hiding this 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.
parse
method forjava.time.Instant
parse
method forjava.time.LocalDate
toString
method injava.time.Instant
Fixes: #35