【问题标题】:Setting Minutes in Calendar differs depending on TimeZone日历中的分钟设置因时区而异
【发布时间】:2016-10-30 11:25:32
【问题描述】:

我刚刚发现 JAVA 日历类有一个奇怪的行为。 当我将分钟设置为 0 时,结果会因使用的时区而异。

有人知道为什么吗?

示例代码

import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;


public class CalendarTest {

    public static void main(String[] args) {
        Date date = new Timestamp(1477780200000L);
        System.out.println(date); // 2016-10-30 00:30:00.0

        testMethod(date, Calendar.getInstance(TimeZone.getTimeZone("CET"))); // Sun Oct 30 02:00:00 CET 2016
        testMethod(date, Calendar.getInstance(TimeZone.getTimeZone("GMT+1"))); // Sun Oct 30 02:00:00 CEST 2016
    }

    private static void testMethod(Date date, Calendar c) {
        c.setTime(date);
        c.add(Calendar.HOUR_OF_DAY, 2);

        c.set(Calendar.MINUTE, 0);

        System.out.println(c.getTime());
    }
}




编辑(使我的问题更容易理解):
更改了 testMethod
此更改的方法在 BOTH(!) 情况下均计算
Sun Oct 30 02:30:00 CEST 2016

private static void testMethod(Date date, Calendar c) {
    c.setTime(date);
    c.add(Calendar.HOUR_OF_DAY, 2);

    System.out.println(c.getTime());
}

【问题讨论】:

    标签: java calendar timezone


    【解决方案1】:

    您可以在下面的示例代码中看到显示的日期与实时(以毫秒为单位)有很大不同。问题是 Sun Oct 30 02:00:00 CET 2016 存在于 CETCEST 时区。切换 CEST => CET 时,您将返回一小时(产生小时重叠)。对于Calendar 对象,这非常棘手,因为您要表达所选时区的时间变化。当您想在这个非常具体的时间重置分钟时,Calendar 必须发现您在哪个时区表示更改。

    我不是 100% Calendar 是如何处理这个问题的,但在第一个例子中 CET,你特别建议你想使用 CET。因此,当发生重叠时Calendar 可以选择您的建议(CET)。当您使用GMT 来表达它时,Calendar 必须选择CETCEST 的时区之一并选择CEST

    public static void main(String[] args) {
        Date date = new Timestamp(1477780200000L);
        System.out.println(date); // 2016-10-30 00:30:00.0
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("CET"));
        calendar.setTime(date);
        print(1, calendar); // 1: Sun Oct 30 00:30:00 CEST 2016 | 1477780200000
        calendar.add(Calendar.HOUR_OF_DAY, 2);
        print(2, calendar); // 2: Sun Oct 30 02:30:00 CEST 2016 | 1477787400000
        calendar.set(Calendar.MINUTE, 0); // minutes expressed in CET
        print(3, calendar); // 3: Sun Oct 30 02:00:00 CET 2016 | 1477789200000
    
        System.out.println("--");
    
        calendar = Calendar.getInstance(TimeZone.getTimeZone("CET"));
        calendar.setTime(date);
        print(4, calendar); // 4: Sun Oct 30 00:30:00 CEST 2016 | 1477780200000
        calendar.add(Calendar.HOUR_OF_DAY, 2);
        print(5, calendar); // 5: Sun Oct 30 02:30:00 CEST 2016 | 1477787400000
        calendar.set(Calendar.MINUTE, 0); // minutes expressed in CET
        print(6, calendar); // 6: Sun Oct 30 02:00:00 CET 2016 | 1477789200000
    
        System.out.println("--");
    
        calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+1"));
        calendar.setTime(date);
        print(4, calendar); // 4: Sun Oct 30 00:30:00 CEST 2016 | 1477780200000
        calendar.add(Calendar.HOUR_OF_DAY, 2);
        print(5, calendar); // 5: Sun Oct 30 02:30:00 CEST 2016 | 1477787400000
        calendar.set(Calendar.MINUTE, 0); // minutes expressed in GMT
        print(6, calendar); // 6: Sun Oct 30 02:00:00 CEST 2016 | 1477785600000
    }
    
    private static void print(int prefix, Calendar calendar) {
        System.out.println(prefix + ": " + calendar.getTime() + " | " + calendar.getTimeInMillis());
    }
    

    更新

    更有趣的是Calendar方法getTimeInMillis

    public long getTimeInMillis() {
        if (!isTimeSet) {
            updateTime();
        }
        return time;
    }
    

    如您所见,时间在您获取时已更新!每次使用set 方法(如calendar.set(Calendar.MINUTE, 0))时,都会有一个标志isTimeSet 设置为false。这意味着您的时间在正确的时区/纪元等方面变得无效。这个方法只是将给定的日历字段设置为给定的值,就是这样。此外,如果您的设置有效,此方法不会进行任何额外的检查。另一方面,add 方法尊重日历规则并优雅地移动您的日期。

    总结一下。您将分钟设置为 0,这会强制日历重新计算日期。你是对的,set 是有问题的。

    【讨论】:

    • 感谢您的回答,但我仍然不明白为什么分钟的设置会导致不同的结果。我的意思是我将分钟设置为 0,所以我期望相同的小时,但比 setter 调用之前的 0 分钟。而且我不明白,为什么结果是移动了 1 小时(从 CET 到 CEST)
    猜你喜欢
    • 1970-01-01
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多