Luchian Grigore
Luchian Grigore

Reputation: 258618

Current milliseconds, from long to int

I currently have the following code:

public static int currentTimeMillis()
{
    long millisLong = System.currentTimeMillis();
    while ( millisLong > Integer.MAX_VALUE )
    {
        millisLong -= Integer.MAX_VALUE;
    }
    return (int)millisLong;
}

which returns the current time in an int format (not exactly, but it can be used for time differences). For very good reasons, I can't use long.

Yes, I am just interested in the difference between two calls, and this approach works well. But it just looks wrong. I know that. And inefficient. I know. So my questions is, how can I improve it?

I need a function that returns an int such that:

int x1 = currentTimeMillis(); //my function
long y1 = System.currentTimeMillis();

.....

int x2 = currentTimeMillis();
long y2 = System.currentTimeMillis();

// here, x2 - x1 must be equal to y2 - y1

EDIT:

FYI, I want to do this for benchmarking. I'm running tests on multiple threads in parallel, the stop event is triggered by an external component. I'm also serializing the data in a way that only supports int, and the object I'm serializing can not have long members.

Upvotes: 11

Views: 26688

Answers (5)

Peter Lawrey
Peter Lawrey

Reputation: 533530

You can just do

public static int currentTimeMillis() {
    return (int) System.currentTimeMillis();
}

If its negative it won't matter provided you take a difference. e.g.

int start = currentTimeMillis();

// will be positive for differences less than 24 days.
int time = currentTimeMillis() - start; 

Using this approach avoid the issue of overflows as they will cancel out e.g.

int start = Integer.MAX_VALUE;
// 1 ms later
int time = Integer.MIN_VALUE /*due to overflow*/ - start; 
// time equals 1 due to underflow.

Upvotes: 2

BalusC
BalusC

Reputation: 1108802

Your function does essentially the same as:

public static int currentTimeMillis() {
    return (int) (System.currentTimeMillis() % Integer.MAX_VALUE);
}

The above is probably what you're looking for. The modulus operator % returns the remainder of the division. I would only wrap it in another class which hides this away. It's namely confusing to have "current time in millis" as an int with the wrong value. Something like:

Stopwatch stopwatch = Stopwatch.start();

// ...

int elapsed = stopwatch.elapsed();

with

public final class Stopwatch {

    private long start;

    private Stopwatch() {
        start = System.currentTimeMillis();
    }

    public static Stopwatch start() {
        return new Stopwatch();
    }

    public int elapsed() {
        return (int) (System.currentTimeMillis() - start);
    }

}

This is also much better in order to prevent problems when the start time is less than Integer.MAX_VALUE and the end time is larger than Integer.MAX_VALUE which thus overflows back to Integer.MIN_VALUE and continues from there.

Upvotes: 31

Asaph
Asaph

Reputation: 162801

You won't be able to satisfy your condition 100% of the time because time can elapse between lines in your program during execution which will throw things off slightly. But the numbers won't be off by much. Without knowing more about your problem, I have to assume that you're not interested in the actual time. Perhaps you're just interested in elapsed time? Are you running some benchmarks? If elapsed time is all you need, the modulus solution suggested by @BalusC will do fine.

Upvotes: 2

StriplingWarrior
StriplingWarrior

Reputation: 156544

Be aware that if the currentTimeMillis value rolls over the Integer.MAX_VALUE between taking x1 and x2, you will end up with x2 - x1 being a negative value. There are two ways to address this.

  1. Use BalusC's approach, and then when you subtract x2 - x1 check to see if it's negative. If it is, add Integer.MAX_VALUE to it again. (This assumes that no two time values will be checked that are actually more than Integer.MAX_VALUE distance apart.)
  2. Store the current time as a a private static value when the class is first initialized. From then on, make your function return the difference between the current time and that first startup time. This assumes that these time values will not need to persist when the system is restarted, and that the system will not be alive long enough to pass the Integer.MAX_VALUE mark.

As a side note, I'm sure we're all wondering what your very good reason is for not using long values?

Upvotes: 3

bezmax
bezmax

Reputation: 26132

Instead of finding a modulus, a much faster solution would be a simple bitwise mask operation:

public static int currentTimeMillis() {
    return (int) (System.currentTimeMillis() & 0x00000000FFFFFFFFL);
}

Upvotes: 3

Related Questions