Hi all I have a piece of code which looks like this:
public class Test {
public static void main(String args[]) {
long a = System.currentTimeMillis(); // line 1
long b = System.currentTimeMillis(); // line 2
assert b - a >= 0;
long y = System.nanoTime(); // line 5
long z = System.nanoTime(); // line 6
}
}
So IERS stated that the next leap second is to occur immediately after 30th June 2012 11:59.9.
I was wondering if I'm right to say that if line 1 is run at 0.9 seconds after 30th June 2012 11:59.9 turns 1st July 2012 00:00.0,
And line 2 is run at 0.1 second after line 1,
The result of b - a could be negative ? (-900 milliseconds)
If that's the case, is it true that if line 5 is run at 0.9 seconds after 30th June 2012 11:59.9 turns 1st July 2012 00:00.0,
And line 6 is run at 0.1 second after line 5,
The result of z - y could be negative ? (-900,000,000 nanoseconds?)
System.nanoTime should be monotonically increasing -- if you have two calls to it, A and B, and A happens-before B, then A <= B. But in practice, you can actually observe nanoTime going "backwards."
nanoTime is determined by an internal counter on the CPU whose starting time is essentially arbitrary (which is why it can't be used to determine wall clock time). This can cause a problem in multi-core environment, since one core's internal timer may have a different starting point than another's. Hotspot tries to compensate for this, but it doesn't always succeed, so you can in fact see nanoTime ticking backwards in some situations.
There was a recent discussion about this on the concurrency-interest mailing list. See in particular this email which links to this bug report, and this email which talks about the workaround (which doesn't seem to work, though I'm not sure why). The bug report has a fair amount of detail.
Am I right to say that if line 1 is run at 0.9 seconds after 30th June 2012 11:59.9 turns 1st July 2012 00:00.0,
If the clock is not adjusted, 0.9 seconds after 30th June 2012 11:59.9 is 1st July 2012 00:00.8
The result of b - a would be negative ?
The currentTimeMillis() is the time in milli-seconds since 1970. It doesn't reset at the start of the day. Or any time in your life time.
The result of z - y would be negative ?
nanoTime() is not the time since the start of the day either. On many JVMs/OSes its the number of nano-seconds since the CPU was last reset.
Not all OSes provide the same resolution. e.g. RHEL/Centos 5.x give only micro-second resolution. This means you can have many calls in a row give the same value (to the micro-second)
long a = System.currentTimeMillis(); // line 1
long b = System.currentTimeMillis(); // line 2
assert b - a >= 0;
This will go backwards whenever the time is corrected by turning it backwards. e.g. via NTP.
long y = System.nanoTime(); // line 5
long z = System.nanoTime(); // line 6
This will go backwards on systems with more than one socket which do no correct for the difference in the Time Stamp Counter in different sockets. e.g. if you are on Windows XP and have two Sockets you can see the difference jump by 4,000,000 forward or backward as it switch the thread between sockets.
No, you are wrong. Because this is not millisecond part of current time, but total milliseconds passed from year 1970.
They could be the same, but later is not less than earlier. However, if a NTP daemon doing its job it could happen, if at some moment the system clock has been adjusted.
The nanoTime is more reliable way, since it doesn't depend on the system clock and should not be changed by clock adjustments.
-System.nanoTime() + System.nanoTime() guaranteed to be >= 0?
Yes. It's a timer, not any absolute time, and according to its docs, it Returns the current value of the most precise available system timer, in nanoseconds. The value returned represents nanoseconds since some fixed but arbitrary time. Time since some fixed time doesn't go backwards (although after 292 years the difference will overflow, but that's hardly a practical issue. Also, as Peter Lawrey pointed out, Windows XP has a bug that breaks nanotime's guarantees).
System.currentTimeMillis() is completely different. It returns absolute time (milliseconds since 1970) which is got from the computer's clock, which could be adjusted anytime.
My reading of the wiki page is same as yours: currentTimeMillis() can go backwards due to leap second.
(Why did they bring this fine astronomical problem into civil time? No civilian cares if solar noon is off by a few seconds; actually nobody uses local time to begin with; people in the same time zone can observer solar noon differ by 1 hour. and in a big country with no time zone, the difference can be hours.)
Related
So I'm pretty new at Java, but I'm making a text adventure game for CompSci, and this is my code for levels.
public static int level(int exp, Long time, int levelnum) {
//Time is the time elapsed since the program started
time = System.nanoTime();
//I divi de by 10,000,000 twice because that sqared is 100 trillion, the conversion factor between nano and second
exp = (int)(Math.round(time/10000000));
exp = Math.round(exp/10000000);
//The exp, or experience, is the percent, under 100, of the way to the next level. 1 is 10%, 2 is 20, etc.
while (exp > 10){
//This loop will check to make sure exp is under 10. If not, it will add one to the level number, and then subtract 10 from the exp and check again.
levelnum++;
exp = exp - 10;
}
int bar;
bar =1;
//Bar is here because originally, I planned on this all being one method, the next one and this, and so I placed it in meaning for it to act as the return value. It has stayed the return value.
System.out.println(levelnum + "\n" + exp + "\n" + time);
//That was for debugging purposes, so I could see the levels data as it processed.
progBar(levelnum, exp);
return bar;
}
public static void progBar(int levelnum, int exp){
char barOpen, barClose;
String bar = "";
String emptyBar;
//I realize now that I could have just "[" + bar + "]", but at the time i didnt think of that
barOpen = '[';
barClose = ']';
if (exp > 1){
//ok so if the experience is greater than 1, then we repeat the = that many times. That way, we don't repeat it when we have one
bar = "=".repeat(exp);
}else if (exp <= 1){
bar = "=";
}
//This makes sure we have the adequate space between the experience and the bar close
emptyBar = " ".repeat(10-exp);
System.out.println("You are currently level " + levelnum + "\n" + barOpen + bar + emptyBar + barClose);
}
When I ran this yesterday, it succeeded in the level barring. However, today System.nanoTime() has begun to give extremely large numbers, even in different machines, none of which accurately represent the time which has elapsed. How could I fix this?
//Time is the time elapsed since the program started
time = System.nanoTime();
No, it is not.
The actual number returned by nanoTime has no specific meaning. It can only be used to measure the duration of time that has passed between two calls to nanoTime. And those calls have to be within the same program run, on the same machine. It is not comparable between different runs, even on the same machine.
tl;dr
The only meaning you should assign to System.nanoTime is to call it twice and compare the two values as an approximate number of elapsed nanoseconds. Do not interpret the two values as being anything other than as minuend and subtrahend (the two parts of a subtraction operation) for elapsed nanos.
Duration.ofNanos( System.nanoTime() - start )
Large or small nanoTime is irrelevant
Read the documentation:
This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary origin time (perhaps in the future, so values may be negative).
The number returned by this method has no meaning other than to be compared to another such returned value to track elapsed time on a scale of nanoseconds.
So whether the number returned is large or small is irrelevant. Comparing the returned numbers between computers or JVMs is meaningless.
In my experience, the numbers may be a count of nanoseconds since the host machine was booted. But you should never count on that. Such a fact is but a mere implementation detail. That detail may differ between Java implementations, or between host OSes.
Also, keep in mind that your computer hardware is not likely able to track time precisely by single nanoseconds. So elapsed time will be approximate.
The number returned represents nanoseconds. That means a billionth of a second. So your math is invalid.
Duration
Java offers you a class to track a span of time unattached to the timeline on a scale of nanoseconds: Duration. So no need for you to do any math.
long start = System.nanoTime() ;
…
Duration duration = Duration.ofNanos( System.nanoTime() - start ) ;
String report = duration.toString() ;
You may interrogate for the amount of elapsed time by calling the various to… methods.
Tips:
If doing benchmarking, consider using the jmh library.
If doing regular business-style apps, use java.time.Instant class to capture moments.
I currently do this to successfully get the current epoch time in nanos:
Instant inst = Instant.now();
long time = inst.getEpochSecond();
time *= 1000000000l;
time += inst.getNano();
However, it's a bit too slow for my use case, taking around 1us each call after the JVM has warmed up.
Is there a faster way to do it?
I'm happy with a solution that gives me the microseconds since epoch, as long as it's faster than the above.
What may work is to run:
long n1 = System.nanoTime();
long m = System.currentTimeMillis();
long n2 = System.nanoTime();
a number of times until the difference between n1 and n2 is less than the resolution you want (it's about 400 ns on my PC after a couple of iterations).
You can then use the difference between n1 (or n2 or an average of the 2...) and m * 1e6 as an offset that you need to add to System.nanoTime() to get the current epoch nanos.
Disclaimer:
System.nanoTime doc explicitly states that the resolution is at least that of System.currentTimeMillis(), which may be > 1 ms. So no guarantee that you will get microsecond resolution.
Corollary: this probably doesn't work in all environments (you may never get n2-n1 small enough - or it may be 0 just because the resolution of your system is too low).
System.nanoTime() may be out of sync over long periods - so this is a trade off between precision and performance.
You also need to account for possible arithmetic overflow.
See also: Current time in microseconds in java
I am asked to store the time right before my algorithm start, and time when it ends, and also need to provide the difference between them (end time - start time).
But the System.currentTimeMillis() function generates values that are too long:
start=1497574732045
end=1497574732168
Is there a way to make this value just 3 digits like "123" but also be as precise as using the System.currentTimeMillis() function?
as the currentTimeMillis() description says:-
Returns the current time in milliseconds. Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems measure time in units of tens of milliseconds.
Returns:
the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
in your case use this simple trick and you will get the desired result.
Long startTime= Long.parseLong("1497674732168");
Long endTime= Long.parseLong("1497574732168");
System.out.println("start time is"+new Date(startTime)+"end time is"+new Date(endTime));
If you need to store the start and end times separately, there are only two ways (I can think of) to make the values smaller.
Firstly, System.currentTimeMillis() counts from January 1, 1970 UTC. But if your clock is never going to run previous to "now", you can subtract a fixed amount of time. I chose 1497580000000 as it's definitely in the past at the time I wrote this and its a nice even number.
Second, divide the value by any amount of precision you are willing to lose. In your case you might not want to even do that, but here I chose 100.
The numbers returned look small now, but they will continue to get bigger as the difference between the current time and 1497580000000 become more pronounced.
The preferred solution is to not do any of this at all, but just store the long value if you can.
You'll never magic a large precise number into only 3 decimal digits. Not without quantum mechanics.
{
long start = 1497584001010L;
long end = 1497584008000L;
System.out.println("Diff: " + (end - start));
int compactStart = compact(start);
int compactEnd = compact(end);
System.out.println("Compact Start: " + compactStart);
System.out.println("Compact End: " + compactEnd);
System.out.println("Diff: " + (expand(compactEnd) - expand(compactStart)));
}
private int compact(long millis) {
return (int)((millis - 1497580000000L)/100);
}
private long expand(int millis) {
return (millis + 1497584000000L)*100;
}
Result...
Diff: 6990
Compact Start: 40010
Compact End: 40080
Diff: 7000
Note 7000 doesn't equal 6990 because of the intentional precision loss.
I use for example this code to check if the user can do some action. So the user can only do one action each 5 seconds.
if((System.currentTimeMillis() - lastTime) > 5000)
{
// Message: Ok, you can do action now.
}else{
// Message: Have to wait 5 seconds to do action.
return;
}
lastTime = System.currentTimeMillis();
But as we all know, System.currentTimeMillis() returns a long, and that long can keep increasing until it turns negativ..
My code should run on a server that need to have more than 1 month of uptime. So I'm afraid at some point System.currentTimeMillis() will return a negativ value and my code will always tell the user that he need to wait 5 seconds or the opposite.
I'm having real hard time to concentrate on this piece of code and fix it, so I'm asking you guys if you have a tip on how to fix this problem and make my code 100% safe.
Don't worry about it.
You know whos problem it is?
The guy who will need to update it on Sun Aug 17 03:12:55 GMT-04:00 292278994.
A long in milliseconds can represent 292 277 266 years. I'm not sure this is the kind of thing you need to be worried about.
According to this thread, it will overflow in year 292278994. I will say it is plenty of time:)
As everyone has said don't worry about it but for future reference maybe you'd prefer to use Joda-Time to ask this kind of question.
import org.joda.time.DateTime;
if(lastTime.plusSeconds(5).isAfterNow()) {
// Message: Ok, you can do action now.
}
else {
// Message: Have to wait 5 seconds to do action.
return;
}
lastTime = new DateTime();
System.currentTimeMillis() returns the time in milliseconds, between the current time and midnight, January 1, 1970 UTC. With the largest maximum value that can be represented as a long is 9,223,372,036,854,775,807, if my calculation is right (long max / (1000 * 3600 * 24 * 365)), that could go up to more than 292471208 years. If your program can survive that long, let someone who will be born that many years later worry about it like we did for Y2K.
Even though the time it will overflow is far, far into the future as others have stated. It won't even be a problem then because you are taking the difference of two times. e.g. say you take the year 292,278,994 and the year 292,278,995 (which would appear to be negative), the difference is only 1 year (a positive number) e.g. if you take
long overflowYear = Long.MIN_VALUE; // overvflow of Long.MAX_VALUE + 1
long okayYear = Long.MAX_VALUE;
// time = 1 (positive due to an underflow!)
long time = overflowYear - okayYear;
This sort of this could happen with System.nanoTime() as it doesn't have a defined starting time and ticks one million time faster. However as long as you take the time difference, it doesn't matter if one is negative or positive provided they are less than 292 years apart.
So in answer to your question, even after the year 292,278,994 you won't have a problem until the application have been running for more than 292,278,994 years between calls to System.currentTimeMillis() !
I'm in and android widget and checking elapsed time between two calls of System.nanoTime() and the number is huge. How do you measure elapsed time with this? it should be a fraaction of a second and instead its much more. Thanks
The System.nanoTime() returns a time value whose granularity is a nanosecond; i.e. 10-9 seconds, as described in the javadoc. The difference between two calls to System.nanoTime() that are a substantial fraction of a second apart is bound to be a large number.
If you want a time measure with a larger granularity, consider System.currentTimeMillis() ... or just divide the nanosecond values by an appropriate power of 10 to suit your application.
Note that on the Android platform there are 3 distinct system clocks that support different "measures" of time; see SystemClock. If you are programming explicitly for the Android platform, you should read the javadoc and decide which measure is most appropriate to what you are doing.
For your information, "nano-" is one of the standard prefixes defines by the International System of Units (SI) - see http://physics.nist.gov/cuu/Units/prefixes.html.
If you really think that "they" got it wrong and that "nano-" is too small, you could always write a letter to the NIST. I'm sure someone would appreciate it ... :-)
One seconds contains 1,000,000,000 nanoseconds, so as long as your number is in that range, it's reasonable.
If you want it in fractional form, just take your value / 10^9 where value is your difference in nanoTime()s.
long nanoSeconds = 500000000;
float seconds = nanoSeconds / 1000000000;
Log.i("NanoTime", nanoSeconds + " ns is the same as " + seconds + " seconds");
Your output would be:
07-27 11:35:47.196: INFO/NanoTime(14237): 500000000 ns is the same as 0.5 seconds