【问题标题】:Get TimeZone offset value from TimeZone without TimeZone name从没有 TimeZone 名称的 TimeZone 获取 TimeZone 偏移值
【发布时间】:2012-07-09 02:43:32
【问题描述】:

我需要以 [+/-]hh:mm 格式保存手机的时区

我正在使用 TimeZone 类来处理这个问题,但我能得到的唯一格式如下:

PST -05:00
GMT +02:00

我宁愿不对结果进行子串化,是否可以设置任何键或选项标志以仅获取值而不是该时区的名称(GMT/CET/PST...)?

【问题讨论】:

标签: java timezone


【解决方案1】:

我需要以 [+/-]hh:mm 格式保存手机的时区

不,你没有。单独的偏移量是不够的,您需要存储整个时区名称/id。例如,我住在奥斯陆,我当前的偏移量是 +02:00,但在冬天(由于)它是 +01:00。标准时间和夏令时间之间的确切切换取决于您不想探索的因素。

因此,我将"Europe/Oslo" 存储在我的数据库中,而不是存储+ 02:00(或者应该是+ 01:00?)。现在我可以使用以下命令恢复完整配置:

TimeZone tz = TimeZone.getTimeZone("Europe/Oslo")

想知道我今天的时区偏移量是多少?

tz.getOffset(new Date().getTime()) / 1000 / 60   //yields +120 minutes

但是 12 月还是一样:

Calendar christmas = new GregorianCalendar(2012, DECEMBER, 25);
tz.getOffset(christmas.getTimeInMillis()) / 1000 / 60   //yields +60 minutes

说得够多了:存储时区名称或 id 并且每次要显示日期时,检查当前偏移量(今天)是多少,而不是存储固定值。您可以使用 TimeZone.getAvailableIDs() 枚举所有支持的时区 ID。

【讨论】:

  • 不,我正在与一个 api 交互,不管它的设计好坏。让我们不要进入那个。他们只要求我发送像 hh:mm 这样的时区......我知道。
  • @MrBean:巧合的是,我已经向您展示了该怎么做:如果您已经拥有 TimeZone 课程,只需使用当前日期调用 getOffset() 并将其从毫秒转换为分钟。然后格式化为hh:mm
  • 很棒的更新 Tomasz,但是,我可以请你扩展一点。我在服务器端数据库中将日期存储为 UTC(显然),并且我也在服务器端数据库中存储了我的 TZ 名称(在您的示例中为“Europe/Oslo”)。我想将应用了正确偏移量的日期传回给客户,我应该(可以吗?)这样做,还是分别传递日期和偏移量?问题是我在客户端上使用 GWT,所以我无法使用 java.util.TimeZone,因此无法将“Europe/Oslo”转换为 com.google.gwt.i18n.shared.TimeZone.createTimeZone("Europe/Oslo" ) 不起作用!
  • @johnvdenley:请提出一个单独的问题,请随时在此处发布后续链接。
  • 这正是我正在寻找的答案,非常好,谢谢!
【解决方案2】:

@MrBean - 我遇到了类似的情况,我必须调用第 3 方 Web 服务并以 +/-hh:mm 格式传递 Android 设备的当前时区偏移量。这是我的解决方案:

public static String getCurrentTimezoneOffset() {

    TimeZone tz = TimeZone.getDefault();  
    Calendar cal = GregorianCalendar.getInstance(tz);
    int offsetInMillis = tz.getOffset(cal.getTimeInMillis());

    String offset = String.format("%02d:%02d", Math.abs(offsetInMillis / 3600000), Math.abs((offsetInMillis / 60000) % 60));
    offset = (offsetInMillis >= 0 ? "+" : "-") + offset;

    return offset;
} 

