The usual way to change date/time for a particular process is to hook corresponding system functions with an LD_PRELOAD trick. There are two basic functions in Linux to get absolute time: gettimeofday
and clock_gettime
. Here is an example library that intercepts these two functions.
Unfortunately, the above trick works on Linux only. But here is another portable solution specifically for Java. It relies on JVM Tool Interface.
In OpenJDK all Java APIs for getting current date/time end up in calling either System.currentTimeMillis()
or VM.getNanoTimeAdjustment()
. The latter is the internal JDK method to provide high resolution Clock
. So, in order to change date/time for a Java application, it's enough to tweak the implementation of those two methods.
The idea is the following.
- JVM TI agent intercepts native method bindings by subscribing to NativeMethodBind event.
- When
NativeMethodBind
is called for currentTimeMillis
or getNanoTimeAdjustment
, the agent remembers the address of the native function and replaces it with its own one.
- Every time the hooked methods are called, the agent first delegates to the original function and then adds the specified offset to the returned value.
The complete code for such an agent is here.
How to compile:
g++ -O2 -fPIC -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -olibfaketime.so faketime.cpp
How to run:
java -agentpath:/path/to/libfaketime.so=<newtime> MainClass
where newtime
is either an absolute timestamp in milliseconds from Epoch, or (when begins with +
or -
) a relative offset in milliseconds from current time.
The only problem is that System.currentTimeMillis
is a JVM intrinsic. This means, a JIT compiled method may skip calling JNI implementation (and thus skip our hook). To avoid this, we can simply disable the corresponding intrinsic with a few more JVM options:
-XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_currentTimeMillis -XX:CompileCommand=dontinline,java.lang.System::currentTimeMillis