日历和数组列表:如何正确分配日期?

Calendar and array list : how do I assign the date right?

下面的 lastDay 变量并不总是包含列表的 i+1。不知道为什么。 我正在介绍 Java 8 的日期。但我仍然想知道出了什么问题...... 彼得(非常新手)

// organize the intervals and split them into the years
        ArrayList<intervall> tmpIntervallList = new ArrayList<intervall>();
        Calendar lastDay = Calendar.getInstance();

        for (i = 0; i < deliveryList.size() - 1; i++) {

            Log.d(TAG, "my log comments: Intervallanfang " +
                    deliveryList.get(i).getDatumasString() +" nächstes: " + deliveryList.get(i+1).getDatumasString());
            //Beginning of the next intervall -1 is the last day of the Intervall before.
            lastDay.set(deliveryList.get(i+1).getYear(),
                    deliveryList.get(i+1).getMonth(),
                    deliveryList.get(i+1).getDay());

            //debugging
            String tmp1String = String.format("%d/%d/%d", lastDay.get(Calendar.DAY_OF_MONTH),
                    lastDay.get(Calendar.MONTH) + 1,
                    lastDay.get(Calendar.YEAR));
            Log.d(TAG, "my log comments: tmp lastday " + tmp1String );

            lastDay.add(Calendar.DATE, -1);

            //debugging
            String tmpString = String.format("%d/%d/%d", lastDay.get(Calendar.DAY_OF_MONTH),
                    lastDay.get(Calendar.MONTH) + 1,
                    lastDay.get(Calendar.YEAR));
            Log.d(TAG, "my log comments: ende intervall " + tmpString);

            intervall tmp2intervall = new intervall(deliveryList.get(i).getAmountFilled(),
                    deliveryList.get(i).getYear(),
                    deliveryList.get(i).getMonth(),
                    deliveryList.get(i).getDay(),
                    lastDay.get(Calendar.YEAR),
                    lastDay.get(Calendar.MONTH),
                    lastDay.get(Calendar.DAY_OF_MONTH));
            tmpIntervallList.add(tmp2intervall);
        }

结果是

我的日志评论:Intervallanfang 01/01/2018 nächstes:01/02/2018

我的日志评论:tmp lastday 1/1/2018

我的日志评论:结束时间 31/12/2017

我的日志评论:Intervallanfang 01/02/2018 nächstes:01/06/2018

我的日志评论:tmp lastday 1/1/2018

我的日志评论:结束时间 31/12/2017

我的日志评论:Intervallanfang 01/06/2018 nächstes:01/01/2019

我的日志评论:tmp lastday 1/1/2019

我的日志评论:结束时间 31/12/2018

我的日志评论:Intervallanfang 01/01/2019 nächstes:01/01/2020

我的日志评论:tmp lastday 1/1/2020

我的日志评论:结束时间 31/12/2019

我的日志评论:Intervallanfang 01/01/2020 nächstes:01/06/2020

我的日志评论:tmp lastday 1/1/2020

我的日志评论:结束时间 31/12/2019

我的日志评论:Intervallanfang 01/06/2020 nächstes:02/01/2021

我的日志评论:tmp 最后一天 2/1/2021

我的日志评论:结束时间 1/1/2021

