Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将一年添加到java.util.Calendar时出现奇怪的结果_Java_Date_Kotlin - Fatal编程技术网

将一年添加到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