tl;博士
Android 的 Calendar.Day_Of_Month 是从零开始的吗?
没有。
我得到“2018-01-02”……
…报告日期为“2018-01-01”
您的第 1 次与第 2 次问题与其他问题有关:时区。
使用 java.time 代替那些非常麻烦的遗留类。
OffsetDateTime.of(
LocalDate.of( 2018 , Month.JANUARY , 1 ) ,
LocalTime.NOON ,
ZoneOffset.UTC
)
.toString(): 2018-01-01T12:00Z
.format(
DateTimeFormatter.ISO_LOCAL_DATE
)
2018-01-01
或者覆盖区域/偏移量。
.format(
DateTimeFormatter.ISO_LOCAL_DATE
.withZone( ZoneId.of( "Pacific/Kiritimati" ) ) // Using zone 14 hours ahead of UTC. So noon UTC is “tomorrow” in Kiribati.
)
2018-01-02
时区
如果在 America/Los_Angeles 时区 16:00 运行您的代码,我会得到 2018-01-01。但是,如果我将您的代码更改为将小时设置为23 而不是12,我会得到2018-01-02。
所以有一个关于时区的问题。什么是“今天”和什么是“明天”取决于您所在的时区。
与其进一步玷污我的大脑,让我提出真正的解决方案:停止使用这些糟糕的日期时间类。
java.time
那些旧的日期时间类(Date、Calendar、SimpleDateFormat)在几年前被现代的 java.time 类所取代。
显然你想在年初的中午。这是如何做。请注意合理的编号:1 月至 12 月的月份为 1-12(与旧课程不同),倒数第二天的月份为 1-31(如旧课程)。
获取日期。
LocalDate ld = LocalDate.of( 2018 , 1 , 1 ) ; // January 1, 2018.
或者使用更易读的Month枚举。
LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 1 ) ; // January 1, 2018.
生成一个以标准 ISO 8601 格式表示该值的字符串。
ld.toString(): 2018-01-01
获取一天中的时间,中午。 LocalTime 类有一个常量。
LocalTime lt = LocalTime.NOON ;
指定与 UTC 的偏移量为零,即 UTC 本身。 ZoneOffset 类有一个常量。
ZoneOffset offset = ZoneOffset.UTC ;
组合以将时刻表示为OffsetDateTime 对象。
OffsetDateTime odt = OffsetDateTime.of( ld , lt , offset ) ;
生成一个以标准 ISO 8601 格式表示该值的字符串。
odt.toString(): 2018-01-01T12:00Z
如果您只需要日期部分,请提取 LocalDate。
LocalDate ld = odt.toLocalDate() ;
或者通过定义 DateTimeFormatter 仅使用日期部分打印字符串。
DateTimeFormatter f = DateTimeFormatter.ISO_LOCAL_DATE ;
String outputOdtDateOnly = odt.format( f ) ;
2018-01-01
默认情况下,DateTimeFormatter 对象使用新字符串表示的对象的偏移量或区域。您可以选择覆盖该偏移量/区域。让我们试试看。
ZoneId z = ZoneId.of( "Pacific/Kiritimati" ); // Most eastern (earliest) time zone is in Kiribati. https://en.wikipedia.org/wiki/Kiribati
DateTimeFormatter fKiritimati = f.withZone( z );
String outputOdtDateOnlyInKiribati = odt.format( fKiritimati );
请注意,我们更改了格式化程序对象,而不是数据对象,而不是OffsetDateTime 对象。我们在新的格式化程序对象中添加了一个时区,之前的格式化程序保存了null、as documented。并注意 java.time 如何使用immutable objects,其中一个新对象是根据原始值实例化的,而不是更改(“变异”)原始对象。因此,我们在第一个对象的基础上得到了第二个 DateTimeFormatter 对象,但添加了我们指定的覆盖区域。
让我们看看我们得到了什么。
System.out.println( outputOdtDateOnlyInKiribati );
2018-01-02
惊喜!回到您的问题中的问题。基里巴斯部分地区比世界标准时间早 14 小时。因此,当它是 UTC 中午时,同时在 Pacific/Kiritimati 区域中是 14 小时后,因此“明天”是第二个。
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?