根据要求提供更多源代码

    public  intervall(int amountFilled, int yearBegin, int monthBegin, int 
               dayBegin, int yearEnd, int monthEnd, int dayEnd) {
                   begin = Calendar.getInstance();
                   end = Calendar.getInstance();
                   this.setIntervall( yearBegin, monthBegin, dayBegin, 
                          yearEnd, monthEnd, dayEnd);
                   this.amountFilled = amountFilled;

.....

    public void setIntervall(int amountFilled, int yearBegin, int 
    monthBegin, int dayBegin, int yearEnd, int monthEnd, int dayEnd){
       this.begin.set(yearBegin, monthBegin, dayBegin);
       this.end.set(yearEnd, monthEnd, dayEnd);

.......

避免遗留日期时间 classes

您使用的是可怕的日期时间 classes,它在几年前被 JSR 中定义的现代 java.time classes 取代310. 永远不要使用 DateCalendar

java.time

获取今天的日期。需要时区。对于任何给定时刻,全球各地的日期因时区而异。

ZoneId z = ZoneId.of( "Europe/Berlin" ) ;
LocalDate today = LocalDate.now( z ) ;

生成标准 ISO 8601 格式 YYYY-MM-DD 的字符串。请注意 java.time 使用合理的编号,因此月份为 1-12,不需要 + 1

String output = today.toString() ;

要增加或减少该日期的天数,请调用 plusDaysminusDaysjava.time class 使用不可变对象。因此,我们没有改变原始对象,而是得到了一个全新的 LocalDate 对象。

LocalDate yesterday = today.minusDays( 1 ) ;
LocalDate tomorrow = today.plusDays( 1 ) ;

三十加

我建议您添加 ThreeTen-Extra library to your project. This gives you access to the LocalDateRange class 来表示一对 LocalDate 对象。

LocalDateRange dateRange = LocalDateRange.of( today , today.plusWeeks( 1 ) ) ;

我猜这个 class 可以用来代替你自制的 intervall class。顺便说一下,Java中的class名称应该有一个首字母大写,Intervall class名称,intervall实例变量名称。

这个LocalDateRangeclass有几种比较方法,比如邻接、包含、重叠等

boolean containsJan23 = dateRange.contains( LocalDate.of( 2020 , Month.JANUARY , 23 ) ) ;

this does not explain the strange behavior. As written I am in the course of introducing the Date from Java 8 but still I would like to understand.

让我们先检查日志输出的前两行:

my log comments: Intervallanfang 01/01/2018 nächstes: 01/02/2018
my log comments: tmp lastday 1/1/2018

(对于不懂德文的读者:第一行表示interval start 01/01/2018 next: 01/02/2018.)

日期 nächstestmp lastday 来自您 deliveryList 的同一个元素,即 deliveryList.get(i+1)01/02/2018 来自 getDatumasString()1/1/2018 来自 getYear()getMonth()getDay()。在输出中,您已正确地将 1 添加到月份编号,因为月份是从 0 而不是 1 疯狂编号的(可能是令人困惑的 GregorianCalendar class 的特征)。因此,当这两个日期不一致时,问题一定出在 class 这些交货所属的任何地方。根据您提供的信息,我不知道 class 是什么,更不知道 class 中的问题是什么(我在评论中鼓励您创建一个原因是有原因的最小的、可重现的例子)。

不过有一个模式:当我们读取您的整个日志输出时,nächstestmp lastday 总是在年份和月份日期上一致(即使在最后一次迭代中,月为 2 更改)。并且 tmp lastday 始终将月份指定为 1(一月),无论它在 nächstes(2、6 或 1)中是什么。因此,似乎 getMonth() 中存在一个错误,导致它总是 return 0(一月),而不管对象中有什么。

为什么 getMonth() 总是 return 一月,这是我的猜测,但我敢于开始猜测。它可能来自使用 SimpleDateFormat 解析日期字符串,这是一个臭名昭著的 class 麻烦制造者。有两个典型的错误经常导致它 return 一月的日期,即使输入字符串在不同的月份:

  1. 在格式模式字符串中使用大写 Y 而不是小写 y 作为年份。例如参见 [​​=34=].
  2. 在您的情况下更有可能使用小写 m 作为月份。例如参见 [​​=35=]

如果这两个结果中的任何一个符合您的问题,我几乎可以向您保证一件事:java.time 不会发生这种情况,现代 Java 日期和时间 API Basil Bourque 在另一个答案中正确地认可了这一点。 java.time 在需要开始调试之前很久就可以更好地捕获此类错误。