Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@runtologist
Copy link
Member

/fixes #4550

@runtologist
Copy link
Member Author

runtologist commented Jan 13, 2021

I'll need to fix the test to only run on JDK > 8.

@adamgfraser
Copy link
Contributor

@runtologist Looks like there is a compilation error on Dotty. I think merging upstream changes should fix.

// This test should only run on JRE >= 9, which is when microsecond precision was introduced.
// Versions of JREs < 9 started with s"1.${majorVersion}", then with JEP 223 they switched to semantic versioning.
assert(jreVersion)(isSome(startsWithString("1."))) || assert((b - a) % 1000)(not(equalTo(0L)))
}.provideLayer(Clock.live ++ System.live) @@ TestAspect.flaky
Copy link
Contributor

Choose a reason for hiding this comment

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

You can use TestAspect.ifProp to clean this up slightly. Also if you use Live.live(clock.currentTime(unit) you can avoid having to provide any layers. Why is this test flaky?

Copy link
Member Author

Choose a reason for hiding this comment

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

TestAspect.ifProp is great, thanks. One of these small tools you rarely need, but that make life easier when you do.

This test tests the live clock. I think that is more obvious when providing a Layer once than when wrapping in Live.live everywhere clock is used. Do you prefer wrapping as more idiomatic?

Copy link
Member Author

@runtologist runtologist Jan 14, 2021

Choose a reason for hiding this comment

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

The test is flaky, because we might actually have measured exactly one millisecond. In that case we can simply retry.


def currentTime(unit: TimeUnit): UIO[Long]

// Could be UIO. We keep IO to preserve binary compatibility.
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this really be UIO? I know we changed this at what point because we observed that it really did throw DateTimeException when the system time zone wasn't in the list that was supported by the java-time implementation.

Copy link
Member Author

Choose a reason for hiding this comment

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

The previous implementation used ZoneId.systemDefault in currentDateTime, which may throw a DateTimeException. The new implementation uses Instant.now, which does not throw according to the docs.


// This could be a UIO. We keep IO to preserve binary compatibility.
// The implementation is only here to preserve binary compatibility.
def localDateTime: IO[DateTimeException, java.time.LocalDateTime] = currentDateTime.map(_.toLocalDateTime())
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as above.

Copy link
Member Author

Choose a reason for hiding this comment

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

The previous implementation was based on currentDateTime, which could a DateTimeException. The new implementation directly uses LocalDateTime.now, which does not throw according to the docs.

case TimeUnit.NANOSECONDS =>
val micros = inst.toEpochMilli() * 1000000 + inst.getNano()
unit.convert(micros, TimeUnit.NANOSECONDS)
case TimeUnit.NANOSECONDS | TimeUnit.MICROSECONDS =>
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure I understand this line. If we matched on NANOSECONDS above shouldn't we just be matching on MICROSECONDS here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch. That's a leftover. Initially I only had the second case, but the decided to add the first one in order to keep the loss in range and precision as low as possible.

def instant: UIO[java.time.Instant] = currentTime(TimeUnit.MILLISECONDS).map(java.time.Instant.ofEpochMilli(_))

// The implementation is only here to preserve binary compatibility.
def instant: UIO[java.time.Instant] = currentTime(TimeUnit.MILLISECONDS).map(java.time.Instant.ofEpochMilli(_))
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe keep these abstract and provide helper methods for default implementations like we do in other services? I think providing default implementations potentially results in counterintuitive behavior with like mock implementations.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd also prefer to do that, but it breaks binary compatibility. If we decide that's OK here, I'll remove the default implementation.

Copy link
Contributor

@adamgfraser adamgfraser left a comment

Choose a reason for hiding this comment

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

Looks good. Couple of specific comments but great idea!

@runtologist
Copy link
Member Author

@runtologist Looks like there is a compilation error on Dotty. I think merging upstream changes should fix.

Yes, I was waiting for #4551

@runtologist
Copy link
Member Author

@adamgfraser I think all review comments have been addressed.

Copy link
Contributor

@adamgfraser adamgfraser left a comment

Choose a reason for hiding this comment

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

Looks good! We can update the type signatures and remove the default implementation when we move to 2.0.

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.

ZIO Clock should provide microsecond precision

2 participants