Java Calendar会随机添加毫秒数?

时间:2015-09-16 00:47:38

标签: java

嗨,我发生了一些奇怪的事情。我只是拿一个日历对象,将其转换为各个部分,并将其放回日历中(有或没有任何更改。在这种情况下,我不做任何更改)。我的意思是,这应该是剪切和粘贴。我还尝试使用calendar = Calendar.getInstance()创建日历并手动设置所有内容。 calendar.set(Calendar.YEAR,mStartYear);等等。仍然提供错误的Calendar对象。我也尝试过设置毫秒,似乎总是有一些垃圾毫秒......但是这种或那种方式的时间完全是关闭的。也许有人看到了愚蠢的疏忽,但我很难过。

这也是一个Android应用程序,但对于基本的Java库对象无关紧要。

注意Weekview是我正在使用的其中一个库的数据包装器。它有一个开始和结束日历。

这是调试器在内存中列出的内容..

mEndDay = 19
mEndHour = 9

mEndMinute = 30
mEndMonth = 8
mEndYear = 2015
mSeekAmount = 0
mStartDay = 18
mStartHour = 23
mStartMinute = 0
mStartMonth = 8
mStartYear = 2015


            Calendar calendarStart = Calendar.getInstance();
            calendarStart.set(mStartYear,mStartMonth,mStartDay,mStartHour,mStartMinute);

            Calendar calendarEnd = Calendar.getInstance();
            calendarEnd.set(mEndYear,mEndMonth,mEndDay,mEndHour,mEndMinute);

我最终得到了

Start 1442363359161
End 1442363359161

calendarStart = {GregorianCalendar@20968} "java.util.GregorianCalendar[time=?,areFieldsSet=false,lenient=true,zone=America/Denver,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2015,MONTH=8,WEEK_OF_YEAR=38,WEEK_OF_MONTH=3,DAY_OF_MONTH=18,DAY_OF_YEAR=258,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=6,HOUR_OF_DAY=23,MINUTE=0,SECOND=19,MILLISECOND=161,ZONE_OFFSET=-25200000,DST_OFFSET=3600000]"
calendarEnd = {GregorianCalendar@20969} "java.util.GregorianCalendar[time=?,areFieldsSet=false,lenient=true,zone=America/Denver,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2015,MONTH=8,WEEK_OF_YEAR=38,WEEK_OF_MONTH=3,DAY_OF_MONTH=19,DAY_OF_YEAR=258,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=6,HOUR_OF_DAY=9,MINUTE=30,SECOND=19,MILLISECOND=161,ZONE_OFFSET=-25200000,DST_OFFSET=3600000]"

EXPECT

Start 1442638800000
End 1442676600000

mEndTime = {GregorianCalendar@20990} "java.util.GregorianCalendar[time=1442676600000,areFieldsSet=true,lenient=true,zone=America/Denver,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2015,MONTH=8,WEEK_OF_YEAR=38,WEEK_OF_MONTH=3,DAY_OF_MONTH=19,DAY_OF_YEAR=262,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=3,AM_PM=0,HOUR=9,HOUR_OF_DAY=9,MINUTE=30,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-25200000,DST_OFFSET=3600000]"
mName = {String@20991} "sleep"
mStartTime = {GregorianCalendar@20992} "java.util.GregorianCalendar[time=1442638800000,areFieldsSet=true,lenient=true,zone=America/Denver,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2015,MONTH=8,WEEK_OF_YEAR=38,WEEK_OF_MONTH=3,DAY_OF_MONTH=18,DAY_OF_YEAR=261,DAY_OF_WEEK=6,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=11,HOUR_OF_DAY=23,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-25200000,DST_OFFSET=3600000]"

这是我最初设置的地方..

   WeekViewEvent weekViewEvent = dateWrapperParam.getWeekViewEvent();
    Calendar endCalendar = weekViewEvent.getEndTime();
    Calendar startCalendar = weekViewEvent.getStartTime();

    Date endDate = endCalendar.getTime();
    Date startDate = startCalendar.getTime();

    mStartHour = startCalendar.get(Calendar.HOUR_OF_DAY);
    mStartMinute = startCalendar.get(Calendar.MINUTE);
    mStartDay = startCalendar.get(Calendar.DAY_OF_MONTH);
    mStartMonth = startCalendar.get(Calendar.MONTH);
    mStartYear = startCalendar.get(Calendar.YEAR);

    mEndHour = endCalendar.get(Calendar.HOUR_OF_DAY);
    mEndMinute = endCalendar.get(Calendar.MINUTE);
    mEndDay = endCalendar.get(Calendar.DAY_OF_MONTH);
    mEndMonth = endCalendar.get(Calendar.MONTH);
    mEndYear = endCalendar.get(Calendar.YEAR);

