3

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

这也是一个 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]"

预计

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

4 回答 4

1

在 的文档中Calendar.set,它说:

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

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

Calendar.clear意志的呼唤

设置此日历未定义的所有日历字段值和时间值(从纪元开始的毫秒偏移量)。

一个简单的例子:

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

2019年11月3日星期日16:15:03 CET
1572794103000

毫秒未定义将给出 0

于 2018-04-25T13:31:11.597 回答
0

java.time 和 ThreeTenABP

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

    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]

AZonedDateTime是某个时区的日期和时间。这是我们最接近现代等效物的GregorianCalendarCalendar您的代码给您的子类)。使用哪个现代类因更精确的要求而异,因此有时您会更喜欢使用 例如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方法。Calendar虽然这可能是该方法所期望的set​(int field, int value),但该方法通常会令人惊讶,而and则set​(int year, int month, int date)更是如此。一般而言,尽管类及其子类的设计意图良好,但设计不佳且令人困惑,并且使用起来很麻烦。这也是我在上面推荐 java.time 的主要原因。set​(int year, int month, int date, int hourOfDay, int minute)set​(int year, int month, int date, int hourOfDay, int minute, int second)Calendar

答案的另一部分是宽松地Calendar计算其字段。所以当你Calendar在调用后查看调试器中的对象时set,它会包含很多垃圾值。调用会getTime()强制Calendar计算其字段,因此在调用之后它在调试器中的外观应该更有意义。同样,这是令人困惑的行为,有时也可以在不使用调试器的情况下观察到。

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

java.time 在较旧和较新的 Android 设备上都能很好地工作。它只需要至少Java 6

  • 在 Java 8 及更高版本以及更新的 Android 设备(从 API 级别 26 开始)中,现代 API 是内置的。
  • 在非 Android Java 6 和 7 中获得 ThreeTen Backport,现代类的后向端口(ThreeTen 用于 JSR 310;请参阅底部的链接)。
  • 在(较旧的)Android 上使用 ThreeTen Backport 的 Android 版本。它被称为 ThreeTenABP。并确保从org.threeten.bp子包中导入日期和时间类。

链接

于 2020-06-24T17:27:25.760 回答
0

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

演示

于 2015-09-18T23:08:01.110 回答
0

当您初始化 Calendar 对象时,它会获取当前时间,包括当前秒和毫秒。提供的代码设置了小时和分钟,但它没有设置秒和毫秒,它保持在初始化 Calendar 对象时的状态。要将秒和纳秒设置为零,请使用:

StartCalendar.set(Year, Month, DayofMonth, Hour, Minute, 0,0);
于 2020-10-08T00:49:07.163 回答