首页 > 解决方案 > 将 UTC 时间 HH:mm:ss 转换为设备时间 HH:mm:ss 并添加夏令时(如果有)

问题描述

我有格式为 (HH: mm: ss) 的 UTC 字符串,我需要将字符串值以相同格式 (HH: mm: ss) 转换为设备时间,并且如果可用,还添加日节省时间我已经尝试转换通过此代码将 UTC 字符串转换为设备时间,但由于(日节省时间),我得到了 1 小时的延迟。

String utcTimeString = "12:15:00"
SimpleDateFormat formatter = new SimpleDateFormat("HH: mm: ss");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
Date value = formatter.parse(utcTimeString);

SimpleDateFormat dateFormatter = new SimpleDateFormat("HH: mm: ss"); 
dateFormatter.setTimeZone(TimeZone.getDefault());
utcDateString = dateFormatter.format(value);

我的时区是 GMT-4

预期输出:08:15:00;给定输出:07:15:00;

标签: javaandroiddatedatetime

解决方案


deHaar的答案通常是正确的,并且明智地利用了现代java.time类。但是,我会使用稍微不同的方法。

tl;博士

OffsetDateTime.of(                           // Represent a moment as a date, a time-of-day, and an offset-from-UTC.
    LocalDate.now( ZoneOffset.UTC ) ,        // Current date as seen right now in UTC. Beware: For any given moment, the date varies around the globe by zone.
    LocalTime.parse( "12:15:00" ) ,          // Your specified time-of-day.
    ZoneOffset.UTC                           // An offset of zero hours-minutes-seconds, for UTC itself.
)                                            // Returns an `OffsetDateTime` object.
.atZoneSameInstant(                          // Adjust from UTC to a time zone. Same moment, different wall-clock-time.
    ZoneId.of( "America/Port_of_Spain" ) ;   // One of the many time zones that are behind UTC by four hours on that date.
)                                            // Returns a `ZonedDateTime` object.
.toLocalTime()                               // Extract the time-of-day only, leaving behind the date and the zone.

时区

我的时区是 GMT-4

没有。那不是时区。

该值GMT-4仅表示与 UTC 的偏移量。UTC 基线之前或之后的小时-分钟-秒数。

时区更多。一个时区有一个名字,代表了过去、现在和未来的历史变化,特定地区的人们使用的偏移量。因此,时区总是比单纯的偏移更可取。

以、或等格式指定适当的时区名称。永远不要使用 2-4 个字母的缩写,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。Continent/RegionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST

ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;  

如果您的时区当前比 UTC 晚 4 小时,则您必须位于America/ArubaAmerica/Puerto_RicoAmerica/ManausAmerica/Martinique等时区。

ZoneId z = ZoneId.of( "America/Martinique" ) ;

世界标准时间

我有格式为(HH:mm:ss)的UTC字符串

没有。

诸如此类的值"12:15:00"不能说是 UTC 中的值。没有日期,该值就没有真正的意义。一个时刻由三个部分组成:

  • 一个约会,
  • 一天中的某个时间,和
  • 偏移量/区域。

说“UTC 中午”只给了我们 3 个部分中的 2 个。日期不见了。

今天……什么概念

Perhaps you want to apply that time-of-day to the current date as seen in UTC.

LocalDate todayUTC = LocalDate.now( ZoneOffset.UTC ) ;

Just keep in mind that for any given moment the date varies around the globe by zone. At this very moment, the date is “tomorrow“ in Tokyo Japan while still being “yesterday” in Toledo Ohio US.

OffsetDateTime

Combine all three into a OffsetDateTime object: date, time-of-day, and offset/zone.

LocalTime localTime = LocalTime.parse( "12:15:00" ) ;
OffsetDateTime odt = OffsetDateTime.of( todayUTC , localTime, ZoneOffset.UTC ) ;

ZonedDateTime

Adjust from UTC to your particular time zone. Same moment, same simultaneous point on the timeline, different wall-clock time. Apply a ZoneId to get a ZonedDateTime object. The time zone nows about if and when Daylight Saving Time (DST) applies for this particular zone, and adjusts accordingly.

ZoneId z = ZoneId.of( "America/Martinique" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

Wrong approach

You should not be adding/subtracting some number of hours from a LocalTime. On some dates in some zones, a particular time-of-day may not exist. For example, for Daylight Saving Time, on the day of "Spring-ahead", in the United States, a time-of-day of 02:15:00 does not exist, as the clock jumps ahead from 02:00:00 to 03:00:00.

The correct approach using the ZonedDateTime class will automatically adjust accordingly.


推荐阅读