为什么使用相同的时区获得不同的localDate

问题描述 投票:2回答:2
java.sql.Date date = java.sql.Date.valueOf("1900-01-01");
org.joda.time.LocalDate localDate = new org.joda.time.LocalDate(date);

基于上面的代码,我做了一些测试如下:

  • 问题#1为什么我会使用相同的时区获得不同的localDate对象?

如果我将当地时区更改为UTC+8 Singapore Timezone,将获得1899-12-31

如果我将当地时区更改为UTC+8 China Timezone,将获得1900-01-01

  • 问题#2为什么我会使用不同的时区获得相同的时间?

如果我将当地时区更改为UTC-8 America/Los_Angeles Timezone,将获得1900-01-01

如果我将当地时区更改为UTC+8 China Timezone,将获得1900-01-01

有人可以帮忙澄清一下吗?它有点困惑。

java date datetime jodatime java-time
2个回答
3
投票

在1900年,Singpore's抵消是UTC +6:55:25,所以当你在新加坡时区创建日期1900-01-01时,它应该是1899-12-31T17:04:35Z[UTC]如下:

java.time.ZonedDateTime localDateTime = ZonedDateTime.of(1900, 01, 01, 0,
            0, 0, 0, ZoneId.of("Singapore"));

System.out.println(localDateTime.withZoneSameInstant(ZoneId.of("UTC")));
// 1899-12-31T17:04:35Z[UTC]

但是,当你使用java.sql.Date时,它使用错误的偏移量UTC +08:00

TimeZone.setDefault(TimeZone.getTimeZone("Singapore"));
java.sql.Date date = java.sql.Date.valueOf("1900-01-01");

java.time.Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println(instant);   // 1899-12-31T16:00:00Z

当你用这个错误的值创建org.joda.time.LocalDateTime时,Joda使用UTC +6:55:25作为偏移量,导致日期时间1899-12-31T16:00:00 + 6:55:25

org.joda.time.LocalDateTime singaporeDateTime = new org.joda.time.LocalDateTime(date);
System.out.println(singaporeDateTime);  // 1899-12-31T22:55:25.000 

您可以使用类似的方法来检查上海和洛杉矶的结果,重点是,避免使用java.sql.Date和其他已弃用的日期时间相关的类。如果您使用的是java8或更高版本,请使用java.time


1
投票

tl;dr

java.time.LocalDate
.of( 
    1900 , 
    Month.JANUARY , 
    1 
) ;

Avoid legacy date-time classes

你正在使用一个可怕的旧类java.sql.Date,设计糟糕,有缺陷的黑客。它的问题之一是它假装代表一个仅限日期的值,但实际上保持一个时间。它甚至可以在内部保持一个时区,但没有吸气剂或二传手。永远不要使用这门课。几年前由java.time.LocalDate类取代。

Joda-Time项目也被java.time类所取代。该项目处于维护模式,接收更新和关键错误修复,但没有新功能。该项目建议迁移到java.time类。迁移很容易,因为他们有着相似的概念,两者都是由同一个人Stephen Colebourne领导的。

java.time.LocalDate

如果您想要一个没有时间且没有时区的仅限日期的值,请使用java.time.LocalDate。你问题中提出的所有问题都会消失。

java.time.LocalDate ld = LocalDate.of( 1900 , Month.JANUARY , 1 ) ;  // Simply a year-month-day date, no problems, no issues, no confusion. 

ld.toString():1900-01-01

另请注意,java.time使用合理的编号,其中2018表示2018年,1-12表示1月至12月。这与麻烦的遗产类形成鲜明对比。


About java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,如java.util.DateCalendarSimpleDateFormat

现在在Joda-Timemaintenance mode项目建议迁移到java.time班。

要了解更多信息,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规格是JSR 310

您可以直接与数据库交换java.time对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目是未来可能添加到java.time的试验场。你可能会在这里找到一些有用的类,如IntervalYearWeekYearQuartermore

© www.soinside.com 2019 - 2024. All rights reserved.