我需要将某个日期与当前日期/时间进行比较,以确保它在当前月份的第一天/小时/分钟/秒之前。为了实现这个功能,我使用getActualMinimum
方法配置了一个Calendar
实例,然而,今天(星期四,19/01/2023 - 10:40:18 BRT 2023),它呈现了一个我以前从未遇到过的行为。考虑下面的代码:
Calendar cal = Calendar.getInstance();
System.out.println("After instantiation: " + cal.getTime());
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
System.out.println("After configuring the Day of Month: " + cal.getTime());
cal.set(Calendar.HOUR_OF_DAY, cal.getActualMinimum(Calendar.HOUR_OF_DAY));
System.out.println("After configuring the Hour of day: " + cal.getTime());
cal.set(Calendar.MINUTE, cal.getActualMinimum(Calendar.MINUTE));
System.out.println("After configuring the Minutes: " + cal.getTime());
cal.set(Calendar.SECOND, cal.getActualMinimum(Calendar.SECOND));
System.out.println("After configuring the Seconds: " + cal.getTime());
cal.set(Calendar.MILLISECOND, cal.getActualMinimum(Calendar.MILLISECOND));
System.out.println("After configuring the Millis: " + cal.getTime());
上面的代码,在这篇文章被创建的那一刻,将打印到控制台:
After instantiation: Thu Jan 19 10:40:18 BRT 2023
After configuring the Day of Month: Sun Jan 01 10:40:18 BRT 2023
After configuring the Hour of day: Sat Dec 31 23:40:18 BRT 2022
After configuring the Minutes: Sat Dec 31 23:00:18 BRT 2022
After configuring the Seconds: Sat Dec 31 23:00:00 BRT 2022
After configuring the Millis: Sat Dec 31 23:00:00 BRT 2022
谁能解释一下,为什么在配置了一天中的小时后,值被设置为2300
?编辑:我使用Java 8,特别是JDK 1.8.0_241
我的当前和默认时区是Horário padr
java.time
java.util
Date-Time API及其格式化API,SimpleDateFormat
是过时的,容易出错。建议完全停止使用它们并切换到现代Date-Time API。
使用java.time
(现代日期时间API),您可以为不同的目的提供专门的类型。一个非常常见的类型是ZonedDateTime
,它包含时区信息以及日期和时间信息。
注意与java.util
日期-时间类型不同,java.time
类型是不可变的,即在设置新值时总是得到一个新实例;因此,像String
一样,如果您希望引用指向新值,则需要将新值赋给引用。
演示strong>:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAdjusters;
import java.util.Locale;
class Main {
public static void main(String[] args) {
// Replace ZoneId.systemDefault() with the applicable ZoneId e.g.
// ZoneId.of("America/New_York")
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.systemDefault());
System.out.println(zdt);
zdt = zdt.with(TemporalAdjusters.firstDayOfMonth());
System.out.println(zdt);
zdt = zdt.withHour(LocalTime.MIN.getHour());
System.out.println(zdt);
zdt = zdt.withMinute(LocalTime.MIN.getMinute());
System.out.println(zdt);
zdt = zdt.withSecond(LocalTime.MIN.getSecond());
System.out.println(zdt);
zdt = zdt.with(ChronoField.MILLI_OF_SECOND, LocalTime.MIN.getLong(ChronoField.MILLI_OF_SECOND));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
System.out.println(zdt.format(formatter));
// In a single statement
String output = ZonedDateTime.now(ZoneId.systemDefault())
.with(TemporalAdjusters.firstDayOfMonth())
.withHour(LocalTime.MIN.getHour())
.withMinute(LocalTime.MIN.getMinute())
.withSecond(LocalTime.MIN.getSecond())
.with(ChronoField.MILLI_OF_SECOND, LocalTime.MIN.getLong(ChronoField.MILLI_OF_SECOND))
.format(formatter);
System.out.println(output);
// There is a better way if all you want is day-1 with minimum time
zdt = LocalDate.now(ZoneId.systemDefault())
.with(TemporalAdjusters.firstDayOfMonth())
.atStartOfDay()
.atZone(ZoneId.systemDefault());
System.out.println(zdt.format(formatter));
}
}
示例运行的输出:
2023-01-19T16:50:43.811714Z[GMT]
2023-01-01T16:50:43.811714Z[GMT]
2023-01-01T00:50:43.811714Z[GMT]
2023-01-01T00:00:43.811714Z[GMT]
2023-01-01T00:00:00.811714Z[GMT]
2023-01-01T00:00:00.000Z
2023-01-01T00:00:00.000Z
2023-01-01T00:00:00.000Z
<在线演示/kbd>
从Trail: Date Time了解更多关于现代Date-Time API的信息.
如果您需要使用遗留API的解决方案:
Calendar#getTime
返回一个java.util.Date
的实例,它不是一个真实的日期时间对象;相反,它只包含从January 1, 1970, 00:00:00 GMT开始的毫秒数。Date#toString
应用系统的时区来计算日期时间,并返回相同的时间。
获得具有所需时区的日期-时间字符串的方法是将时区应用于SimpleDateFormat
并使用它来格式化java.util.Date
的实例。
演示strong>:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
class Main {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss.SSS z yyyy", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Calendar cal = Calendar.getInstance();
System.out.println("After instantiation: " + sdf.format(cal.getTime()));
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
System.out.println("After configuring the Day of Month: " + sdf.format(cal.getTime()));
cal.set(Calendar.HOUR_OF_DAY, cal.getActualMinimum(Calendar.HOUR_OF_DAY));
System.out.println("After configuring the Hour of day: " + sdf.format(cal.getTime()));
cal.set(Calendar.MINUTE, cal.getActualMinimum(Calendar.MINUTE));
System.out.println("After configuring the Minutes: " + sdf.format(cal.getTime()));
cal.set(Calendar.SECOND, cal.getActualMinimum(Calendar.SECOND));
System.out.println("After configuring the Seconds: " + sdf.format(cal.getTime()));
cal.set(Calendar.MILLISECOND, cal.getActualMinimum(Calendar.MILLISECOND));
System.out.println("After configuring the Millis: " + sdf.format(cal.getTime()));
}
}
示例运行的输出:
After instantiation: Thu Jan 19 15:29:38.381 UTC 2023
After configuring the Day of Month: Sun Jan 01 15:29:38.381 UTC 2023
After configuring the Hour of day: Sun Jan 01 00:29:38.381 UTC 2023
After configuring the Minutes: Sun Jan 01 00:00:38.381 UTC 2023
After configuring the Seconds: Sun Jan 01 00:00:00.381 UTC 2023
After configuring the Millis: Sun Jan 01 00:00:00.000 UTC 2023
<在线演示/kbd>
这可能是由您的PC的默认时区引起的,请尝试在声明Calnedar对象后添加此
cal.setTimeZone(TimeZone.getTimeZone("UTC"));