Java Agent Timemachine
Requirements

TimeMachineAgentDelegate requires:

  1. com.hapiware.agent.Agent. For more information see General Java Agent.
  2. ASM 3.0 or newer. For more information see http://asm.ow2.org/.

TimeMachineAgentDelegate can be used to shift system time without touching the system clock. The trick is to catch all the system time calls and manipulate their byte code directly to achieve the desired result. Time shift is done only for some specific classes which can be defined in the configuration file.

The shift of system time can be relative or absolute. Relative system time shift means that some offset is added to or subtracted from the original system time value. Absolute system time shift means that original system time is always replaced by some absolute value.

TimeMachineAgentDelegate is specified in the agent configuration XML file using /agent/delegate element. For example:

<?xml version="1.0" encoding="UTF-8" ?>
<agent>
    <delegate>com.hapiware.asm.timemachine.TimeMachineAgentDelegate</delegate>
    ...
</agent>

Requirements

TimeMachineAgentDelegate requires com.hapiware.agent.Agent. For more information see com.hapiware.agent.Agent. Also an ASM 3.0 or later is needed (see <a href="http://asm.ow2.org/" target="_blank">http://asm.ow2.org/</a>).

Time shift configuration

Time shift is configured using /agent/configuration element with a single valid String object which presents time shift.

The /agent/configuration element has the following format:<br>

<time>[+|-]y-M-d@H:m:s</time>

where:

  • + or - Optional. Indicates if the configured time is relative or absolute. Relative time has a plus (+) or minus (-) sign preceding the time signature. If the sign is plus (+) then the time value is added to the returned system time. If the sign is minus (-) then time subtracted from system time. Absolute time has no preceding symbol in the front of the time signature.
  • y is a year for absolute time or number of years for relative time.
  • M is a month for absolute time or number of months for relative time. Notice! The month for absolute time is given from 0 to 11 (from January to December respectively) and follows the general Java convention of managing months. Also, month can be anything between 0 and 99. Values bigger than eleven (11) increase years accordingly.
  • d is a days for absolute time or number of days for relative time. Notice that d can be anything between 0 and 999999. This can be useful when exact relative time shift is needed. For absolute time (dates) only correct days should be used to avoid strange results.
  • H is hours for absolute and relative time.
  • m is minutes for absolute and relative time.
  • s is seconds for absolute relative time.

Exact regular expression match pattern for <time> element is:

[+-]?\d{1,4}-\d{1,2}-\d{1,6}@\d{1,2}:\d{1,2}:\d{1,2}

Example configurations

This example matches all the classes for the system time shift:

<?xml version="1.0" encoding="UTF-8" ?>
<agent>
    <delegate>com.hapiware.asm.timemachine.TimeMachineAgentDelegate</delegate>
    <classpath>
        <entry>/users/me/agent/target/timemachine-delegate-2.0.0.jar</entry>
        <entry>/usr/local/asm-3.1/lib/asm-3.1.jar</entry>
    </classpath>
    <!--
        Moves time two years and 5 months backward.
        The time shift is done for every class.
    -->
    <configuration>-2-5-0@0:0:0</configuration>
</agent>

And here is another example:

<?xml version="1.0" encoding="UTF-8" ?>
<agent>
    <delegate>com.hapiware.asm.timemachine.TimeMachineAgentDelegate</delegate>
    <classpath>
        <entry>/users/me/agent/target/timemachine-delegate-2.0.0.jar</entry>
        <entry>/usr/local/asm-3.1/lib/asm-3.1.jar</entry>
    </classpath>

    <!--
        Moves time ten days and eight hours forward.
        The time shift is done for every loaded class
        under com.hapiware.* package.
    -->
    <filter>
        <include>^com/hapiware/.+</include>
    </filter>
    <configuration>+0-0-10@8:0:0</configuration>
</agent>

And yet another example:

<?xml version="1.0" encoding="UTF-8" ?>
<agent>
    <delegate>com.hapiware.asm.timemachine.TimeMachineAgentDelegate</delegate>
    <classpath>
        <entry>/users/me/agent/target/timemachine-delegate-2.0.0.jar</entry>
        <entry>/usr/local/asm-3.1/lib/asm-3.1.jar</entry>
    </classpath>

    <filter>
        <include>^com/hapiware/.*f[oi]x/.+</include>
        <include>^com/mysoft/.+</include>
        <exclude>^com/hapiware/.+/CreateCalculationForm</exclude>
    </filter>
    <!--
        Set time to 13th of April 2010 7:15 AM. Remember that January is zero (0).
    -->
    <configuration>2010-3-13@7:15:0</configuration>
</agent>

Notice! Calculating the relative time value

For calculating the relative time value there are a few assumptions used:

  1. A year has 365 days.
  2. A month has 30 days.

This leads to a little bit inaccurate results, of course, but in practice this doesn't matter. If the exact shift in time is absolutely needed then days should be calculated manually and put the manually calculated result to <time> element without using years and months at all.

Known issues

If the class to be transformed (i.e. the class name matches the <include> element) has a new Date() call without setting the result anywhere then the java.lang.VerifyError is thrown. For example, this works just great:

public static void main(String[] args)
{
    Date now = new Date();
    System.out.println(now);
}

but this throws an exception:

public static void main(String[] args)
{
    new Date();  // This line here is the problem.
    Date now = new Date();
    System.out.println(now);
}

The problem is the different byte code generated in each of the cases.

    new Date();

generates this

    NEW java/util/Date
    INVOKESPECIAL java/util/Date.<init>()V

and

    Date d = new Date();

generates this

    NEW java/util/Date
    DUP
    INVOKESPECIAL java/util/Date.<init>()V
    ASTORE 1

Now, because the DUP command is missing from the first byte code Timemachine cannot interpret it correctly. Fortunately this should be very uncommon case because there is not too many practical problems to be solved by creating a Date object and then not using it.

Download

Download from Java Agent Tools page.

License

MIT License

Copyright (c) 2010 Hapi, http://www.hapiware.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License