简体   繁体   中英

Scheduling a task to happen at a specific time (in Java)

I have already looked at the forum for this and I kind of got the answer, but it didn't quite fit my problem.

So the thing is (this is for a college assignment): I have to schedule a task to happen at a specific time in the future (to be defined by the user of the program).

First I started trying to get this working by choosing a date this way:

//this is my main class

        DateFormat dateFormatter = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
        String year = String.valueOf(LocalDate.now().getYear());
        String month = String.valueOf(LocalDate.now().getMonthValue());
        String day = "05";
        Date date = dateFormatter.parse(year + "-" + month + "-" + day + " 02:24:08");

        Timer timer = new Timer();
        timer.schedule(new MyTimeTask("Patrick"), date);

//the class MyTimeTask:

        public class MyTimeTask extends TimerTask {
           private String name;
           public MyTimeTask(String name) {
              this.name = name;
           }
           public void run() {
              System.out.println(this.name);
           }
        }

The problem is: this doesn't run at the time I want. Instead, it automatically runs as soon as I run the file, no matter how far in the future I choose the date.

Where am I wrong?

Thank you.

You have a couple problems in your code that need addressed.

First is this: new SimpleDateFormat("yyyy-mm-dd hh:mm:ss") . Take a closer look at your pattern. yyyy-mm-dd hh:mm:ss translates to year-minute-day hour:minute:second . I believe you want the month after the year, not the minute. A simple change to yyyy-MM-dd hh:mm:ss fixes that.

Second, LocalDate.now().getMonthValue() is (at the moment) returning 6 (instead of 06 ), so your pattern yyyy:MM:dd does not match it. To fix this, I would combine your year and month strings into a single variable so you can use DateTimeFormatter to format the month as MM :

String yearMonth = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));

Now you can parse your date like this:

Date date = dateFormatter.parse(yearMonth + "-" + day + " 02:24:08");

The last thing I would do (this is not completely necessary) is to specify whether the given time is ante meridian or post meridian, or change the hour to military time. To do this you can just add "aa" to end of your date formatter.

Here's the final code:

DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ssaa");
String yearMonth = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
String day = "04";
Date date = dateFormatter.parse(yearMonth + "-" + day + " 02:24:08PM");

Timer timer = new Timer();
timer.schedule(new MyTimeTask("Patrick"), date);

java.time

You are already using LocalDate from java.time, the modern Java date and time API. That's good. When Timer.schedule() requires an old-fashioned java.util.Date object:

  1. Do your time math using java.time exclusicely.
  2. Convert to a modern Instant .
  3. Convert the Instant to a Date just before calling the legacy API that requires a Date .

For your purpose I suggest:

    ZoneId zone = ZoneId.systemDefault();
    Instant scheduleTime = YearMonth.now(zone)
            .atDay(5)
            .atTime(LocalTime.of(2, 24, 8))
            .atZone(zone)
            .toInstant();
    Date oldfashionedDate = Date.from(scheduleTime);

    System.out.println(oldfashionedDate);

Output when running in my time zone just now:

Fri Jun 05 02:24:08 CEST 2020

What went wrong in your code?

  1. Your format pattern string, yyyy-mm-dd hh:mm:ss , is wrong. Format pattern letters are case sensitive, so it makes a difference whether you use uppercase MM or lowercase mm , and whether you use HH or hh . I believe that this is the reason for your timer firing prematurely.
  2. As a matter of clear code I prefer to pass a time zone to LocalDate.now() even if the time zone you pass is ZoneId.systemDefault() .
  3. Don't read LocalDate.now() twice. If your code runs over midnight, you risk getting two different dates and an inconsistent result in the end. Read the date once and use that reading in the rest of your code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM