I am trying to make a program that updates currentTime every second so that in the console it will go 1s, 2s, 3s, 4s and so on.
public static void main(String[] args) throws InterruptedException{
OSpanel runner = new OSpanel();
runner.currentTime();
}
public static void currentTime() throws InterruptedException{
if(true) {
Date currentTime = new Date();
while(true) {
Thread.sleep(1000);
System.out.println(currentTime);
Thread.sleep(1000);
System.out.println(currentTime);
}
}
}
java.time
The java.util Date-Time API is outdated and error-prone. It is recommended to stop using it completely and switch to the modern Date-Time API*.
You can use Instant#now to get the current instant of time. In order to get it every second, you can use ScheduledExecutorService#scheduleWithFixedDelay e.g.
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
Executors.newScheduledThreadPool(1)
.scheduleWithFixedDelay(
() -> System.out.println(Instant.now()),
0,
1,
TimeUnit.SECONDS
);
}
}
Output from a sample run:
2021-10-03T13:53:42.462768Z
2021-10-03T13:53:43.469758Z
2021-10-03T13:53:44.470316Z
...
ONLINE DEMO
An Instant represents an instantaneous point on the timeline, normally represented in UTC time. The Z in the output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
Note: If you want to print just the running second, replace the print statement with the following:
System.out.println(ZonedDateTime.now(ZoneOffset.UTC).getSecond() + "s")
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project. Android 8.0 Oreo already provides support for java.time.
You are updating currentTime outside of the while loop - you are outputting the date to the console every second but you are not updating the time.
Try this:
Main.java
public static void main(String[] args) throws InterruptedException{
OSpanel runner = new OSpanel();
runner.currentTime();
}
OSpanel.java
public void currentTime() throws InterruptedException{
int counter = 1;
while (true) {
System.out.println(counter + "s");
Thread.sleep(1000);
counter++;
}
}
}
Duration
Adding to the good Answer by Avinash, let me show the use of Duration to track elapsed time.
Record a starting moment.
Instant start = Instant.now() ; // Capture the current moment as seen in UTC.
At any other moment, calculate elapsed time on a scale of hours-minutes-seconds using the java.time.Duration class.
Duration d = Duration.between( start , Instant.now() ) ;
Generate text representing that elapsed time in standard ISO 8601 format: PnYnMnDTnHnMnS .
String output = Duration.toString() ;
PT21s
To generate text in a custom format, write a method that accesses the various parts. Call toHoursPart, toMinutesPart, etc. Put those parts together in whatever way you desire.
Pulling this all together, in the code of that other Answer, change this line:
() -> System.out.println( Instant.now() ) ,
… to this line:
() -> System.out.println( Duration.between( start , Instant.now() ).toString() ) ,
… or call your custom formatting method.
This will create a thread pool with one thread which will execute the lambda printing the number of seconds since the program started once every second.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class SOAnswer {
public static void main(String[] args) {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
long start = System.currentTimeMillis();
executorService.scheduleAtFixedRate(() -> System.out.println(String.format("%ds", (System.currentTimeMillis() - start) / 1000)), 0, 1, TimeUnit.SECONDS);
}
}
Related
I was working with LocalDateTime and trying to see if the purchase date(in my case) is withing last x units(days/hours)
I achieved this the following way
public static final int BOOK_PURCHASED_MIN_HOURS = 72;
private boolean isWithinAllowedMinTime(LocalDateTime purchaseDateTime) {
return !LocalDateTime.now(ZoneOffset.UTC).minusHours(BOOK_PURCHASED_MIN_HOURS ).isAfter(purchaseDateTime);
}
This works perfectly fine and gives me true or false if the book has been purchase in 72 hours
I was wondering something like this can be done but with Duration in java where I do not have to worry about time unit and simply can specify like PT03D or PT72H
I was wondering something like this can be done but with Duration in
java where I do not have to worry about time unit and simply can
specify like PT03D or PT72H
Of course, you can do so. You can pass a duration string to your function and parse it to a Duration object to perform a calculation based on it.
I also recommend you use OffsetDateTime instead of LocalDateTime so that you can use the same offset with OffsetDateTime#now.
Demo:
class Main {
public static void main(String[] args) {
// Tests
System.out.println(isWithinAllowedMinTime(OffsetDateTime.now(ZoneOffset.UTC).minusHours(50), "PT72H")); // true
System.out.println(isWithinAllowedMinTime(OffsetDateTime.now(ZoneOffset.UTC).minusHours(75), "PT72H")); // false
System.out.println(isWithinAllowedMinTime(OffsetDateTime.now(ZoneOffset.UTC).minusHours(50), "P3DT12H")); // true
System.out.println(isWithinAllowedMinTime(OffsetDateTime.now(ZoneOffset.UTC).minusHours(72), "P3DT12H")); // true
System.out.println(isWithinAllowedMinTime(OffsetDateTime.now(ZoneOffset.UTC).minusHours(90), "P3DT12H")); // false
}
static boolean isWithinAllowedMinTime(OffsetDateTime purchaseDateTime, String strDuration) {
Duration duration = Duration.parse(strDuration);
return !OffsetDateTime.now(purchaseDateTime.getOffset()).minus(duration).isAfter(purchaseDateTime);
}
}
Output:
true
false
true
true
false
Learn more about the modern Date-Time API from Trail: Date Time.
I wrote my own utility where you can specify time interval as "3d" for 3 days "72h" for 72 hours and so on. This utility is part of Open Source MgntUtils Java library written and maintained by me. Here is a code to demonstrate the point:
private static final String BOOK_PURCHASED_MIN_INTERVAL = "72h"; //possible values could be like "3d" for 3 days
private static void timeIntervalTest() {
TimeInterval bookPurchesedMinInterval = TextUtils.parseStringToTimeInterval(BOOK_PURCHASED_MIN_INTERVAL);
ZonedDateTime purchaseDateTime = ZonedDateTime.now().minusHours(71); //This is to simulate your parameter of book purchacing date
long seconds = ZonedDateTime.now().toEpochSecond() - purchaseDateTime.toEpochSecond();
System.out.println(seconds > bookPurchesedMinInterval.toSeconds());
}
Here is Javadoc for TextUtils.parseStringToTimeInterval() method. If you want to use the library you can get it it as maven artifacts or on Github (source code and Javadoc included). Here is the link for full Javadoc
I’m currently using selenium in a web bot to purchase items on a website. When I search for the item I want to buy and it cannot be found I use driver.navigate().refresh() to refresh the page to see if it is there now, it will keep doing this until it finds the product when it is released on the page. However, I wish to start my bot a few hours before the release of the product which currently doesn’t work as after roughly 30 seconds of refreshing the page I get banned from the page due to the anti-ddos software they use. One option is to increase the delay between refreshing, however I need to catch the release of this product as soon as possible so I’m trying to find a way that my program can wait/sleep until 30 seconds before the release however I’m struggling to find a way to do this.
Just call Thread.sleep with the appropriate amount of milliseconds:
public static void main(String[] args) throws InterruptedException {
long currentTime = System.currentTimeMillis();
long releaseTime = currentTime + 1000 * 60 * 60 * 24 * 3; // 3 days
Thread.sleep(releaseTime - currentTime);
}
Another way would be to use java.time classes:
public static void main(String[] args) throws InterruptedException {
LocalDateTime now = LocalDateTime.now();
LocalDateTime release = LocalDateTime.of(2019, 10, 30, 13, 30);
long sleepDuration = Duration.between(now, release).toMillis();
TimeUnit.MILLISECONDS.sleep(sleepDuration);
}
Java 9 introduces new methods to the Duration class like toSeconds(), toMinutes() and so on.
You could also consider using a ScheduledExecutorService to schedule your tasks. This is especially useful if you have multiple tasks to schedule and don't want having multiple threads being blocked for that:
private static final ScheduledExecutorService service = new ScheduledThreadPoolExecutor(2);
private static ScheduledFuture<?> scheduleTask(Runnable task, LocalDateTime releaseTime) {
Duration duration = Duration.between(LocalDateTime.now(), releaseTime);
return service.schedule(task, duration.toSeconds(), TimeUnit.SECONDS);
}
In general, to sleep until the next Thursday at 10:59 you could use the following code:
LocalDateTime release = LocalDateTime.now()
.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY))
.withHour(10)
.withMinute(59);
Duration duration = Duration.between(LocalDateTime.now(), release);
TimeUnit.MILLISECONDS.sleep(duration.toMillis());
I think rather than sleeping you should take a look at scheduled tasks with cron expressions in Spring... that way you don't have a blocked thread just sitting there.
Scheduled Tasks with Spring
Cron Expressions
I have the following code in my class
private static final SimpleDateFormat SDF_ISO_DATE = new SimpleDateFormat("yyyy-MM-dd");
private static final SimpleDateFormat SDF_ISO_TIME = new SimpleDateFormat("HH:mm:ss");
public static String getTimeStampAsString(final long time) {
TimeZone tz = TimeZone.getTimeZone("UTC");
SDF_ISO_DATE.setTimeZone(tz);
SDF_ISO_TIME.setTimeZone(tz);
return SDF_ISO_DATE.format(
new Date(time)) + " " + SDF_ISO_TIME.format(new Date(time)
);
}
In my multi threaded application the following method returns date in future, even for the current date, is the static method or variable is responsible for this?
edit:
I had the following code to reproduce and prove what are mentioned in the answers,but still not able to.Can some one help me for the same.
public static void main(String[] args) throws InterruptedException, ExecutionException {
Callable<String> task = new Callable<String>(){
public String call() throws Exception {
return DateUtil.getTimeStampAsString(1524567870569L);
}
};
//pool with 50 threads
ExecutorService exec = Executors.newFixedThreadPool(50);
List<Future<String>> results = new ArrayList<Future<String>>();
//perform 10 date conversions
for(int i = 0 ; i < 50 ; i++){
results.add(exec.submit(task));
}
exec.shutdown();
//look at the results
for(Future<String> result : results){
System.out.println(result.get());
}
}
is the static method or variable is responsible for this?
Static variables. SimpleDateFormat isn't thread-safe, which should be obvious since you're modifying its internal state by calling setTimeZone(). It means that several threads could be doing that at the same time, which should feel like producing unpredictable results.
You need to build your formats locally rather than reuse some defined statically. Or better yet, drop Java's old time-managing classes and use java.time.* instead.
As an answer to your edit: how to reproduce the problem with thread-unsafety (not sure whether that really ought to be a separate question). Formatting the same date in two or more threads using the same SimpleDateFormat seems to go well (at least most often, no guarantee that it always will). Try formatting different date-times, and it will be very easy to get wrong results. I changed your task like this:
AtomicLong time = new AtomicLong(1_524_567_870_569L);
Callable<String> task = new Callable<String>(){
#Override
public String call() {
return DateUtil.getTimeStampAsString(time.getAndAdd(2_768_461_000L));
}
};
It’s easiest to see that the results are wrong when I also sort them in the output, so I have done that. I am only quoting the first few results from one run since this is enough to demonstrate the problem:
2018-04-24 11:04:30
2018-05-26 12:05:31
2018-06-11 13:06:32
2018-07-29 14:07:33
2018-08-08 15:08:34
2018-10-01 16:09:35
…
The expected result was (obtained by declaring getTimeStampAsString() synchronized; also sorted afterward):
2018-04-24 11:04:30
2018-05-26 12:05:31
2018-06-27 13:06:32
2018-07-29 14:07:33
2018-08-30 15:08:34
2018-10-01 16:09:35
…
Already the fifth printed result has the day-of-month all wrong, 08 instead of 30, and there are many more errors in the full list. You may try it yourself. As you probably know, exact results are not reproducible, but you should get results that are wrong somehow.
PS Here’s my code for printing the results in sorted order in case you want to try it:
//look at the results
SortedSet<String> sorted = new TreeSet<>();
for (Future<String> result : results){
sorted.add(result.get());
}
sorted.forEach(System.out::println);
tl;dr
To capture the current moment and generate a string in your desired format (which is a modified form of standard ISO 8601 format), use the java.time classes. These classes are much simpler and vastly better designed. They are also thread-safe.
Instant.now().toString().replace( "T" , " " )
Current moment
Your method is named getCurrentTimeStamp(final Date date) yet you are passing an existing Date object set to a specific moment rather than capturing the current moment.
Nowhere in your code do I see you capturing the current moment. If you want the current moment, call Instant.now() as shown below.
Avoid legacy date-time classes
The legacy date-time classes such as Date & SimpleDateFormat are not thread-safe. One of many reasons to avoid these troublesome classes. They were supplanted years ago by the java.time classes.
java.time
As a moment in UTC, the java.util.Date class is replaced by the Instant class. Same idea, but Instant has a resolution in nanoseconds rather than milliseconds. And Instant::toString does not inject a time zone dynamically as Date::toString does.
To capture the current moment in UTC, call the static Instant.now() method.
Instant instant = Instant.now() ; // Capture current moment in UTC.
Parse your input number as a count of milliseconds since the epoch reference of first moment of 1970 in UTC.
Instant instant = Instant.ofEpochMilli( 1_524_567_870_569L ) ;
instant.toString(): 2018-04-24T11:04:30.569Z
No need for must of your code. No need for your DateUtil, as seen in code above. No need for custom formatting patterns, as your desired format happens to comply with the ISO 8601 standard used by default in the java.time classes. If the T in the middle bothers you or your users, replace with a SPACE.
String output = instant.toString().replace( "T" , " " ) ;
2018-04-24T11:04:30.569Z
ExecutorService blocking
You seem to misunderstand ExecutorService::shutdown. That method does not block to wait for tasks to complete. As your code is written, some tasks may not yet be done running until after you report results (partially-completed results).
Add a call to ExecutorService::awaitTermination, as seen in code below. Set a time-out long enough that if exceeded it must mean some problem occurred. To quote the doc:
Block until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
See example code below. For more discussion see this Question, ExecutorService - How to wait for completition of all tasks in non-blocking style
Threads
The java.time classes are thread-safe by design. They use the immutable objects pattern, returning fresh object based on existing values rather than changing (“mutating”) the original.
Example code. Your Question is confused about whether you want a hard-coded moment or the current moment. Switch to either by enabling the commented-out line in this example.
Callable < String > task = new Callable < String >() {
public String call () throws Exception {
long threadId = Thread.currentThread().getId();
// String moment = Instant.ofEpochMilli( 1524567870569L ).toString().replace( "T" , " " );
String moment = Instant.now().toString().replace( "T" , " " );
String output = ( moment + " | " + threadId );
return output;
}
};
// Pool with 5 threads
ExecutorService exec = Executors.newFixedThreadPool( 5 );
List < Future < String > > results = new ArrayList < Future < String > >();
// Perform a certain number of tasks.
int countAssignedTasks = 500;
for ( int i = 0 ; i < countAssignedTasks ; i++ ) {
results.add( exec.submit( task ) );
}
// Wait for tasks to complete.
Boolean completedBeforeTimeOut = null;
try {
exec.shutdown();
completedBeforeTimeOut = exec.awaitTermination( 5 , TimeUnit.SECONDS ); // Block until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
} catch ( InterruptedException e ) {
e.printStackTrace();
}
// Report results.
System.out.println( "completedBeforeTimeOut: " + completedBeforeTimeOut );
for ( Future < String > result : results ) {
try {
System.out.println( result.get() );
} catch ( InterruptedException e ) {
e.printStackTrace();
} catch ( ExecutionException e ) {
e.printStackTrace();
}
}
System.out.println( "BASIL - done." );
When run.
Note that the times are not chronological. In multi-threaded code, you cannot predict which tasks will be executed when.
2018-04-24 20:24:06.991225Z | 13
2018-04-24 20:24:06.991246Z | 14
2018-04-24 20:24:06.991236Z | 15
2018-04-24 20:24:06.991232Z | 16
2018-04-24 20:24:06.991222Z | 17
2018-04-24 20:24:07.067002Z | 16
2018-04-24 20:24:07.067009Z | 17
tz is effectively constant and the setters don't do anything after the first invocation of either method. Use a static initialiser to set the timezone right away to make the methods thread-safe.
private static final SimpleDateFormat SDF_ISO_DATE = new SimpleDateFormat("yyyy-MM-dd");
private static final SimpleDateFormat SDF_ISO_TIME = new SimpleDateFormat("HH:mm:ss");
static {
TimeZone tz = TimeZone.getTimeZone("UTC");
SDF_ISO_DATE.setTimeZone(tz);
SDF_ISO_TIME.setTimeZone(tz);
}
public static String getCurrentTimeStamp(final Date date) {
return SDF_ISO_DATE.format(date) + " " + SDF_ISO_TIME.format(date);
}
public static String getTimeStampAsString(final long time) {
return getCurrentTimeStamp(new Date(time));
}
I am trying to calculate the age of the person based on the date of birth and doing some logic if its over 18 years. I had my code written and it was working fine, but I stumbled upon a code I found online and I am not getting one condition in that. The code is:
public class AgeValidation {
public static void main(String[] args) {
getAge("29-12-1999");
}
private static void getAge(String dob1) {
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
Date dob;
try {
dob = format.parse(dob1);
Calendar dob2 = Calendar.getInstance();
dob2.setTime(dob);
Calendar today = Calendar.getInstance();
int age = today.get(Calendar.YEAR) - dob2.get(Calendar.YEAR);
if(dob2.after(today)) {
System.out.println("Future date not allowed");
System.exit(0);
}
if (today.get(Calendar.MONTH) < dob2.get(Calendar.MONTH)) {
System.out.println("First if condition");
age--;
} else if (today.get(Calendar.MONTH) == dob2.get(Calendar.MONTH)
&& today.get(Calendar.DAY_OF_MONTH) < dob2.get(Calendar.DAY_OF_MONTH)) {
System.out.println("else if condition");
age--;
}
if (age < 18) {
System.out.println(age);
System.out.println("Underage");
} else {
System.out.println(age);
System.out.println("18 years");
//Some logic
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
Need addressing on below points:
I have added a condition if DOB year is after Current year it should not proceed.
if(dob2.after(today)) {
System.out.println("Future date not allowed");
System.exit(0);
}
Is it correct to use System.exit(0); or is there some better approach to stop further execution.
In the code that I found online I saw a condition as
` if (today.get(Calendar.MONTH) < dob2.get(Calendar.MONTH))`
I am not getting in which scenario will this be executed.
Is there any use case in which this code will not work (I cannot think of any)
java.time
You should not (as in not) want to use the long outdated classes SimpleDateFormat, Date and Calendar. Especially the first is notoriously troublesome, but we have better replacements for all of them in java.time, the modern Java date and time API also known as JSR-310.
And even more so because the modern API has a method for counting years between two dates built-in. Not only is it easier to write the code, more importantly it is easier to read and understand, and you can be more sure of the correctness.
private static final DateTimeFormatter dateFormatter
= DateTimeFormatter.ofPattern("dd-MM-uuuu");
private static void getAge(String dob1) {
LocalDate dob = LocalDate.parse(dob1, dateFormatter);
LocalDate today = LocalDate.now(ZoneId.of("Asia/Dushanbe"));
if (dob.isAfter(today)) {
System.out.println("Future date not allowed");
} else {
int age = (int) ChronoUnit.YEARS.between(dob, today);
if (age < 18) {
System.out.println(age);
System.out.println("Underage");
} else {
System.out.println(age);
System.out.println("18 years");
//Some logic
}
}
}
With your example date of "29-12-1999" the above method prints:
17
Underage
Since it is never the same date in all time zones, please substitute your desired time zone instead of Asia/Dushanbe.
between() returns a long. In this case we can safely cast it to an int because LocalDate only handles years in the range -999 999 999 through 999 999 999, so the difference in years will never exceed the capacity of int.
Your questions
Use of System.exit(0); is generally questionable, though at times necessary. In my code I have avoided it using an if-else construct. Another option would be return;. I guess this would more give you what you wanted in case there were two calls to getAge() after each other. Yet another option is throwing an IllegalArgumentException, that would leave for the caller to decide to catch it or not.
The line you are quoting will not be executed when running your code here in December. Imagine running your code next January, then today’s month will be January and dob2’s month will still be December, so since January is before December, the code will be executed. Which will also be necessary for your method to calculate the correct age.
The code seems convoluted, as Jim Garrison said, but appears to be correct (not even with the outdated API needed it be this complex). I have not spotted a case that would not be handled correctly.
Question: Can I use the modern API with my Java version?
If using at least Java 6, you can.
In Java 8 and later the new API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310).
On Android, use the Android edition of ThreeTen Backport. It’s called ThreeTenABP, and there’s a thorough explanation in this question: How to use ThreeTenABP in Android Project.
For learning to use java.time, see the Oracle tutorial or find other resoureces on the net.
I am giving you a solution which doesn't take care of leap year logic. But you can build upon this approach.
public static void main(String[] args) throws Exception{
String date ="11_10_1991";
SimpleDateFormat sdf = new SimpleDateFormat("dd_MM_yyyy");
Date birthDate = sdf.parse(date);
long ageInMillis = System.currentTimeMillis() - birthDate.getTime();
long years = ageInMillis /(365 * 24*60*60*1000l);
long leftover = ageInMillis %(365 * 24*60*60*1000l);
long days = leftover/(24*60*60*1000l);
System.out.println(years);
System.out.println(days);
}
Is javax.swing.Timer timer; enough for computing the time elapsed? I'm doing a Tetris project that also calculates the time it took for the player to play the game. In the play method,
public void play() {
reset();
onPlay = true;
Thread thread = new Thread(new Game());
thread.start();
rightPanel.setPlayButtonEnable(false);
rightPanel.setPause(true);
rightPanel.setStop(true);
playItem.setEnabled(false);
pauseItem.setEnabled(true);
stopItem.setEnabled(true);
setBlockColorItem.setEnabled(false);
setBGColorItem.setEnabled(false);
rightPanel.requestFocus();
//time.start();
//timeElapsed = System.currentTimeMillis();
RightPanel.timeElapsedTextField.setText("");
timer.start();
startTime = System.currentTimeMillis();
}
In the stop method,
public void stop() {
isStop=true;
onPlay = false;
if (piece != null)
piece.isMoving = false;
playItem.setEnabled(true);
rightPanel.setPlayButtonEnable(true);
pauseItem.setEnabled(false);
rightPanel.setPauseButtonLabel(true);
stopItem.setEnabled(false);
resumeItem.setEnabled(false);
setBlockColorItem.setEnabled(true);
setBGColorItem.setEnabled(true);
rightPanel.setPause(false);
rightPanel.setStop(false);
reset();
//time.stop();
timer.stop();
long delta = (System.currentTimeMillis() - startTime)/10;
RightPanel.timeElapsedTextField.setText(Double.toString(delta/100.0) + " seconds");
}
Are those enough? Whenever try to display the time elapsed, the JTextField displays nothing. What can be wrong? Thank you very much!
public void run() {
int column = 4, style = Piece.SHAPES[(int) (Math.random() * 7)][(int) (Math.random() * 4)];
//timer.start();
//startTime = System.currentTimeMillis();
while (onPlay) {
if (piece != null) {
if (piece.isAlive()) {
try {
Thread.currentThread().sleep(100);
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
continue;
}
}
checkFullLine();
if (isGameOver()) {
playItem.setEnabled(true);
pauseItem.setEnabled(true);
resumeItem.setEnabled(false);
rightPanel.setPlayButtonEnable(true);
rightPanel.setPauseButtonLabel(true);
displayGameOver();
return;
}
piece = new Piece(style, -1, column, board);
piece.start();
//numDropped = numDropped+1;
//RightPanel.scoreTextField.setText(numDropped+"");
style = Piece.SHAPES[(int) (Math.random() * 7)][(int) (Math.random() * 4)];
rightPanel.setTipStyle(style);
numDropped = numDropped+1;
RightPanel.numDroppedTextField.setText(numDropped+"");
//RightPanel.numDroppedTextField = new JTextField(numDropped+"");
long startTime = System.currentTimeMillis();
}
long estimatedTime = ((System.currentTimeMillis() - startTime)/1000);
RightPanel.timeElapsedTextField.setText(estimatedTime+"");
}
You should use nanoTime() to calculate elapsed time.
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
You have a Thread running for Game. I think you should calculate startTime in start of run() method and estimatedTime end of run() method. I can only speculate since I don't know Game class code.
Below is the simple illustration of how you can do it.
import java.util.concurrent.TimeUnit;
public class Demo implements Runnable {
private volatile boolean shouldRun = true;
#Override
public void run() {
long startTime = System.nanoTime();
while (shouldRun) {
// do nothing
}
long estimatedTime = System.nanoTime() - startTime;
System.out.println(TimeUnit.NANOSECONDS.toSeconds(estimatedTime));//Print apprx 5 seconds since time may be required to actually enter in to run method after start
}
public void stop() {
shouldRun = false;
}
public static void main(String[] args) throws InterruptedException {
Demo demo = new Demo();
Thread thread = new Thread(demo);
thread.start();
Thread.sleep(5000);// 5 Seconds sleep
demo.stop();// Stop the thread
}
}
tl;dr
Duration
.between(
then ,
Instant.now()
)
.toSeconds()
Details
Timer does not measure elapsed time.
Your calls to System.currentTimeMillis measure elapsed time. But that method is obsolete with Java 8 and later. Instead, use java.time.Instant.
Instant represents a moment in UTC with a resolution of nanoseconds. However, the hardware clocks in current conventional computers do not track time that accurately, so Instant.now captures the current moment with a resolution of microseconds in Java 9 and later (and milliseconds in Java 8 only).
Instant start = Instant.now() ;
…
Instant stop = Instant.now() ;
To represent the time elapsed between those two moments, use Duration.
Duration d = Duration.between( start , stop ) ;
Generate text in standard ISO 8601 for that elapsed time.
String output = d.toString() ;
Or interrogate for a count of seconds or some such.
long secondsElapsed = d.toSeconds() ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.