【问题标题】:Java Calendar is corrupted by setting HOUR_OF_DAYJava 日历因设置 HOUR_OF_DAY 而损坏
【发布时间】:2016-09-12 23:14:30
【问题描述】:

问题:您认为这是 java.util.Calendar 中的错误吗?

本地 (PDT) 时区的日历对象被实例化并分配零(纪元开始)日期。在将日历的毫秒、秒和分钟设置为零后,该值将保持不变。但是,一旦将一天中的小时设置为零,时间就会变为非零。它 获取值 -57600000ms = -16 小时。这可能是一个时区错误,但值 -16 小时与执行时有效的本地 -7 小时 (PDT) 偏移不对应。如果没有夏令时,时间偏移量是 PST(-8 小时),也不对应于 -16 小时。

如果设置小时会影响时区偏移量,您会期望设置分钟也应该因为:(来自https://en.wikipedia.org/wiki/Time_zone)一些地方“使用与标准时间的半小时偏差,有些地方”......“使用四分之一小时偏差。”

代码:

Date epochStart = new Date(0L);
System.out.println("epochStart=" + epochStart.getTime());

Calendar calendar = Calendar.getInstance();
calendar.setTime(epochStart);
System.out.println("epochStart in calendar=" + calendar.getTime().getTime());

calendar.set(Calendar.MILLISECOND, 0);
System.out.println("ms cleared in calendar=" + calendar.getTime().getTime());

calendar.set(Calendar.SECOND, 0);
System.out.println("second cleared in calendar=" + calendar.getTime().getTime());

calendar.set(Calendar.MINUTE, 0);
System.out.println("minute cleared in calendar=" + calendar.getTime().getTime());

calendar.set(Calendar.HOUR_OF_DAY, 0);
System.out.println("hourOfDay cleared in calendar=" + calendar.getTime().getTime());

输出:

epochStart=0
epochStart in calendar=0
ms cleared in calendar=0
second cleared in calendar=0
minute cleared in calendar=0
hourOfDay cleared in calendar=-57600000

我在 java.util.Calendar 中找到了其他错误的描述,但我认为这不为人所知。

-- 感谢您的宝贵时间。

【问题讨论】:

    标签: java calendar


    【解决方案1】:

    Java 很好,可以按预期工作。

    java.util.Date 是一个时间点,内部表示为自纪元开始(1970 年 1 月 1 日 00:00:00 UTC)以来的毫秒数。

    java.util.Calender 用于以时区相关格式处理时间信息。通常,时区是通过当前语言环境隐式定义的。调用calendar.setTime(xxx) 会及时获取所提供的时刻,并根据其时区将其转换为日历字段(年、月、日、小时、分钟……)。

    在您的情况下,纪元的开始分为Dec 31, 1969, 16:00:00.000 PDT。清除毫秒、秒和分钟字段没有任何效果,因为这些字段已经为零。

    但是,清除小时字段会将时间戳更改为 在您的情况下,纪元的开始分为Dec 31, 1969, 00:00:00.000 PDT

    以下代码显示了您的操作,以及将日历时间戳转换为 UTC 和 PDT 日期字符串。

    import java.text.SimpleDateFormat;
    import java.util.*;
    
    public class CalendarTest {
    
        public static void main(String[] args) {
            TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
            SimpleDateFormat udf = new SimpleDateFormat("'UTC: 'yyyy-MM-dd HH:mm:ss.SSS Z");
            udf.setTimeZone(TimeZone.getTimeZone("UTC"));
            SimpleDateFormat df = new SimpleDateFormat("'PDT: 'yyyy-MM-dd HH:mm:ss.SSS Z");
            df.setTimeZone(timeZone);
    
            Date epochStart = new Date(0L);
            System.out.println("epochStart=" + epochStart.getTime());
            System.out.println(udf.format(epochStart));
            System.out.println(df.format(epochStart));
            System.out.println();
    
            Calendar calendar = Calendar.getInstance(timeZone);
            calendar.setTime(epochStart);
            System.out.println("epochStart in calendar=" + calendar.getTime().getTime());
            System.out.println(udf.format(calendar.getTime()));
            System.out.println(df.format(calendar.getTime()));
            System.out.println();
    
            calendar.set(Calendar.MILLISECOND, 0);
            System.out.println("ms cleared in calendar=" + calendar.getTime().getTime());
            System.out.println(udf.format(calendar.getTime()));
            System.out.println(df.format(calendar.getTime()));
            System.out.println();
    
            calendar.set(Calendar.SECOND, 0);
            System.out.println("second cleared in calendar=" + calendar.getTime().getTime());
            System.out.println(udf.format(calendar.getTime()));
            System.out.println(df.format(calendar.getTime()));
            System.out.println();
    
            calendar.set(Calendar.MINUTE, 0);
            System.out.println("minute cleared in calendar=" + calendar.getTime().getTime());
            System.out.println(udf.format(calendar.getTime()));
            System.out.println(df.format(calendar.getTime()));
            System.out.println();
    
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            System.out.println("hourOfDay cleared in calendar=" + calendar.getTime().getTime());
            System.out.println(udf.format(calendar.getTime()));
            System.out.println(df.format(calendar.getTime()));
            System.out.println();
        }
    }
    

    【讨论】:

      【解决方案2】:

      tl;博士

      LocalDate.now( ZoneId.of( "America/Montreal" ) )
               .atStartOfDay( ZoneId.of( "America/Montreal" ) )
      

      java.time

      您正在使用麻烦的旧日期时间类,现在已被 java.time 类取代。

      看来你正试图抓住今天的第一刻。不要假设并将时间硬编码为00:00:00。在某些时区,由于夏令时 (DST) 等异常情况,一天的开始时间可能不同。让 java.time 确定第一个时刻。

      获取当前日期和时间。这需要一个时区。对于任何特定时刻,日期和时间都因全球区域而异。

      ZoneId z = ZoneId.of( "America/Montreal" );
      ZonedDateTime zdt = ZonedDateTime.now( z );
      

      只提取日期,没有时间和时区。

      LocalDate ld = zdt.toLocalDate();
      

      询问当天的第一时间,agsin 甚至指定时区。

      ZonedDateTime zdtStart = ld.atStartOfDay( z );
      

      【讨论】:

        猜你喜欢
        • 2016-10-16
        • 2020-11-28
        • 1970-01-01
        • 1970-01-01
        • 2016-10-30
        • 2012-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多