将一年添加到java.util.Calendar时出现奇怪的结果
使用将一年添加到java.util.Calendar时出现奇怪的结果,java,date,kotlin,Java,Date,Kotlin,使用1900年5月31日初始化java.util.Calendar。然后再加上一年二十次 以下是代码: import java.text.DateFormat import java.text.SimpleDateFormat import java.util.* fun main(args : Array<String>) { val f = SimpleDateFormat("yyyy.dd.MM") val cal = Calendar.getInstance
1900年5月31日初始化java.util.Calendar
。然后再加上一年二十次
以下是代码:
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
fun main(args : Array<String>) {
val f = SimpleDateFormat("yyyy.dd.MM")
val cal = Calendar.getInstance()
cal.set(1900, Calendar.MAY, 31)
for(i in 1..20) {
println(f.format(cal.time))
cal.add(Calendar.YEAR, 1)
}
}
为什么从1918年起我得到的是6月1日而不是5月31日
UPD:具有时间信息
1917.31.05 23:38:50.611
1918.01.06 01:38:50.611
如果这是DST的发明,我该如何防止呢?您似乎在一个时区运行代码,该时区在1917或1918年将其偏移量更改了两个小时。也就是说,UTC前后的小时数发生了变化。我不知道为什么你们的时区会这样做,但我相信这有一个很好的历史原因
如果您只对日期感兴趣,而没有时间组件,请使用java.Time.LocalDate
类,它实际上只表示一天、一个月和一年。它不受任何夏令时异常的影响
LocalDate today = LocalDate.now();
或
我假设你在欧洲/莫斯科时区。图灵85正确地发现了你观察到的行为的原因:1918年,你所在时区的夏令时(DST)开始于5月31日。时钟从22:00向前拨到24:00,也就是说,拨了两个小时。您的日历
对象知道这一点,因此拒绝在此日期给出23:38:50.611。相反,它选择了两小时后的时间,1918.01.06 01:38:50.611。现在,月份和日期已改为6月1日
不幸的是,此更改保留在日历中
并延续到下一年
如果这是DST发明,我该如何防止
Thomas Kläger in给出了正确的解决方案:如果您只需要日期,请使用java.time
中的LocalDate
:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuu.dd.MM");
LocalDate date = LocalDate.of(1900, Month.MAY, 31);
for (int i = 1; i <= 20; i++) {
System.out.println(date.format(dateFormatter));
date = date.plusYears(1);
}
LocalDate
中的“local”在java.time
行话中的意思是“没有时区”,因此这保证不会让您因时区异常而感到意外
LocalDate today = LocalDate.now();
如果你需要一个时间,你可以考虑<代码> LoalDATeTime< /Cord>,但是因为这也没有时区,它将给你不存在的时间1918.31.05 23∶38:50.611,所以可能不是。
你可以考虑的另一件事是把正确的年份加在1900。31.05:23∶38:50.611。那么,至少在你到达一个不存在的时间的年份里,你只会有惊喜。我正在使用
ZoneDateTime
进行此演示:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu.dd.MM HH:mm:ss.SSS");
ZonedDateTime originalDateTime = ZonedDateTime.of(1900, Month.MAY.getValue(), 31,
23, 30, 50, 611000000, ZoneId.of("Europe/Moscow"));
for (int i = 0; i < 25; i++) {
System.out.println(originalDateTime.plusYears(i).format(formatter));
}
1919年,夏季又从5月31日开始。这次时钟只提前了1小时,从23点到24点,所以你只比想象中的23:30:50.611晚了1小时
对于日期和时间工作,我推荐java.time
,尤其是像你这样在日期上做数学运算的时候。Calendar
类被认为早已过时java.time
的设计承认Calendar
和其他旧类的设计很差。现代人更适合一起工作
我怎么能确定是莫斯科?
在欧洲/莫斯科以外的任何时区,1918.31.05 23:38:50.611的时间都不存在。我检查:
LocalDateTime dateTime = LocalDateTime.of(1918, Month.MAY, 31, 23, 38, 50, 611000000);
for (String zid : ZoneId.getAvailableZoneIds()) {
ZonedDateTime zdt = dateTime.atZone(ZoneId.of(zid));
LocalDateTime newDateTime = zdt.toLocalDateTime();
if (! newDateTime.equals(dateTime)) {
System.out.println(zid + ": -> " + zdt + " -> " + newDateTime);
}
}
输出:
1900.31.05 23:30:50.611
1901.31.05 23:30:50.611
…
1917.31.05 23:30:50.611
1918.01.06 01:30:50.611
1919.01.06 00:30:50.611
1920.31.05 23:30:50.611
…
1924.31.05 23:30:50.611
Europe/Moscow: -> 1918-06-01T01:38:50.611+04:31:19[Europe/Moscow] -> 1918-06-01T01:38:50.611
W-SU: -> 1918-06-01T01:38:50.611+04:31:19[W-SU] -> 1918-06-01T01:38:50.611
“W-SU”是同一时区的一个弃用名称,它代表苏联西部
链接
- 解释如何使用
java.time
- 将W-SU显示为已弃用
- 声明“但很久以前……我们的名字基于比城市名称更具政治性的实体。例如,我们使用“W-SU”表示苏联西部……”
可能是DST的发明。打印整个内容,包括时间信息。如果您只想使用日期,最好使用java.time.LocalDate
-这实际上是一个日期,而java.util.Calendar
使用时间戳(日期和时间)可能是原因。仅供参考,麻烦的旧日期时间类,例如,和java.text.simpleDataFormat
现在被内置在Java8和更高版本中的类所取代。请参阅。“如果这是DST发明,我如何防止它?”我担心现在阻止DST发明已经太晚了-(1917年或1918年的变化本身还不足以解释。可能的解释是,时钟在1918年5月31日向前移动,这样我们通过增加一年来达到的时钟时间就不存在了。日历选择另一个时间,在这种情况下是午夜后的时间,因此日期改为6月1日。是的,@OleV.V你是对的。根据图灵85提供的链接,事情就是这样。在那一天,时钟从晚上10点移到了午夜。Ole,如果你想写你自己的答案,请打电话给我,我会投票给你。
LocalDateTime dateTime = LocalDateTime.of(1918, Month.MAY, 31, 23, 38, 50, 611000000);
for (String zid : ZoneId.getAvailableZoneIds()) {
ZonedDateTime zdt = dateTime.atZone(ZoneId.of(zid));
LocalDateTime newDateTime = zdt.toLocalDateTime();
if (! newDateTime.equals(dateTime)) {
System.out.println(zid + ": -> " + zdt + " -> " + newDateTime);
}
}
Europe/Moscow: -> 1918-06-01T01:38:50.611+04:31:19[Europe/Moscow] -> 1918-06-01T01:38:50.611
W-SU: -> 1918-06-01T01:38:50.611+04:31:19[W-SU] -> 1918-06-01T01:38:50.611