I strongly recommend that instead of messing with the system clock, you bite the bullet and refactor that legacy code to use a replaceable clock. Ideally that should be done with dependency injection, but even if you used a replaceable singleton you would gain testability.
This could almost be automated with search and replace for the singleton version:
- Replace
Calendar.getInstance()withClock.getInstance().getCalendarInstance(). - Replace
new Date()withClock.getInstance().newDate() - Replace
System.currentTimeMillis()withClock.getInstance().currentTimeMillis()
(etc as required)
Once you’ve taken that first step, you can replace the singleton with DI a bit at a time.