-1

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.

Andino
  • 1
  • 2
  • In your `run` method this line declares a new local variable: `LocalDateTime now = LocalDateTime.now();`. You don’t want that. You want to assign to the variable that you already have in the `Date` class. If you want that design, it should be something like `Date.setNow(LocalDateTime.now());` where `setNow` is a method in your `Date` class that sets that variable (a so-called setter). – Ole V.V. Sep 24 '22 at 06:20
  • When posting to Stack Overflow and asking people to read your code, please indent it properly. Your IDE can do it for you. Many more tips here: [Stack Overflow question checklist - Jon Skeet's coding blog](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Ole V.V. Sep 24 '22 at 06:25

2 Answers2

1

LocalDateTime is an immutable date-time object that represents a date-time, often viewed as year-month-day-hour-minute-second. Other date and time fields, such as day-of-year, day-of-week and week-of-year, can also be accessed. Time is represented to nanosecond precision. For example, the value "2nd October 2007 at 13:45.30.123456789" can be stored in a LocalDateTime.

It's from here: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html

'immutable' means that you cannot modify it.

You need to create a new instance of LocalDateTime and assing this new instance to your variable.

Igor Kanshyn
  • 867
  • 6
  • 13
1

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.

Example code

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
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Thank you so much for your thorough response. I managed to fix my code with your help. I going to read The Java™ Tutorials and keep learning to code Java. Thanks! – Andino Sep 24 '22 at 01:21