简体   繁体   English

Android - GregorianCalendar 显示错误的月份

[英]Android - GregorianCalendar displays wrong month

I tried searching the internet and found a lot of questions on StackOverlflow somewhat regarding the same topic, but couldn't find anything that I was able to understand...我尝试在互联网上搜索并在 StackOverlflow 上发现了很多关于同一主题的问题,但找不到任何我能够理解的内容......

So, I have this data class that contains a dateOfOrigin of type GregorianCalendar.所以,我有这个数据 class,其中包含 GregorianCalendar 类型的 dateOfOrigin。 Using gson I convert all json and return an Observable array with all locations.使用 gson 我转换所有 json 并返回一个包含所有位置的 Observable 数组。 Inside the json file, I added the dateOfOrigin as an object like so:在 json 文件中,我将 dateOfOrigin 添加为 object,如下所示:

{
    "id": 6,
    "name": "Fuse",
    "image": "fuse.jpg",
    "street": "Blaesstraat 208",
    "city": "Brussels Hoofdstedelijk Gewest",
    "zip": 1000,
    "date_of_origin": {"year":1994,"month":4,"dayOfMonth":16},
    "parking": true
}

And this is what my data class looks like:这就是我的数据 class 的样子:

data class Location (
    val id : Int,
    val name : String,
    val image : String,
    val street : String,
    val city : String,
    val zip : Int,
    @SerializedName("date_of_origin")
    val originDate : GregorianCalendar?,
    val parking : Boolean = true,
    var imageBitmap : Bitmap? = null
)

Whenever I try to set the dateText like this:每当我尝试像这样设置 dateText 时:

originDate?.let {
    dateText = "${it.get(Calendar.DAY_OF_MONTH)} ${it.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault())} ${it.get(Calendar.YEAR)}"

    dateText = resources.getString(R.string.origin_date, dateText)
}

It outputs 16 May 1994 instead of 16 Apr 1994它输出16 May 1994而不是16 Apr 1994

I'm not able to figure out how to fix this...我无法弄清楚如何解决这个问题......

EDIT Subtracting 1 from the month seems to fix the problem for most cases.编辑从月份中减去 1 似乎可以解决大多数情况下的问题。 Still, I have one result that is supposed to output 30 Jan 2016 but displays 1 Feb 2016 .不过,我有一个结果应该是 output 30 Jan 2016但显示1 Feb 2016

"date_of_origin": {"year":2016,"month":1,"dayOfMonth":30}

GregorianCalendar represents months with numbers in the range from 0 to 11 . GregorianCalendar表示月份,数字范围从011 This means that the number 0 is represented as January and 11 is represented as of December.这意味着数字0表示为 1 月,而11表示为 12 月。

Therefore you need to subtract 1 if your API is not using the same logic as the Java implementation.因此,如果您的 API 未使用与 Java 实现相同的逻辑,则需要减1

Updated: GregorianCalendar(2016, 1, 30) is understood as 30th of February.更新: GregorianCalendar(2016, 1, 30)理解为 2 月 30 日。 This is internally converted to 1st of March, therefore when you subtract one month from the date, you get 1st of February.这在内部转换为 3 月 1 日,因此当您从日期中减去一个月时,您将得到 2 月 1 日。 You need to create an instance of GregorianCalendar class already with the subtracted month number, ie.您需要使用减去的月份数创建一个GregorianCalendar class 实例,即。 January as 0, February as 1 and so on.一月为 0,二月为 1,依此类推。

The Answer by Hawklike is correct. Hawklike的答案是正确的。 You were tricked by the crazy month-numbering scheme employed by the GregorianCalendar class.您被GregorianCalendar class 采用的疯狂月份编号方案欺骗了。 One of many reasons to avoid this class.避免使用此 class 的众多原因之一。


tl;dr tl;博士