【讨论】:

    【解决方案3】:

    现在有了java8,你可以使用

    Integer offset  = ZonedDateTime.now().getOffset().getTotalSeconds();
    

    从 UTC 获取当前系统时间偏移量。然后,您可以将其转换为您想要的任何格式。发现它对我的情况很有用。 示例:https://docs.oracle.com/javase/tutorial/datetime/iso/timezones.html

    【讨论】:

      【解决方案4】:

      使用 Java 8,您可以通过以下代码实现此目的。

          TimeZone tz = TimeZone.getDefault();
          String offsetId = tz.toZoneId().getRules().getStandardOffset(Instant.now()).getId();
      

      offsetId 类似于 +01:00

      请注意函数getStandardOffset 需要一个Instant 作为参数。这是您要检查给定时区偏移量的特定时间点,因为时区的偏移量可能随时间变化。由于某些地区有夏令时

      我认为这是@Tomasz Nurkiewicz 建议不要直接以符号小时格式存储偏移量的原因,而是在每次需要时检查偏移量。

      【讨论】:

        【解决方案5】:
        ZoneId here = ZoneId.of("Europe/Kiev");
        ZonedDateTime hereAndNow = Instant.now().atZone(here);
        String.format("%tz", hereAndNow);
        

        会给你一个标准化的字符串表示,比如“+0300”

        【讨论】:

        • 仅适用于Android API 26及以上,android用户使用前请注意
        • @ShadabK android 用户可以使用 ThreeTenABP 做同样的事情,它就像一个魅力。
        【解决方案6】:

        我们可以很容易地得到一个TimeZone 的毫秒偏移量,只需要一个TimeZone 实例和System.currentTimeMillis()。然后我们可以使用TimeUnit 类从毫秒转换为任何时间单位。

        像这样:

        public static int getOffsetHours(TimeZone timeZone) {
            return (int) TimeUnit.MILLISECONDS.toHours(timeZone.getOffset(System.currentTimeMillis()));
        }
        

        或者,如果您更喜欢新的 Java 8 时间 API

        public static ZoneOffset getOffset(TimeZone timeZone) { //for using ZoneOffsett class
            ZoneId zi = timeZone.toZoneId();
            ZoneRules zr = zi.getRules();
            return zr.getOffset(LocalDateTime.now());
        }
        
        public static int getOffsetHours(TimeZone timeZone) { //just hour offset
            ZoneOffset zo = getOffset(timeZone);
            TimeUnit.SECONDS.toHours(zo.getTotalSeconds());
        }
        

        【讨论】:

        • 您可以拥有不在整小时内的时区,例如Banglore 是 GMT +5.5 小时,所以我不建议使用 getOffsetHours
        【解决方案7】:

        java.time:现代日期时间 API

        您可以使用ZonedDateTime#getOffset 获取时区的偏移量。

        请注意,遵守DST 的时区的偏移量会根据 DST 的变化而变化。对于其他地方(例如印度),它保持不变。因此,建议提及显示时区偏移量的时刻。时刻被提到为Instant.now(),它代表UTC 中的日期时间(由代表Zulu 的Z 表示,并指定+00:00 小时的时区偏移量)。

        ZoneId.getAvailableZoneIds()返回的所有时区的显示偏移量:

        import java.time.Instant;
        import java.time.ZoneId;
        import java.time.ZonedDateTime;
        
        public class Main {
            public static void main(String[] args) {
                // Test
                Instant instant = Instant.now();
                System.out.println("Timezone offset at " + instant);
                System.out.println("==============================================");
                ZoneId.getAvailableZoneIds()
                    .stream()
                    .sorted()
                    .forEach(strZoneId -> System.out.printf("%-35s: %-6s%n",
                        strZoneId, getTzOffsetString(ZoneId.of(strZoneId), instant)));
            }
        
            static String getTzOffsetString(ZoneId zoneId, Instant instant) {
                return ZonedDateTime.ofInstant(instant, zoneId).getOffset().toString();
            }
        }
        

        输出:

        Timezone offset at 2021-05-05T21:45:34.150901Z
        ==============================================
        Africa/Abidjan                     : Z     
        Africa/Accra                       : Z     
        Africa/Addis_Ababa                 : +03:00
        ...
        ...
        ...    
        W-SU                               : +03:00
        WET                                : +01:00
        Zulu                               : Z  
        

        Trail: Date Time 了解有关 modern date-time API* 的更多信息。


        * 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 和 7 . 如果您正在为一个 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

        【讨论】:

          【解决方案8】:

          我知道这是旧的,但我想我会提供我的意见。我必须为工作中的项目执行此操作,这是我的解决方案。

          我有一个使用 TimeZone 类包含 Timezone 的 Building 对象,并希望在新类中创建 zoneId 和 offset 字段。

          所以我所做的就是创建:

          private String timeZoneId;
          private String timeZoneOffset;
          

          然后在构造函数中,我传入了 Building 对象并像这样设置这些字段:

          this.timeZoneId = building.getTimeZone().getID();
          this.timeZoneOffset = building.getTimeZone().toZoneId().getId();
          

          因此 timeZoneId 可能等于“EST” timeZoneOffset 可能等于“-05:00”

          我不想你可能不会

          【讨论】:

          • building.getTimeZone().toZoneId().getId() 返回文本(如“Europe/Oslo”),而不是偏移量(如“2”)
          猜你喜欢
          • 2021-08-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-11
          • 2021-11-28
          • 2018-01-16
          • 2018-04-16
          相关资源
          最近更新 更多