设置HOUR_OF_DAY会损坏Java日历

时间:2016-09-12 23:14:30

标签: java calendar

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

实例化本地(PDT)时区中的Calendar对象并为其指定零(纪元开始)日期。在将日历的毫秒,秒和分钟设置为零之后,按照预期保持该值。但是,一旦将一天中的小时设置为零,则时间变为非零。它 获取值-57600000ms = -16小时。这可能是时区错误,但是-16小时的值与执行时生效的本地-7小时(PDT)偏移不对应。没有夏令时,时间偏移为PST(-8小时),也不对应-16小时。

如果设置小时应该会影响时区偏移,那么您也可以设置分钟,因为:(来自https://en.wikipedia.org/wiki/Time_zone)有几个地方"使用与标准时间的半小时偏差,以及一些& #34; ......"使用四分之一小时的偏差。"

代码:

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中找到了其他bug的描述,但我不认为这是已知的。

- 谢谢你的时间。

2 个答案:

答案 0 :(得分: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();
    }
}

答案 1 :(得分:0)

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 );