Android API 23及以下版本上的日历集()已损坏-java.util.Calendar
我使用java.util.Calendar的set()方法查找给定星期的开始Android API 23及以下版本上的日历集()已损坏-java.util.Calendar,java,android,kotlin,android-6.0-marshmallow,java.util.calendar,Java,Android,Kotlin,Android 6.0 Marshmallow,Java.util.calendar,我使用java.util.Calendar的set()方法查找给定星期的开始 这在Android牛轧糖+(Nougat+)上非常有效,但在棉花糖以下的任何Android版本上都不起作用 我已经在物理设备和模拟器上进行了测试 我使用了调试器来验证问题是否出在日历代码上,而不是在显示日历代码时出现的问题 我使用Kotlin和Java创建了不同的最小示例,这两个示例中都存在问题 以下是Kotlin minimal示例,其中文本视图显示日期,并使用按钮将该日期增加一周: class MainActi
- 这在Android牛轧糖+(Nougat+)上非常有效,但在棉花糖以下的任何Android版本上都不起作用
- 我已经在物理设备和模拟器上进行了测试
- 我使用了调试器来验证问题是否出在日历代码上,而不是在显示日历代码时出现的问题
- 我使用Kotlin和Java创建了不同的最小示例,这两个示例中都存在问题
class MainActivity : AppCompatActivity() {
var week = 10
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Set TextView to show the date of the 10th week in 2018.
setCalendarText(week)
// Increase the week on every button click, and show the new date.
button.setOnClickListener { setCalendarText(++week) }
}
/**
* Set the text of a TextView, defined in XML, to the date of
* a given week in 2018.
*/
fun setCalendarText(week: Int) {
val cal = Calendar.getInstance().apply {
firstDayOfWeek = Calendar.MONDAY
set(Calendar.YEAR, 2018)
set(Calendar.WEEK_OF_YEAR, week)
set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 1)
}
textView.text = SimpleDateFormat("dd MMMM yyyy", Locale.UK).format(cal.time)
}
}
当按预期工作时,活动启动时,TextView设置为显示“2018年3月5日”。单击按钮时,此值将更改为连续每周的第一天
安卓棉花糖及以下产品:
- TextView的初始值设置为本周开始(2018年9月3日)
- 单击按钮时,日期不会更改
- 如果日期设置为
Calendar.SUNDAY,则日历可以正确检索当前星期的最后一天。它在其他任何星期内都不起作用
CalendarTester.test()
快速检查基本问题是否出现
tl;博士
使用向后移植到早期Android的java.time类
问题陈述:从当前日期开始,移动到上一个或同一个星期一,然后移动到标准ISO 8601的星期一,该日期基于周的年份的第10个星期,添加一周,并为结果日期生成标准ISO 8601格式的文本
org.threeten.bp.LocalDate.now( // Represent a date-only value, without time-of-day and without time zone.
ZoneId.of( "Europe/London" ) // Determining current date requires a time zone. For any given moment, the date and time vary around the globe by zone.
) // Returns a `LocalDate`. Per immutable objects pattern, any further actions generate another object rather than changing (“mutating”) this object.
.with(
TemporalAdjusters.previousOrSame( // Move to another date.
DayOfWeek.MONDAY // Specify desired day-of-week using `DayOfWeek` enum, with seven objects pre-defined for each day-of-week.
)
) // Renders another `LocalDate` object.
.with(
IsoFields.WEEK_OF_WEEK_BASED_YEAR ,
10
)
.plusWeeks( 1 )
.toString()
2018-03-12
简化问题
在追踪神秘或有缺陷的行为时,只需将编程降至再现问题所需的最低限度。在本例中,去掉假定不相关的GUI代码,将重点放在日期时间类上
在科学实验中,控制各种变量。在这种情况下,时区和地区都会影响日历的行为。首先,在日历
内的一周的定义因地区
而异。因此,通过硬编码明确指定这些方面
设置一个特定的日期和时间,因为不同区域中不同日期的不同时间可能会影响行为
Calendar
是一个具有各种实现的超类。如果您需要的是gregoriacalendar
,请在调试时显式使用它
因此,尝试在您的工具场景中运行以下内容来解决您的问题
TimeZone tz = TimeZone.getTimeZone( "America/Los_Angeles" );
Locale locale = Locale.US;
GregorianCalendar gc = new GregorianCalendar( tz , locale );
gc.set( 2018 , 9- 1 , 3 , 0 , 0 , 0 ); // Subtract 1 from month number to account for nonsensical month numbering used by this terrible class.
gc.set( Calendar.MILLISECOND , 0 ); // Clear fractional second.
System.out.println( "gc (original): " + gc.toString() );
System.out.println( gc.toZonedDateTime() + "\n" ); // Generate a more readable string, using modern java.time classes. Delete this line if running on Android <26.
int week = 10;
gc.set( Calendar.WEEK_OF_YEAR , week );
System.out.println( "gc (week=10): " + gc.toString() );
System.out.println( gc.toZonedDateTime() + "\n" );
int weekAfter = ( week + 1 );
gc.set( Calendar.WEEK_OF_YEAR , weekAfter );
System.out.println( "gc (weekAfter): " + gc.toString() );
System.out.println( gc.toZonedDateTime() + "\n" );
如果要使用JVM的当前默认时区,请请求它并将其作为参数传递。如果省略,则隐式应用JVM的当前默认值。最好是显式的,因为JVM中任何应用程序的任何线程中的任何代码都可能在运行时的任何时刻更改默认值
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
或者指定一个日期。你可以用一个数字来设置月份,1-12月的数字为1-12
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
或者,最好使用预定义的枚举对象,一年中每个月一个。提示:在整个代码库中使用这些Month
对象,而不仅仅是一个整数,这样可以使代码更加自我记录,确保有效值,并提供更高的可用性
TemporalAdjuster
要移动到上一个星期一,或者如果已经是星期一,则停留在该日期,请使用临时调整器
类中提供的临时调整器
实现。使用DayOfWeek
enum指定所需的星期几
LocalDate monday = ld.with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) ) ;
IsoFields
java.time类在几周内的支持有限。将类与其常量WEEK\u OF theu WEEK\u BASED\u YEAR
和WEEK\u BASED\u YEAR
一起使用
LocalDate mondayOfWeekTen = monday.with( IsoFields.WEEK_OF_WEEK_BASED_YEAR , 10 ) ;
ISO 8601
ISO 8601标准定义了许多有用的实用格式,用于将日期时间值表示为文本。这包括几个星期。让我们生成这样的文本作为输出
String weekLaterOutput =
weekLater
.get( IsoFields.WEEK_BASED_YEAR )
+ "-W"
+ String.format( "%02d" , weekLater.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) )
+ "-"
+ weekLater.getDayOfWeek().getValue()
; // Generate standard ISO 8601 output. Ex: 2018-W11-1
转储到控制台
System.out.println("ld.toString(): " + ld);
System.out.println("monday.toString(): " +monday);
System.out.println("weekLater.toString(): " + weekLater);
System.out.println( "weekLaterOutput: " + weekLaterOutput ) ;
跑步的时候
ld.toString():2018-09-03
星期一toString():2018-09-03
weekLater.toString():2018-03-12
周后产量:2018-W11-1
为java(不是Android)的提示:如果在几个星期内做了很多工作,考虑添加库来访问它的代码>年份类。p>
关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,& 该项目现已启动,建议迁移到类 要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是 您可以直接与数据库交换java.time对象。使用兼容的或更高版本。不需要字符串,也不需要
java.sql.*
类
从哪里获得java.time类
- 、和更高版本-标准Java API的一部分,带有捆绑实现。
- Java9添加了一些次要功能和修复
- 及
- 大多数java.time功能都在中向后移植到Java6和Java7
-
- 更高版本的Android捆绑包实现了java.time类
- 对于早期的Android(您是否尝试过使用GregoriaCalendar?是否尝试过将日期操作代码与GUI代码分离?只需将值转储到控制台以验证值。@BasilBourque,我使用调试器将根问题标识为日历时间。(我原本以为这是安卓系统中TextSwitcher的一个bug。)如果您在没有GUI的情况下编写并发布一段仅控制台的代码,其他人将更容易验证您的结果。请参阅:@TheRealChx101 Joda Time项目处于维护模式,并建议迁移到java.Time类。以三个十个后端口的形式后端口到java 6/7,并进一步调整
LocalDate mondayOfWeekTen = monday.with( IsoFields.WEEK_OF_WEEK_BASED_YEAR , 10 ) ;
String weekLaterOutput = weekLater .get( IsoFields.WEEK_BASED_YEAR ) + "-W" + String.format( "%02d" , weekLater.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ) + "-" + weekLater.getDayOfWeek().getValue() ; // Generate standard ISO 8601 output. Ex: 2018-W11-1
System.out.println("ld.toString(): " + ld); System.out.println("monday.toString(): " +monday); System.out.println("weekLater.toString(): " + weekLater); System.out.println( "weekLaterOutput: " + weekLaterOutput ) ;