gpt4 book ai didi

java - Java将字符串转换为日期,即使提供了浏览器时区,也可以减少一天的时间

转载 作者:行者123 更新时间:2023-12-02 02:13:04 27 4
gpt4 key购买 nike

我正在从Angular应用中以字符串形式将日期发送到服务器,然后转换为java Date对象以存储在数据库中。

还从UI发送timeZoneOffset以在转换时使用客户端的时区。 (谷歌搜索后,我发现这种方法可根据用户位置获得正确的结果)

编写以下代码进行转换:

public static void main(String args[]) throws ParseException {
String inputDate = "04/05/2018"; // This date coming from UI
int timeZoneOffset = -330; // This offset coming from UI
// (new Date().getTimeZoneOffset())
getDate(inputDate, timeZoneOffset);
}

public static Date getDate(String inputDate, int timeZoneOffset)
throws ParseException {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(-timeZoneOffset * 60);
System.out.println("Default time zone: " + TimeZone.getDefault().getID());
TimeZone timeZone = TimeZone.getTimeZone(zoneOffset);
System.out.println("Time zone from offset: " + timeZone.getID());
dateFormat.setTimeZone(timeZone);
Date date = dateFormat.parse(inputDate);
System.out.println("Converted date: " + date);
return date;
}


预期产量:


  默认时区:美国/纽约
      偏移时区:GMT + 05:30
      转换日期:IST 2018年4月5日00:00:00


服务器中的实际结果:


  默认时区:美国/纽约
      偏移时区:GMT + 05:30
      转换日期:2018年4月4日星期三14:30:00


为什么即使设置了用户时区,日期也减少到一天?我是与日期和时间相关的概念的新手,我在Google上搜索了几次都找不到答案,请有人帮忙解决这个问题。

提前致谢

最佳答案

Answer by Godfrey是正确的。

tl; dr

LocalDate.parse( 
"04/05/2018" ,
DateTimeFormatter.ofPattern( "MM/dd/uuuu" )
)
.atStartOfDay(
ZoneId.of( "Asia/Kolkata" )
)
.toString()



  2018-04-05T00:00 + 05:30 [亚洲/加尔各答]


要存储在数据库中,请使用UTC。

当印度开始新的一天时,UTC的日期仍然是“昨天”,因此是4月4日而不是4月5日。同一时刻,时间轴上的同一点,不同的时钟时间。

LocalDate.parse( 
"04/05/2018" ,
DateTimeFormatter.ofPattern( "MM/dd/uuuu" )
)
.atStartOfDay(
ZoneId.of( "Asia/Kolkata" )
)
.toInstant()



  2018-04-04T18:30:00Z


java.time

您正在使用可怕的旧日期时间类,这些类早已被证明设计不良,令人困惑和麻烦。现在,它们已被java.time类取代。

完全避免使用旧的日期时间类

ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(-timeZoneOffset * 60);

TimeZone timeZone = TimeZone.getTimeZone(zoneOffset);


您正在将现代类( ZoneOffset)与麻烦的旧类( TimeZone)混合在一起。不要将现代类与遗留类混合使用。忘记所有有关旧类的信息,包括 DateCalendarSimpleDateFormat。 java.time类旨在完全取代旧类。

代替 TimeZone,使用 ZoneId(和 ZoneOffset)。

LocalDate

将您的输入字符串解析为 LocalDateLocalDate类表示没有日期和时区的仅日期值。

String input = "04/05/2018" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
LocalDate ld = LocalDate.parse( input , f ) ;


偏移量与时区


  int timeZoneOffset = -330;


offset-from-UTC不是时区。偏移量只是距UTC数小时,数分钟和数秒的偏移量。您选择的变量名表明在这一点上可能会造成混淆。

ZoneOffset offset = ZoneOffset.of( -3 , 30 ) ;  


time zone是特定区域的人们使用的偏移量的过去,现在和将来的历史记录。因此,时区始终优于偏移量。

