Time Travel in Java

Do you have a clock?

Altimetrik Poland Tech Blog
5 min readSep 29, 2022

Time travel! I bet that many of us would like to experience it, but guess what? — you can do it in Java! All you need is a clock…

In this article I will show you how to:

  • manage the time that your application assumes to be now
  • test your code which uses static methods from java.time.*package

What is “now” ?

Date and time may seem like just easy concepts. When you start working with different time zones, you will see that it can be really tricky. I’ve listed just a few technical dilemmas below:

  • you live in time zone A, and your production infrastructure is running in time zone B. LocalDateTime.now() returns different results on your local machine, and on production;
  • your database server runs in a different time zone than yours — your SQL was prepared and tested locally, but may apply a different offset on the actual server;
  • your service and your database run in a different time zones — which side should apply the offset when saving the date and time? Your service or your database? What if neither (or both) apply the offset shift?
  • you store everything in UTC — great! But what if someone wants to know what the client’s time was when some action was performed?

As you can see, it’s not so trivial neither in a complex systems, nor… locally! Let’s have a look at a common use case.

Now + something

Business requirements are often time-based — e.g. if you buy something, you can pay for it 30 days later. Your system must somehow calculate this due date — you would typically see the following solution:

The problem is that LocalDateTime.now() method is static and not so easy to mock. So how to test it? This is already getting tricky, but it’s still possible.

If you don’t want to mock up static methods, and precision to seconds is “good enough” for you, you can come up with the following idea:

These are the logs produced by the test — as you can see, there is a difference in milliseconds. In this case, the seconds match, but if you run the test again, they may not.

actualDueDate 2022-10-03T23:46:50.307535
expectedDueDate 2022-10-03T23:46:50.306746

Problems

  • testing and assertions against the results of static methods— as you can see, this is more complex, because you are not 100% sure what was the result obtained by static methods
  • problems with time-dependent requirements — sometimes business requirements are really complex and strongly time-dependent, e.g. prices may be dynamic, something is cheaper in the evening on weekdays but only in the winter, etc. In such cases you want to compare date&time with as much precision as possible.

Ideas

Here are some solutions and “solutions” to both of these problems. First, let’s consider the ones that may work, but are not so relevant in my opinion:

Working, but not great

  • pass “now” as an argument to a method — ouch, that hurts. Yes, it will make testing easier, but… code complexity increases because your method takes one additional argument. Why do method clients have to provide you with this date&time? What if some clients use this as an advantage and, for example, pass the year 2100 as “now” (as in the previous example with the date)?
  • mocking up static methods — this can be done with some test libraries or AOP, but… in my opinion, if you need to mock a static method to test your business requirements, you’re doing something wrong. Staticity is great for utility methods, but any use of a static method is a hidden dependency.

Better, but not the best

  • custom TimeService wrapping static method. You can inject this service into other services and mock it in tests;

Pros:

  • visible dependence — you are aware of the time dependence
  • easy to test and mock — in your tests, and you can just mock TimeService behaviour

Cons:

  • additional class used (probably) throughout the application
  • this class can grow quickly — maybe it’s not a big deal, but the number of wrapped methods can grow quickly if you use a lot of static methods from java.time package. Imagine that this class has 20 public methods - to me it sounds like a good old utility class, but tied with a nice ribbon. It’s also not too Solid.
  • it’s a new dependency for other classes

The (in my opinion) best

  • using java.time.Clock class as a time provider - makes testing easier and allows time travel

As you can read in the javadoc:

The use of the clock is optional. All key date-time classes also have a now() factory method that uses the system clock in the default time zone. The primary purpose of this abstraction is to allow alternative clocks to be connected if needed. Applications use an object to get the current time instead of a static method. This can simplify testing.

and

Best practice for applications is to pass clock to any method that requires the current time and time zone.

Sounds like a great solution!

Pros:

  • Clock class comes from JDK - no 3rd party library is needed
  • allows time travel — you can simulate that the application is running at any point in time

Cons:

  • this is a new dependency for other classes (but is unlikely to be overcome)

Clock bean configuration

The bellow examples show how to configure Clock bean using Spring configuration.

Local date&time

Using this configuration will return local date&time results.

Fixed clock

Using this configuration will return fixed results —calling the now() method will always return the same time.

UTC

Time travel

If you want to travel in time and configure what is now for your service, here’s how you can achieve it:

This configuration registers Clock bean in the context of the application. If you do not set any of the time-travel.**properties, your app will use the system’s default time zone. If you set the time-travel.** properties, for example, as follows:

time-travel.enabled=true
time-travel.instant=2022-09-01T12:00:00.00Z
time-travel.zone=UTC

then now in your application will always be 2022–09–01T12:00:00.

Summary

In this article I described:

  • what problems with date, time and time zones you may have
  • why these great static methods from the java.time package are not the easiest to test
  • how to deal with time in the app and time travel
  • what is the best (in my opinion) way to handle time in Java

Resources and further reading:

Words by Aleksander Kołata, Senior Full Stack Developer at Altimetrik Poland

https://www.linkedin.com/in/aleksander-kolata/

Copywriting by Kinga Kuśnierz, Content Writer at Altimetrik Poland

https://www.linkedin.com/in/kingakusnierz/

--

--

Altimetrik Poland Tech Blog
Altimetrik Poland Tech Blog

Written by Altimetrik Poland Tech Blog

This is a Technical Blog of Altimetrik Poland team. We focus on subjects like: Java, Data, Mobile, Blockchain and Recruitment. Waiting for your feedback!

No responses yet