Reading the system clock directly within unit tests introduces non-determinism. Tests that rely on the current wall-clock time are "flaky": they may pass today but fail tomorrow, or behave differently depending on the time zone and local time of the CI/CD runner.

To ensure that they are repeatable and predictable, .now() methods like LocalDate.now(), LocalDateTime.now(), or Instant.now() should only be called with a fixed clock in unit tests. Legacy APIs such as System.currentTimeMillis(), new Date(), and Calendar.getInstance() have the same problem and should be replaced with clock injection. Other methods that explicitly call the system clock, such as Clock.system(ZoneId zone), Clock.systemDefaultZone() and Clock.systemUTC() should also be avoided in tests.

Why is this an issue?

When a test uses the system clock, it relies on an external, uncontrollable state. This makes it impossible to:

How to fix it

The best practice is to inject a java.time.Clock instance into the class or method being tested. In production code, Clock.systemDefaultZone() can be used, whereas in test code, Clock.fixed(Instant fixedInstant, ZoneId zone) should be called, or a mock Clock be injected. This ensures that tests remain deterministic regardless of when or where they are run.

Code examples

Noncompliant code example

The test below is flaky because assumes that the second call to Instant.now() returns an instant that is later than the first, which might not be true depending on the environment in which the test is run.

@Test
void testTimeDifference() {
    Instant instant1 = Instant.now();
    Instant instant2 = Instant.now();
    assertTrue(instant1.isBefore(instant2)); // Noncompliant
}

In the second example below, the service uses a static call to Instant.now(). This makes it impossible to mock the time without using advanced (and often discouraged) static mocking techniques.

public class SecurityService {
    public boolean isTokenValid(Instant issuedAt) {
        return issuedAt.isAfter(Instant.now().minus(1, ChronoUnit.HOURS));
    }
}

public class SecurityServiceTest {
    @Test
    void testTokenValidation() {
        SecurityService service = new SecurityService();
        assertTrue(service.isTokenValid(Instant.now().minusSeconds(60))); // Noncompliant: the test is non-deterministic and depends on the execution time.
    }
}

Compliant solution

Here, the first instant is guaranteed to be before the second, because it is fixed, and the second is explicitly set to a later moment.

@Test
void testTimeDifference() {
    Instant instant1 = Instant.parse("2026-05-07T10:00:00Z"); // Compliant
    Instant instant2 = instant1.plus(1, ChronoUnit.MINUTES);
    assertTrue(instant1.isBefore(instant2));
}

In the solution below, the Clock is a field in the class (often injected by a framework like Spring). In the test, we use @Mock to control exactly what time the service "thinks" it is.

public class SecurityService {
    private final Clock clock;

    public SecurityService(Clock clock) {
        this.clock = clock;
    }

    public boolean isTokenValid(Instant issuedAt) {
        return issuedAt.isAfter(Instant.now(clock).minus(1, ChronoUnit.HOURS));
    }
}

@ExtendWith(MockitoExtension.class)
public class SecurityServiceTest {
    @Mock
    private Clock clock;

    @Test
    void testTokenValidationWithMock() {
        Instant fixedPoint = Instant.parse("2026-05-07T10:00:00Z");

        // Stub the mock clock to behave like a fixed clock.
        when(clock.instant()).thenReturn(fixedPoint);
        when(clock.getZone()).thenReturn(ZoneOffset.UTC);

        SecurityService service = new SecurityService(clock);

        Instant issuedAt = Instant.parse("2026-05-07T09:30:00Z");
        assertTrue(service.isTokenValid(issuedAt)); // Compliant: this is now deterministic, as 09:30 is within 1 hour of 10:00.
    }
}

Resources

Documentation

Articles & blog posts