Java 8 将日期字符串转换为带时区的日期

Aks*_*wad 0 java date java-8

我收到了格式为“yyyy-MM-dd'T'HH:mm:ssXXX”的字符串

例如“2020-06-01T11:04:02+02:00”

我想把它转换成“yyyy-MM-dd'T'HH:mm:ss:SSSZ”

例如“2020-06-01T11:04:02.000+0200”

我实际上不知道时区。它应该取自字符串的最后一部分。

我已经尝试过,但是当我将字符串转换为日期(即 IST)时,它占用了我的本地时间和时区。

        SimpleDateFormat sd1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
        //sd1.setTimeZone(TimeZone.getTimeZone("PST"));
        Date dt = sd1.parse("2020-06-01T11:04:02+02:00");
        SimpleDateFormat sd2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss:SSSZ");
        System.out.println(sd2.format(dt));
Run Code Online (Sandbox Code Playgroud)

输出:

2020-06-01T14:34:02:000+0530
Run Code Online (Sandbox Code Playgroud)

只有日期是正确的,时间和时区已更改。

我知道我做错了,如果有人能告诉我我该怎么做,这将非常有帮助。谢谢您的帮助。

Bas*_*que 8

Java 中所有日期时间类型的表,包括现代的和传统的

OffsetDateTime

你说:

我收到了格式为“yyyy-MM-dd'T'HH:mm:ssXXX”的字符串

例如“2020-06-01T11:04:02+02:00”

无需定义格式模式。您的输入符合ISO 8601标准。

在解析/生成字符串时,java.time类中默认使用这些标准格式。

您的输入应被解析为OffsetDateTime.

String input = "2020-06-01T11:04:02+02:00" ;
OffsetDateTime odt = OffsetDateTime.parse( input ) ;
Run Code Online (Sandbox Code Playgroud)

odt.toString(): 2020-06-01T11:04:02+02:00

UTC 偏移量与时区

你说:

我实际上不知道时区。

+02:00对到底是不是一个时区。该文本仅代表 UTC 的偏移量。偏移量只是一些小时-分钟-秒,正数或负数。时区要多得多。时区是特定地区人民使用的偏移量的过去、现在和未来变化的历史记录。时区的名称格式为Continent/Region,例如Europe/BrusselsAfrica/Cairo

您可以从单纯的偏移调整到特定时区。申请 aZoneId以获得ZonedDateTime.

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ; 
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
Run Code Online (Sandbox Code Playgroud)

zdt.toString(): 2020-06-01T14:34:02+05:30[亚洲/加尔各答]

你说:

它应该取自字符串的最后一部分。

我不确定你的意思。如果您将输入解析为OffsetDateTime,则该对象知道其偏移量,可作为ZoneOffset.

ZoneOffset offset = odt.getOffset() ;
Run Code Online (Sandbox Code Playgroud)

请参阅在 IdeOne.com 上实时运行的此答案中显示的代码。

offset.toString(): +02:00

格式化字符串

你说:

我想把它转换成“yyyy-MM-dd'T'HH:mm:ss:SSSZ”

例如“2020-06-01T11:04:02.000+0200”

不确定你在这里的意思。即使值为零,您的意思是强制显示毫秒吗?首先,您应该知道java.time对象具有最多九位十进制数字的纳秒分辨率,比以十进制小数的 3 位数字显示的毫秒要精细得多。其次,强制显示小数秒已经在 Stack Overflow 上有介绍,比如这里。在发布之前总是搜索 Stack Overflow

或者您的意思是将没有 COLON 字符的偏移量显示为分钟和秒之间的分隔符?

  • 我建议不要这样做。虽然 ISO 8601 标准在技术上允许删除 COLON,但我已经看到不止一个软件库或系统无法处理没有该分隔符的偏移量。使用没有分钟的小时偏移量也是如此。我建议始终使用小时、分钟和分隔符。
  • 如果您坚持,请使用DateTimeFormatter格式模式。研究 Javadoc,记住格式代码是 (a) 区分大小写,和 (b) 对重复字符 0、1 或更多次敏感。这里我们xx用来获取没有 COLON 字符分隔的偏移量的小时和分钟。(同样,我不推荐这种格式。)

代码显示在同一个 IdeOne.com 页面中

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSxx" ) ;     
String output = odt.format( f ) ;
Run Code Online (Sandbox Code Playgroud)

输出:2020-06-01T11:04:02.000+0200

Date::toString 注入时区

你说:

我已经尝试过,但是当我将字符串转换为日期(即 IST)时,它占用了我的本地时间和时区。

java.util.Date::toString方法说谎。虽然本意是好的,但不幸的是,该方法在Date生成文本时将 JVM 的当前默认时区应用于该值。本Date类实际上代表了UTC片刻。这是从不使用Date. 现在那个班级被java.time.Instant.


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

现在处于维护模式Joda-Time项目建议迁移到java.time类。

您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。Hibernate 5 & JPA 2.2 支持java.timejava.sql.*

从哪里获得 java.time 类?

  • 是的,实际上我对时区和区域偏移量感到困惑,ZoneOffset 完成了工作。非常感谢您的回答和澄清。 (2认同)

Dan*_*oas 5

我向您提出的第一个建议是从使用 Date 对象切换到 LocalDateTime (java 8+)

使用新的 API 会以这种方式工作

String YOUR_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ssXXX";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YOUR_DATE_TIME_PATTERN);
LocalDateTime dateTime = LocalDateTime.parse(input_date, formatter);

//Then you can set your timezone in this way - remember to replace the values with the proper timezone you want. 



ZonedDateTime zonedUTC = dateTime.atZone(ZoneId.of("UTC"));

ZonedDateTime zonedIST = zonedUTC.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));
Run Code Online (Sandbox Code Playgroud)

让我知道这是否适合你