myGregCal  
.toZonedDateTime()                           // Convert from obsolete `GregorianCalendar` class to modern `java.time.ZonedDateTime` class.
.toLocalDate()                               // Extract the date portion, without time-of-day and without time zone.
.format(                                     // Generate text representing the value of this date-time object.
    DateTimeFormatter
    .ofLocalizedDate( FormatStyle.MEDIUM )   // Automatically localize.
    .withLocale(                             // Specify a locale for the human language and cultural norms used in localization. 
        Locale.UK
    )
)

23 Jan 2021 2021 年 1 月 23 日

Details细节

Never use GregorianCalendar .切勿使用GregorianCalendar This class is part of the date-time classes bundled with the earliest versions of Java.此 class 是与 Java 的最早版本捆绑在一起的日期时间类的一部分。 These classes were years ago supplanted by the modern java.time classes defined in JSR 310 .这些类在几年前被JSR 310中定义的现代java.time类所取代。

If you must interoperate with code not yet updated to java.time , convert.如果您必须与尚未更新到java.time的代码进行互操作,请转换。 Call new conversion methods added to the old classes.调用添加到旧类的新转换方法。

GregorianCalendar was replaced by ZonedDateTime . GregorianCalendarZonedDateTime取代。

ZonedDateTime zdt = myGregCal.toZonedDateTime() ;  // From legacy class to modern class.

Going the other direction.往另一个方向走。

ZonedDateTime zdt = ZonedDateTime.of( 2021 , Month.JANUARY , 23 , 12 , 0 , 0 , 0 , ZoneId.of( "America/Montreal" ) ) ;
GregorianCalendar myGregCal = GregorianCalendar.from( zdt ) ;

Or break that int multiple parts.或打破该int多个部分。

LocalDate ld = LocalDate.of( 2021 , Month.JANUARY , 23 ) ;
LocalTime lt = LocalTime.of( 12 , 0 ) ;
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
GregorianCalendar myGregCal = GregorianCalendar.from( zdt ) ;

Or use month number rather than Month enum for the month.或者使用月份编号而不是Month枚举。 Notice that java.time uses sane numbering, 1-12 for January-December, unlike GregorianCalendar .请注意,与GregorianCalendar不同, java.time使用合理的编号,1-12 表示一月至十二月。

LocalDate.of( 2021 , 1 , 23 )  // Same effect as Month.JANUARY. 

To generate text, use DateTimeFormatter class.要生成文本,请使用DateTimeFormatter class。 Your desired format happens to match that of localized format used in the UK.您所需的格式恰好与英国使用的本地化格式相匹配。 So let java.time automatically localize for you by calling DateTimeFormatter.ofLocalizedDate .因此,通过调用DateTimeFormatter.ofLocalizedDatejava.time自动为您本地化。

Locale locale = Locale.UK ; 
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM ).withLocale( locale ) ;
String output = zdt2.toLocalDate().format( f ) ;

See this code run live at IdeOne.com .请参阅在 IdeOne.com 上实时运行的代码

23 Jan 2021 2021 年 1 月 23 日


About java.time关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于 Java 8 及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat .这些类取代了麻烦的日期时间类,例如java.util.DateCalendarSimpleDateFormat

To learn more, see the Oracle Tutorial .要了解更多信息,请参阅Oracle 教程 And search Stack Overflow for many examples and explanations.并在 Stack Overflow 上搜索许多示例和解释。 Specification is JSR 310 .规范是JSR 310

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes.现在处于维护模式Joda-Time项目建议迁移到java.time类。

You may exchange java.time objects directly with your database.您可以直接与数据库交换java.time对象。 Use a JDBC driver compliant with JDBC 4.2 or later.使用符合JDBC 4.2或更高版本的JDBC 驱动程序 No need for strings, no need for java.sql.* classes.不需要字符串,不需要java.sql.*类。 Hibernate 5 & JPA 2.2 support java.time . Hibernate 5 & JPA 2.2 支持java.time

Where to obtain the java.time classes?从哪里获得 java.time 课程?

哪个 java.time 库与哪个版本的 Java 或 Android 一起使用的表

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM