安排任务在特定时间发生(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
对象时:
- 专门使用 java.time 计算时间。
- 转换为现代
Instant
。
- 在调用需要
Date
. 的遗留 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
你的代码出了什么问题?
- 您的格式模式字符串
yyyy-mm-dd hh:mm:ss
是错误的。格式模式字母区分大小写,因此使用大写 MM
或小写 mm
,以及使用 HH
或 hh
都会有所不同。我相信这就是您的计时器过早触发的原因。
- 作为清晰的代码,我更喜欢将时区传递给
LocalDate.now()
,即使您传递的时区是 ZoneId.systemDefault()
。
- 不要读
LocalDate.now()
两遍。如果您的代码在午夜运行,您可能会得到两个不同的日期和最终不一致的结果。读取一次日期并在其余代码中使用该读数。
我已经在论坛上看过这个问题,我得到了一些答案,但它不太符合我的问题。
所以事情是(这是大学作业):我必须安排一个任务在未来的特定时间发生(由程序的用户定义)。
首先,我开始尝试通过这种方式选择日期来实现此目的:
//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
对象时:
- 专门使用 java.time 计算时间。
- 转换为现代
Instant
。 - 在调用需要
Date
. 的遗留 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
你的代码出了什么问题?
- 您的格式模式字符串
yyyy-mm-dd hh:mm:ss
是错误的。格式模式字母区分大小写,因此使用大写MM
或小写mm
,以及使用HH
或hh
都会有所不同。我相信这就是您的计时器过早触发的原因。 - 作为清晰的代码,我更喜欢将时区传递给
LocalDate.now()
,即使您传递的时区是ZoneId.systemDefault()
。 - 不要读
LocalDate.now()
两遍。如果您的代码在午夜运行,您可能会得到两个不同的日期和最终不一致的结果。读取一次日期并在其余代码中使用该读数。