continent/region的格式指定 proper time zone name,例如 America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母的缩写,例如 ESTIST,因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;  // India time zone. Currently uses offset of +05:30 (five and a half hours ahead of UTC). 


一天的第一刻

您似乎打算将该日期作为该区域的第一刻。让java.time确定第一天。不要假定时间为00:00:00。在某些日期的某些区域中,一天可能在其他时间(例如01:00:00)开始。

ZonedDateTime zdt = ld.atStartOfDay( z ) ;  // Determine the first moment of the day on this date in this zone. Not always 00:00:00.


作为您为什么要使用时区而不是仅从UTC偏移的示例,请查看您的示例数据 -330,我很容易将其误解为比UTC落后三个半小时。当前,此偏移量仅在区域 America/St_Johns中使用,并且仅在一年的部分时间中使用。因此,如果对错误的日期中的日期应用了-03:30的偏移量,则结果将无效且无法检测。

使用偏移量(不建议)

但是您的示例缺少时区,因此让我们从UTC偏移量开始,而不是时区。

使用 int整数表示UTC偏移量是一种不好的类型选择。首先,它是模棱两可的。 -330可能被解释为笨拙的尝试,因为 -03:30的时间比计划晚了三个半小时。其次,它使解析变得比需要的棘手。第三,以分钟为单位,它忽略了以秒为单位偏移的可能性。第四,尽管通常用法和标准用法相反,但您使用负数表示UTC之前的偏移量(显然)。最后,它忽略了 ISO 8601为将偏移量表示为文本: ±HH:MM:SS(和变体)设置的明确标准。顺便说一句,填充零在标准中是可选的,但是我建议始终包括在内,因为各种库和协议都希望填充零。

您的意图似乎是整数表示的分钟数。

long seconds =( TimeUnit.MINUTES.toSeconds( - 330 ) * -1 );  // Multiply by negative one to flip the sign to standard ISO 8601 usage, where `+` means “ahead* of UTC and `-` means *behind* UTC.



  秒:19800


ZoneOffset offset = ZoneOffset.ofTotalSeconds( ( int ) seconds );



  offset.toString():+05:30


最后一步:获取此偏移量中的第一天。注意:我们不确定该偏移量在该日期是否有效,因为我们缺少时区。

从返回的 ZonedDateTime转换为 OffsetDateTime。如上所述,确定一天中的第一时刻应该始终以一个时区完成,从而获得 ZonedDateTime。我们违反了使用偏移量的明智做法,但是使用返回的 ZonedDateTime对象将产生误导,因为我们的对象缺少真实的时区,并且仅有偏移量。因此, OffsetDateTime类使我们的意图更加明确,我们的代码也更加自我记录。

    OffsetDateTime odt = ld.atStartOfDay( offset ).toOffsetDateTime();


同样,不建议使用偏移量的方法,因为您应该从用户那里收集时区名称作为输入而不是偏移量。

世界标准时间

通常最好将时间存储在UTC中。

从您的 InstantOffsetDateTime中提取一个 ZonedDateTime以获得与UTC相同的时刻。

Instant instant = zdt.toInstant() ;



  2018-04-04T18:30:00Z




关于java.time

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

现在位于 Joda-Time中的 maintenance mode项目建议迁移到 java.time类。

要了解更多信息,请参见 Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为 JSR 310

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

在哪里获取java.time类?


Java SE 8Java SE 9和更高版本


内置的
标准Java API的一部分,具有捆绑的实现。
Java 9添加了一些次要功能和修复。

Java SE 6Java SE 7


ThreeTen-Backport中的许多java.time功能都已反向移植到Java 6和7。

Android


更高版本的Android捆绑了java.time类的实现。
对于早期的Android(<26), ThreeTenABP项目改编了ThreeTen-Backport(如上所述)。请参见 How to use ThreeTenABP…



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

关于java - Java将字符串转换为日期,即使提供了浏览器时区,也可以减少一天的时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49679312/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com