I have just started to learn Java, and I want to make random array and to measure time. I used System.currentTimeMillis(); at the beginning of filling my array, and the same at then and. Then I wanted to convert milliseconds to nanoseconds and used long total=TimeUnit.MILLISECONDS.toNanos(time1); but trouble occurred:
import java.util.*;
import java.util.concurrent.TimeUnit;
public class main {
public static void main(String[] args) {
long time1,time2,time3;
int [] array = new int[10];
Random rand =new Random(100);
time1=System.currentTimeMillis();
for(int i=0;i<array.length;i++){
array[i]=rand.nextInt(100);
}
time2=System.currentTimeMillis()-time1;
long total=TimeUnit.MILLISECONDS.toNanos(time1);
System.out.println("Time is:"+time1
);
}
}
In the end I got 'Time is:1361703051169;' I think that something's wrong with this.
Well, instead of using
System.currentTimeMillis()
you can use
System.nanoTime()
That provides the time in nanoseconds, without having to do any conversion
Also i think this maybe wrong:
long total=TimeUnit.MILLISECONDS.toNanos(time1);
System.out.println("Time is:"+time1);
Maybe you wanted to print total instead of time1?
EDIT
Please note that, as Mark Rotteveel said, in the System.nanoTime and System.currentTimeMillis() are different.
From Javadocs:
System.currentTimeMillis()
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.
and
System.nanoTime()
Returns the current value of the most precise available system timer, in nanoseconds.
This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time.
You may want to rewrite your code like this:
public static void main(String[] args) {
long start, end, difference;
start = System.nanoTime();
//code to meassure here
end = System.nanoTime();
difference = end - start;
System.out.println("Time taken:" + difference);
}
You can do a simple conversion with java.time.Duration like so: Duration.ofMillis(numberOfMilliseconds).toNanos()
Related
I'm doing a homework assignment where we're testing the runtime of a couple algorithms (greatest common divisor, or GCD) using 10-digit prime numbers.
We are to capture the runtime as milliseconds, which I capture using System.currentTimeMillis().
The way I do it is to have a start time variable and a stop time variable, then find the difference between those two in another variable.
So far, it works perfectly for one method, but returns 0 or 1 for the other method.
I went through the debugger, and it seemed to work correctly, but when I run it, it returns 0 or 1.
Here are the variables I'm using and the main method. The commented-out line works as intended, but the fastgcd method is the one that returns 0 or 1.
public class GCD {
public static long startTime;
public static long stopTime;
public static long elapsedTime;
public GCD(){
}
public static void main(String[] args){
startTime = System.currentTimeMillis();
//System.out.println(gcd(3267000013L, 1500450271L));
System.out.println(fastgcd(3267000013L, 1500450271L));
stopTime = System.currentTimeMillis();
elapsedTime = stopTime - startTime;
System.out.println(Long.toString(elapsedTime));
}
Here's the method that works:
public static String gcd(long a, long b) {
long n = Long.min(a, b);
for (long i = n; i >= 1; i--) {
if (a % i == 0 && b % i == 0) {
return "Done";
}
}
// If error
return null;
}
And here's the method that doesn't work:
public static String fastgcd(long a, long b){
if(b == 0){
return "Done";
}
else{
return fastgcd(b, a%b);
}
}
So for the method that works, I will get somewhere between 12000 - 12500 milliseconds for a 10-digit number.
The fastgcd method returns 0 or 1 milliseconds, which isn't right, especially a 10-digit prime number.
No idea where it's going wrong...
Your code is fine (in terms of getting time), and the values that you're getting are "correct". What you're measuring is wall-clock time (see here), which is inherently slightly inaccurate, and also not granular enough to measure code that is running as quickly as your fastgcd method.
For measuring elapsed time with a high degree of precision, use System.nanoTime() instead of System.currentTimeMillis().
If you run your method and check the recursion count, it will be called recursively only 19 times. And for these modern days compiler and machines, it is not huge operation. So completing it in 1 millisecond is totally justified. If you check it in nanoseconds using System.nanoTime(), fastgcd is taking around 280675 nanoseconds on my Windows machine Java 8, 32 GB RAM and 8th Gen Core I7. So nothing going wrong here.
I'm a novice in Java programming and I wanted to implement the timer class in my program.
I'm making a mini time-based testing system which outputs a question then time remaining and then the answer choices
Example:
Which operator returns the remainder of integer division? (4 minutes left...)
A. %
B./
C. *
D. None of the above
The escape sequence that represents the new line character is: (1 minutes left...)
A. \r
B. \t
C. \n
D. \
I don't know how to get that time remaining part. It's supposed to run in background and change right when the next question comes up
You can accomplish what you're trying to do without using timer, which will probably be easier, as you're new.
There's a function called System.currentTimeMillis() that returns the current system time in milliseconds. From that, you can:
Store the time when you start
Do some other stuff
Check the time when you stop, and calculate the time remaining
As such:
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
// Do other stuff...
long stopTime = System.currentTimeMillis();
int elapsedSeconds = (int)((stopTime - startTime) / 1000);
System.out.println(elapsedSeconds + " seconds elapsed");
}
I want to convert the result of System.nanoTime() to a date.
public void tempBan(Player p, Player banner, int timeInSeconds){
Long timeInNano = (long) (timeInSeconds * 10^9);
int newTime = (int) (System.nanoTime() + timeInNano);
// here I want to convert newTime to a date
}
I have converted the seconds into nanoseconds by multiplying by 10^9. Now I need to convert the current system time plus the parameter which I converted into nanoseconds into a date.
Unfortunately, System.nanoTime() is not what you want for this.
To quote the JavaDoc:
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 same origin is used by all invocations of this method in an instance of a Java virtual machine; other virtual machine instances are likely to use a different origin.
You probably want System.currentTimeMillis(), in which case you can use new Date(System.currentTimeMillis() + milliseconds) to get the date for that number of milliseconds in the future.
While you could then subtract System.nanoTime(), scale the value, and add System.currentTimeMillis() to have a similar result... since you're adding System.nanoTime() anyway and therefore have the original number of seconds, you could just use System.currentTimeMillis() directly.
In the theory, you should not use the only System.nanotime(), but you can do a simple trick with this method in order to get nanoseconds of the current time.
public class TimeProvider{
private final static long jvm_diff;
static {
jvm_diff = System.currentTimeMillis()*1000_000-System.nanoTime();
}
public static long getAccurateNow(){
return System.nanoTime()+jvm_diff;
}
}
Even though, you can create your own Clock implementation with this way for using high-level java data time classes.
public class HighLevelClock extends Clock {
private final ZoneId zoneId;
public HighLevelClock(ZoneId zoneId) {
this.zoneId = zoneId;
}
static long nano_per_second = 1000_000_000L;
#Override
public ZoneId getZone() {
return zoneId;
}
#Override
public Clock withZone(ZoneId zoneId) {
return new HighLevelClock(zoneId);
}
#Override
public Instant instant() {
long nanos = TimeProvider.getAccurateNow();
return Instant.ofEpochSecond(nanos/nano_per_second, nanos%nano_per_second);
}
}
Now we can use our clock implementation like the following:
Clock highLevelClock = new HighLevelClock(ZoneId.systemDefault());
System.out.println(LocalDateTime.now(highLevelClock)); //2020-04-04T19:22:06.756194290
System.out.println(ZonedDateTime.now(highLevelClock)); //2020-04-04T19:22:06.756202923+04:00[Asia/Baku]
System.out.println(LocalTime.now(highLevelClock)); //19:22:06.756220764
You can convert it into system time using the below code
public static long convertToUnixMs(final long timeMs) {
final long refMonoMs = monoTimeMs();
final long refUnixMx = System.currentTimeMillis();
return refUnixMx + (timeMs - refMonoMs);
}
public static long monoTimeMs() {
return System.nanoTime() / 1000000;
}
Explanation:
System.nonoTime() is a monotonic time that increases only, it has no idea of what time it is right now, but it would only increase regardless. So it is a good way for measuring elapsing time. But you can not convert this into a sensible time as it has no reference to the current time.
The provided method is a way to convert your stored nano time into a sensible time. First, you have a timeMs that is in nano time that you would like to convert. Then, you created another nanotime (i.e refMonoMs) and another System.currentTimeMillis() (i.e refUnixMx). Then you minus refMonoMs from the timeMs, and add the reference back into it to get the sensible time back.
I am having some strange output when I am attempting to get an average from a long value and converting it to a String (in HH:mm:ss) format. I'm using the Joda time library, which mostly has been a life saver.
Here's what I have so far:
//this is in a static class
public static Duration calculateTime(Date start, Date end) {
Duration duration = new Duration(start.getTime(), end.getTime());
return duration;
}
public static String convertMillisToTime(long milliseconds) {
return String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(milliseconds),
TimeUnit.MILLISECONDS.toMinutes(milliseconds) -
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(milliseconds)),
TimeUnit.MILLISECONDS.toSeconds(milliseconds) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliseconds)));
}
long averageRunTime = 0;
averageRunTime += calculateTime(drs.startTime, drs.endTime).getMillis();
Since this is done in an array list, to get the average, I am taking
averageRunTime = averageRunTime / (long)arrayList.size();
when I get to the point of
convertMillisToTime(averageRunTime);
It's returning a value that is higher than any times I have. IE( I have no job times that are over 11 hours) but this is returning me a String with 11:mm:ss. Not quite sure WHY?
I used the convertMillisToTime from: How to convert milliseconds to "hh:mm:ss" format?
Can anyone point me in the right direction?
Thank you in advance,
RR
Edit: I've modified the code that converts the long to time using TimeUnit. It's strange though, I grabbed three runs (time streams) and got 09:14:17, 08:57:18, 09:10:25 for the length of each run, and the average is coming out as: 10:27:26.
You could just use a formatter from Joda Time instead, for example...
public static final PeriodFormatter PERIOD_FORMATTER = new PeriodFormatterBuilder().printZeroAlways().
appendHours().appendSeparator(":").
appendMinutes().appendSeparator(":").
appendSeconds().appendSeparator(".").
appendMillis().toFormatter();
public static String toString(Duration duration) {
return duration == null ? "[invalid duration]" : duration.toPeriod().toString(PERIOD_FORMATTER);
}
Regarding the following method:
private long getCountdownLeft(Integer seconds) {
long now = System.currentTimeMillis();
long elapsedMillis = now - seconds;
long millisLeft = seconds * 1000 - elapsedMillis;
return millisLeft/1000;
}
public static void Main(String[] args) {
getApi().getLogger.debug("TimeLeft " + getCountDownLeft(3600)); //base time
}
It is returning a value of something like: -12039495960, why is that?
If 3600 is the value you are passing in, you're obviously going to get a negative value.
Print out System.currentTimeMillis(), youll see that it is quite a large value.
currentTimeMillis() is defined as:
the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
It's extremely hard to tell based on the information given, but for this method to work, seconds must be initialized with System.currentTimeMillis() / 1000.
Boiled down into one statement, you have
return (seconds * 999 - System.currentTimeMillis())/1000;
If System.currentTimeMillis() is unix time (1343874904292 right now), then OF COURSE this will be negative. I'm not sure what you meant to write, but this obviously not it...
Your problem is you are subtracting seconds from milliseconds.
Try this:
long elapsedMillis = now - (seconds * 1000); // convert seconds to millseconds
It seems you are really just trying to do this:
private long getCountdownLeft(Integer seconds) {
return seconds * 1000;
}