安排任务在特定时间发生(Java)

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

我已经在论坛上看过这个问题,我得到了一些答案,但它不太符合我的问题。

所以事情是(这是大学作业):我必须安排一个任务在未来的特定时间发生(由程序的用户定义)。

首先,我开始尝试通过这种方式选择日期来实现此目的:

//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);
           }
        }

问题是:这不是我想要的 运行。相反,它会在我 运行 文件后立即自动 运行s,无论我选择多远的未来日期。

我哪里错了?

谢谢。

您的代码中有几个问题需要解决。

首先是:new SimpleDateFormat("yyyy-mm-dd hh:mm:ss")。仔细看看你的模式。 yyyy-mm-dd hh:mm:ss 转换为 year-minute-day hour:minute:second。我相信您想要年后的月份,而不是分钟。对 yyyy-MM-dd hh:mm:ss 进行简单更改即可解决此问题。

其次,LocalDate.now().getMonthValue()(目前)返回 6(而不是 06),因此您的模式 yyyy:MM:dd 与它不匹配。要解决此问题,我会将您的年份和月份字符串组合成一个变量,这样您就可以使用 DateTimeFormatter 将月份格式化为 MM

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

现在您可以像这样解析您的日期:

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

我要做的最后一件事(这不是完全必要的)是指定给定时间是早午线还是 post 早午线,或者将小时更改为军事时间。为此,您只需将 "aa" 添加到日期格式化程序的末尾即可。

这是最终代码:

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

您已经在使用来自 java.time 的 LocalDate,现代 Java 日期和时间 API。那挺好的。当 Timer.schedule() 需要一个老式的 java.util.Date 对象时:

  1. 专门使用 java.time 计算时间。
  2. 转换为现代Instant
  3. 在调用需要 Date.
  4. 的遗留 API 之前将 Instant 转换为 Date

为了您的目的,我建议:

    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);

刚才在我的时区运行时的输出:

Fri Jun 05 02:24:08 CEST 2020

你的代码出了什么问题?

  1. 您的格式模式字符串 yyyy-mm-dd hh:mm:ss 是错误的。格式模式字母区分大小写,因此使用大写 MM 或小写 mm,以及使用 HHhh 都会有所不同。我相信这就是您的计时器过早触发的原因。
  2. 作为清晰的代码,我更喜欢将时区传递给 LocalDate.now(),即使您传递的时区是 ZoneId.systemDefault()
  3. 不要读 LocalDate.now() 两遍。如果您的代码在午夜运行,您可能会得到两个不同的日期和最终不一致的结果。读取一次日期并在其余代码中使用该读数。