We've got some strange behavior in Android 7 (API 24/25) using Calendar
.
我们在Android 7 (API 24/25)中使用日历有一些奇怪的行为。
Given this fairly simple code:
考虑到这个相当简单的代码:
SimpleDateFormat month_date = new SimpleDateFormat("dd.MM.YYYY");
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"), Locale.GERMANY);
cal.setFirstDayOfWeek(Calendar.MONDAY);
for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) {
Calendar start = ((Calendar) cal.clone());
start.set(2017, month, 1);
Calendar end = ((Calendar) start.clone());
end.set(Calendar.DAY_OF_MONTH, end.getActualMaximum(Calendar.DAY_OF_MONTH));
Log.d("CAL", "\n Date Start: " + month_date.format(start.getTime()) + " " +
" WEEK_OF_MONTH: " + start.get(Calendar.WEEK_OF_MONTH)
);
Log.d("CAL", "\n Date End: " + month_date.format(end.getTime()) +
" WEEK_OF_MONTH: " + end.get(Calendar.WEEK_OF_MONTH)
);
}
Running on Android 4.0x, 5.x and 6.x showing the right value for WEEK_OF_MONTH
:
运行在4。0x, 5。x和6。x显示的值为WEEK_OF_MONTH:
Date Start: 01.01.2016 WEEK_OF_MONTH: 1
Date End: 31.01.2017 WEEK_OF_MONTH: 6
Date Start: 01.02.2017 WEEK_OF_MONTH: 1
Date End: 28.02.2017 WEEK_OF_MONTH: 5
Date Start: 01.03.2017 WEEK_OF_MONTH: 1
Date End: 31.03.2017 WEEK_OF_MONTH: 5
Date Start: 01.04.2017 WEEK_OF_MONTH: 1
Date End: 30.04.2017 WEEK_OF_MONTH: 5
Date Start: 01.05.2017 WEEK_OF_MONTH: 1
Date End: 31.05.2017 WEEK_OF_MONTH: 5
Date Start: 01.06.2017 WEEK_OF_MONTH: 1
Date End: 30.06.2017 WEEK_OF_MONTH: 5
Date Start: 01.07.2017 WEEK_OF_MONTH: 1
Date End: 31.07.2017 WEEK_OF_MONTH: 6
Date Start: 01.08.2017 WEEK_OF_MONTH: 1
Date End: 31.08.2017 WEEK_OF_MONTH: 5
Date Start: 01.09.2017 WEEK_OF_MONTH: 1
Date End: 30.09.2017 WEEK_OF_MONTH: 5
Date Start: 01.10.2017 WEEK_OF_MONTH: 1
Date End: 31.10.2017 WEEK_OF_MONTH: 6
Date Start: 01.11.2017 WEEK_OF_MONTH: 1
Date End: 30.11.2017 WEEK_OF_MONTH: 5
Date Start: 01.12.2017 WEEK_OF_MONTH: 1
Date End: 31.12.2017 WEEK_OF_MONTH: 5
Running on Android 7.x broken WEEK_OF_MONTH
:
运行在Android 7。x破WEEK_OF_MONTH:
Date Start: 01.01.2016 WEEK_OF_MONTH: 0
Date End: 31.01.2017 WEEK_OF_MONTH: 5
Date Start: 01.02.2017 WEEK_OF_MONTH: 1
Date End: 28.02.2017 WEEK_OF_MONTH: 5
Date Start: 01.03.2017 WEEK_OF_MONTH: 1
Date End: 31.03.2017 WEEK_OF_MONTH: 5
Date Start: 01.04.2017 WEEK_OF_MONTH: 0
Date End: 30.04.2017 WEEK_OF_MONTH: 4
Date Start: 01.05.2017 WEEK_OF_MONTH: 1
Date End: 31.05.2017 WEEK_OF_MONTH: 5
Date Start: 01.06.2017 WEEK_OF_MONTH: 1
Date End: 30.06.2017 WEEK_OF_MONTH: 5
Date Start: 01.07.2017 WEEK_OF_MONTH: 0
Date End: 31.07.2017 WEEK_OF_MONTH: 5
Date Start: 01.08.2017 WEEK_OF_MONTH: 1
Date End: 31.08.2017 WEEK_OF_MONTH: 5
Date Start: 01.09.2017 WEEK_OF_MONTH: 0
Date End: 30.09.2017 WEEK_OF_MONTH: 4
Date Start: 01.10.2017 WEEK_OF_MONTH: 0
Date End: 31.10.2017 WEEK_OF_MONTH: 5
Date Start: 01.11.2017 WEEK_OF_MONTH: 1
Date End: 30.11.2017 WEEK_OF_MONTH: 5
Date Start: 01.12.2017 WEEK_OF_MONTH: 0
Date End: 31.12.2017 WEEK_OF_MONTH: 4
We couldn't find any documented changes for Calendar
in API 24.
在API 24中,我们找不到任何文档化的日历更改。
Any clue how to solve this issue?
你知道怎么解决这个问题吗?
We already implemented our own method for WEEK_OF_MONTH
returning the same values as Android 6.x but by the looks of it set(WEEK_OF_MONTH)
is also broken. Rewriting the code using Joda is not an option.
我们已经在WEEK_OF_MONTH中实现了我们自己的方法,返回与Android 6相同的值。但它的外观(WEEK_OF_MONTH)也被打破了。使用Joda重写代码不是一个选项。
1 个解决方案
#1
0
You can use the setMinimalDaysInFirstWeek()
method to change how the weeks are counted:
可以使用setMinimalDaysInFirstWeek()方法更改周的计数方式:
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"), Locale.GERMANY);
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(1);
This will produce the correct values for week of month.
这将产生一个月的正确值。
You told that rewriting the code with Joda-Time is not an option, but what about another API?
您告诉过使用Joda-Time重写代码不是一个选项,但是另一个API呢?
In Android you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes, together with the ThreeTenABP (more on how to use it here).
在Android中,您可以使用ThreeTen Backport,这是Java 8的新日期/时间类的一个很好的Backport,以及ThreeTenABP(更多关于如何在这里使用它的信息)。
BTW, Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. Even in joda's website it says: "Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".
顺便说一句,Joda-Time处于维护模式,正在被新的api所取代,所以我不建议使用它启动新的项目。甚至在joda的网站上也说:“注意,joda - time被认为是一个很大程度上“完成”的项目。没有重大的改进计划。如果使用Java SE 8,请迁移到Java。时间(jsr - 310)。
The classes below are under the org.threeten.bp
package. The code will be like this:
下面的课程是在课程下面。英国石油(bp)包。代码是这样的:
import java.util.Locale;
import org.threeten.bp.DayOfWeek;
import org.threeten.bp.LocalDate;
import org.threeten.bp.Month;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.DateTimeFormatterBuilder;
import org.threeten.bp.temporal.TemporalAdjusters;
import org.threeten.bp.temporal.WeekFields;
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// day and month
.appendPattern("dd.MM.")
// week based year (equivalent to YYYY in SimpleDateFormat)
.appendValue(WeekFields.ISO.weekBasedYear())
// create formatter
.toFormatter(Locale.GERMANY);
// week starting at monday, consider week=1 even if it has 1 day (default is 4)
WeekFields wf = WeekFields.of(DayOfWeek.MONDAY, 1);
for (Month month : Month.values()) {
LocalDate start = LocalDate.of(2017, month, 1);
LocalDate end = start.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("Date Start: " + fmt.format(start) + " " + " WEEK_OF_MONTH: " + start.get(wf.weekOfMonth()));
System.out.println("Date End: " + fmt.format(end) + " WEEK_OF_MONTH: " + end.get(wf.weekOfMonth()));
}
The output will be:
的输出将会是:
Date Start: 01.01.2016 WEEK_OF_MONTH: 1
Date End: 31.01.2017 WEEK_OF_MONTH: 6
Date Start: 01.02.2017 WEEK_OF_MONTH: 1
Date End: 28.02.2017 WEEK_OF_MONTH: 5
Date Start: 01.03.2017 WEEK_OF_MONTH: 1
Date End: 31.03.2017 WEEK_OF_MONTH: 5
Date Start: 01.04.2017 WEEK_OF_MONTH: 1
Date End: 30.04.2017 WEEK_OF_MONTH: 5
Date Start: 01.05.2017 WEEK_OF_MONTH: 1
Date End: 31.05.2017 WEEK_OF_MONTH: 5
Date Start: 01.06.2017 WEEK_OF_MONTH: 1
Date End: 30.06.2017 WEEK_OF_MONTH: 5
Date Start: 01.07.2017 WEEK_OF_MONTH: 1
Date End: 31.07.2017 WEEK_OF_MONTH: 6
Date Start: 01.08.2017 WEEK_OF_MONTH: 1
Date End: 31.08.2017 WEEK_OF_MONTH: 5
Date Start: 01.09.2017 WEEK_OF_MONTH: 1
Date End: 30.09.2017 WEEK_OF_MONTH: 5
Date Start: 01.10.2017 WEEK_OF_MONTH: 1
Date End: 31.10.2017 WEEK_OF_MONTH: 6
Date Start: 01.11.2017 WEEK_OF_MONTH: 1
Date End: 30.11.2017 WEEK_OF_MONTH: 5
Date Start: 01.12.2017 WEEK_OF_MONTH: 1
Date End: 31.12.2017 WEEK_OF_MONTH: 5
#1
0
You can use the setMinimalDaysInFirstWeek()
method to change how the weeks are counted:
可以使用setMinimalDaysInFirstWeek()方法更改周的计数方式:
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"), Locale.GERMANY);
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(1);
This will produce the correct values for week of month.
这将产生一个月的正确值。
You told that rewriting the code with Joda-Time is not an option, but what about another API?
您告诉过使用Joda-Time重写代码不是一个选项,但是另一个API呢?
In Android you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes, together with the ThreeTenABP (more on how to use it here).
在Android中,您可以使用ThreeTen Backport,这是Java 8的新日期/时间类的一个很好的Backport,以及ThreeTenABP(更多关于如何在这里使用它的信息)。
BTW, Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. Even in joda's website it says: "Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".
顺便说一句,Joda-Time处于维护模式,正在被新的api所取代,所以我不建议使用它启动新的项目。甚至在joda的网站上也说:“注意,joda - time被认为是一个很大程度上“完成”的项目。没有重大的改进计划。如果使用Java SE 8,请迁移到Java。时间(jsr - 310)。
The classes below are under the org.threeten.bp
package. The code will be like this:
下面的课程是在课程下面。英国石油(bp)包。代码是这样的:
import java.util.Locale;
import org.threeten.bp.DayOfWeek;
import org.threeten.bp.LocalDate;
import org.threeten.bp.Month;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.DateTimeFormatterBuilder;
import org.threeten.bp.temporal.TemporalAdjusters;
import org.threeten.bp.temporal.WeekFields;
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// day and month
.appendPattern("dd.MM.")
// week based year (equivalent to YYYY in SimpleDateFormat)
.appendValue(WeekFields.ISO.weekBasedYear())
// create formatter
.toFormatter(Locale.GERMANY);
// week starting at monday, consider week=1 even if it has 1 day (default is 4)
WeekFields wf = WeekFields.of(DayOfWeek.MONDAY, 1);
for (Month month : Month.values()) {
LocalDate start = LocalDate.of(2017, month, 1);
LocalDate end = start.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("Date Start: " + fmt.format(start) + " " + " WEEK_OF_MONTH: " + start.get(wf.weekOfMonth()));
System.out.println("Date End: " + fmt.format(end) + " WEEK_OF_MONTH: " + end.get(wf.weekOfMonth()));
}
The output will be:
的输出将会是:
Date Start: 01.01.2016 WEEK_OF_MONTH: 1
Date End: 31.01.2017 WEEK_OF_MONTH: 6
Date Start: 01.02.2017 WEEK_OF_MONTH: 1
Date End: 28.02.2017 WEEK_OF_MONTH: 5
Date Start: 01.03.2017 WEEK_OF_MONTH: 1
Date End: 31.03.2017 WEEK_OF_MONTH: 5
Date Start: 01.04.2017 WEEK_OF_MONTH: 1
Date End: 30.04.2017 WEEK_OF_MONTH: 5
Date Start: 01.05.2017 WEEK_OF_MONTH: 1
Date End: 31.05.2017 WEEK_OF_MONTH: 5
Date Start: 01.06.2017 WEEK_OF_MONTH: 1
Date End: 30.06.2017 WEEK_OF_MONTH: 5
Date Start: 01.07.2017 WEEK_OF_MONTH: 1
Date End: 31.07.2017 WEEK_OF_MONTH: 6
Date Start: 01.08.2017 WEEK_OF_MONTH: 1
Date End: 31.08.2017 WEEK_OF_MONTH: 5
Date Start: 01.09.2017 WEEK_OF_MONTH: 1
Date End: 30.09.2017 WEEK_OF_MONTH: 5
Date Start: 01.10.2017 WEEK_OF_MONTH: 1
Date End: 31.10.2017 WEEK_OF_MONTH: 6
Date Start: 01.11.2017 WEEK_OF_MONTH: 1
Date End: 30.11.2017 WEEK_OF_MONTH: 5
Date Start: 01.12.2017 WEEK_OF_MONTH: 1
Date End: 31.12.2017 WEEK_OF_MONTH: 5