4 个答案:

答案 0 :(得分:0)

根据您在我的问题下的评论,startCalendarcalendarStart时间之间只有秒和毫秒的差异,因为这些值未重置。

请参阅DEMO

答案 1 :(得分:0)

Calendar.set的文档中,有人说:

  

设置字段YEAR,MONTH,DAY_OF_MONTH,HOUR,MINUTE和SECOND的值。保留其他字段的先前值。如果不需要,请先致电clear()

原因是并非所有字段都使用此方法设置,在您的情况下,您没有设置MILLISECOND。因此它在创建实例时保留值。

Calendar.clear的来电

  

设置此Calendar的所有日历字段值和时间值(与Epoch的毫秒偏移量)undefined。

一个简单的例子:

    Calendar c = GregorianCalendar.getInstance();
    c.clear();
    c.set(2019, Calendar.NOVEMBER, 03, 16, 15, 03);

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

Sun Nov 03 16:15:03 CET 2019
  1572794103000

未定义的毫秒数将为0

答案 2 :(得分:0)

java.time和ThreeTenABP

我建议您使用java.time(现代的Java日期和时间API)进行日期和时间工作。例如:

    ZonedDateTime start = ZonedDateTime.now(ZoneId.systemDefault());
    ZonedDateTime end = start;
    
    System.out.println("Start: " + start);
    System.out.println("End:   " + end);

我刚才在时区运行代码时的输出:

Start: 2020-06-24T19:24:04.811+02:00[Europe/Copenhagen]
End:   2020-06-24T19:24:04.811+02:00[Europe/Copenhagen]

ZonedDateTime是某个时区中的日期和时间。这是我们最接近的等效于GregorianCalendar(您的代码为您提供的Calendar的子类)的现代形式。使用哪种现代类随更精确的要求而变化,因此有时您会更喜欢使用LocalDateOffsetDateTime甚至是LocalTime

要将值截断为整分钟(将秒和秒的秒数设置为0):

    ZonedDateTime start = ZonedDateTime.now(ZoneId.systemDefault())
            .truncatedTo(ChronoUnit.MINUTES);
Start: 2020-06-24T19:24+02:00[Europe/Copenhagen]

ZonedDateTime和其他java.time类提供了许多方法来修改获得的值。例如:

    ZonedDateTime end = start.plusDays(2).withHour(13);
End:   2020-06-26T13:24+02:00[Europe/Copenhagen]

如果您要仅使用开始时间中的选定字段手动创建结束时间:

    ZonedDateTime end = ZonedDateTime.of(
            2021, start.getMonthValue(), start.getDayOfMonth(),
            start.getHour(), 30, 0, 0, start.getZone());
End:   2021-06-24T19:30+02:00[Europe/Copenhagen]

您的代码出了什么问题?

部分答案已经在其他答案中:set的{​​{1}}方法仅设置他们承诺设置的字段,并在可能的情况下保持其他字段不变。尽管这可能是Calendar方法所期望的,但它常常使set​(int field, int value)方法感到惊讶,甚至使set​(int year, int month, int date)set​(int year, int month, int date, int hourOfDay, int minute)更加令人惊讶。通常,虽然set​(int year, int month, int date, int hourOfDay, int minute, int second)类及其子类的意图很好,但它们的设计很差且令人困惑,使用起来很麻烦。这就是我推荐上述java.time的主要原因。

答案的另一部分是Calendar宽大地计算其字段。因此,当您在调用Calendar后在调试器中查看Calendar对象时,它将包含很多垃圾值。调用set会强制getTime()计算其字段,因此在调用之后,它在调试器中的显示方式应该更有意义。再次,这令人困惑,并且有时也可以在不使用调试器的情况下观察到它。

问题:java.time是否不需要Android API级别26?

java.time在较新和较旧的Android设备上均可正常运行。它只需要至少 Java 6

  • 在Java 8和更高版本以及更新的Android设备(API级别26以上)中,内置了现代API。
  • 在非Android Java 6和7中,获得ThreeTen Backport,这是现代类的backport(JSR 310的ThreeTen;请参见底部的链接)。
  • 在旧版Android上,请使用Android版的ThreeTen Backport。称为ThreeTenABP。并确保使用子包从Calendar导入日期和时间类。

链接

答案 3 :(得分:0)

初始化Calendar对象时,它将获取当前时间,包括当前的秒和毫秒。提供的代码设置小时和分钟,但不设置秒和毫秒,而是保留设置Calendar对象初始化时的时间。 为了将秒和纳秒设置为零,请使用:

StartCalendar.set(Year, Month, DayofMonth, Hour, Minute, 0,0);