I'm learning Java on my own and I'm stuck with the following problem. I scheduled my code to run for every 120 seconds and my issue here is that can't find the way to update LocalDateTime variable now outside of the run() method. I have a private static class called Date and I'm using this so I'm able to use this variables in other parts of the code that need to use the date at the same time.
public class Test{
private static class Date {
//This wont update every 120 seconds
private static final LocalDateTime now = LocalDateTime.now();
private static final DateTimeFormatter archive = DateTimeFormatter.ofPattern("yyyy MM dd HH:mm");
}
public Test(int seconds) {
timer = new Timer();
timer.schedule(new APICallerTask(), 0,seconds * 1000L); }
static class APICallerTask {
public void run() {
//This will update every 120 seconds
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter archive = DateTimeFormatter.ofPattern("yyyy MM dd HH:mm");}
}
public static void main(String[] args) {
new Test(120);
}
}
I'm sorry if this is a dumb question but I'm not being able to figure it out.
Any help is appreciated.
Thanks in advance.
As seen in correct Answer by Kanshyn, LocalDateTime
is immutable. You need to store a fresh new instance when you want a new value.
Also, LocalDateTime
is the wrong class here. The LocalDateTime
class lacks the context of an offset-from-UTC or a time zone.
When tracking a moment, a specific point in the timeline, use Instant
, OffsetDateTime
, or ZonedDateTime
.
In your case, probably best to use Instant
in your data model. When presenting to user, adjust to their expected time zone.
Instant instant = Instant.now() ;
ZoneId z = ZoneId.of( "Africa/Tunis" ) ; // Or ZoneId.systemDefault().
ZonedDateTime zdt = instant.atZone( z ) ;
Generate text from that ZonedDateTime
by using DateTimeFormatter
. Automatically localize by calling ZonedDateTime.ofLocalizedDateTime
. Search Stack Overflow to learn more as this has been covered many times already.
I'm learning Java on my own and I'm stuck with the following problem.
Study The Java™ Tutorials by Oracle Corp., free of cost.
See the section on date-time handling with java.time here.
I have a private static class called
Date
Java comes with two classes named Date
. I suggest using another name to avoid confusion.
static class APICallerTask {
No need to make your task class static
.
private static class Date {
Try to resist the urge to use that static
label. As a beginner, you'll almost always be using static
in a wrong or less-than-optimal fashion. Code with static
is not object-oriented.
timer = new Timer();
The Timer
and TimerTask
classes are legacy, as noted in their Javadoc. Best to use the Executors framework in Java 5+. See The Java™ Tutorials.
A ScheduledExecutorService
runs tasks repeatedly.
ScheduledExecutorService see = Executors.newSingleThreadScheduledExecutor() ;
ses.scheduleAtFixedRate( myRunnable , initialDelay, period, TimeUnit.SECONDS ) ;
…
… // Eventually shut down the executor service gracefully using boilerplate code found in Javadoc.
For that shutdown boilerplate, see ExecutorService Javadoc.
We define an app to hold a reference to latest recorded moment. Because we expect to access this reference across threads, we use AtomicReference
for thread-safety.
Our task is a nested class, UpdateMomentTask
. That class implements Runnable
, which means it promises to implement a method named run
. The ScheduledExecutorService
calls that run
method on our behalf.
On each execution of its run
method, we capture the current moment by instantiating a new Instant
object. Our task then stores a reference to that object as the payload of our app’s AtomicReference
variable named moment
.
Notice no static
anywhere (except main
).
package work.basil.example.now;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
public class App
{
AtomicReference < Instant > moment = new AtomicReference <>( Instant.now() );
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
System.out.println( "Demo start: " + Instant.now() );
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
Runnable task = new UpdateMomentTask();
ses.scheduleAtFixedRate( task , 0 , 10 , TimeUnit.SECONDS );
// We sleep this main thread to give our background task time enough to do some work.
try { Thread.sleep( Duration.ofMinutes( 1 ).toMillis() ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
this.shutdownAndAwaitTermination( ses );
System.out.println( "Last recorded moment was: " + this.moment.get().toString() );
System.out.println( "Demo end: " + Instant.now() );
}
class UpdateMomentTask implements Runnable
{
@Override
public void run ( )
{
Instant currentMoment = Instant.now();
moment.set( currentMoment );
System.out.println( "Set the moment to: " + currentMoment );
}
}
// Boilerplate taken from https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ExecutorService.html.
// Slightly modified here.
void shutdownAndAwaitTermination ( ExecutorService executorService )
{
executorService.shutdown(); // Disable new tasks from being submitted
try
{
// Wait a while for existing tasks to terminate.
if ( ! executorService.awaitTermination( 60 , TimeUnit.SECONDS ) )
{
executorService.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled.
if ( ! executorService.awaitTermination( 60 , TimeUnit.SECONDS ) )
{ System.err.println( "Executor service did not terminate. " + Instant.now() ); }
}
}
catch ( InterruptedException ex )
{
// (Re-)Cancel if current thread also interrupted.
executorService.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
}
When run:
Demo start: 2022-09-23T20:46:06.420162Z
Set the moment to: 2022-09-23T20:46:06.435521Z
Set the moment to: 2022-09-23T20:46:16.433719Z
Set the moment to: 2022-09-23T20:46:26.425594Z
Set the moment to: 2022-09-23T20:46:36.426603Z
Set the moment to: 2022-09-23T20:46:46.422073Z
Set the moment to: 2022-09-23T20:46:56.427291Z
Set the moment to: 2022-09-23T20:47:06.423843Z
Last recorded moment was: 2022-09-23T20:47:06.423843Z
Demo end: 2022-09-23T20:47:06.430045Z