【问题标题】:Allow user to select time zone允许用户选择时区
【发布时间】:2019-05-14 11:45:03
【问题描述】:

我正在编写一个 Java 应用程序,用户应该可以在其中选择他们的时区。我列出了所有可用的 TimeZone.getAvailableIDs(),它返回了 627 行。显然我不会要求用户从中选择。我应该如何覆盖所有时区 + 在适用的情况下使用正确的夏令时,并且选择最少?

【问题讨论】:

  • 使用自动完成输入。
  • TimeZone 类是旧的并且存在一些设计问题,以及它的朋友如CalendarSimpleDateFormat。我建议你切换到java.time, the modern Java date and time API。它对应的类是ZoneId(不过也有627个可用的ID)。
  • 没错,我们缺少一个时区选择器 GUI 组件。如果我们可以使用世界地图并让用户指向一个时区,那就太好了。如果做不到这一点,一个想法是让用户先选择大陆,然后再选择城市。它不能解决整个问题;仅美洲大陆就有 100 多个区域。
  • How to provide an elegant time zone picker? 的可能重复项,不过,那个人没有一个赞成或接受的答案。

标签: java date time timezone


【解决方案1】:

您是否考虑过简化事情并使用UTC?我见过许多对用户时区感兴趣的网站都使用它。这应该会将其减少到大约 24 个选项(如果您担心为 每个 国家/地区提供服务并且不适合为一对夫妇提供 30 分钟的服务,那么在某些特殊情况下,可能会将其增加到约 40 个)。那么唯一的考虑就是询问他们是否遵守夏令时。实施这将涉及考虑半球。

【讨论】:

  • 据我所知,甚至夏令时的开始和结束日期因国家/地区而异,因此 UTC 偏移量 + 布尔值无法解决问题。 :(
  • 有 627 个区域 ID 是有原因的。承认有重复(别名 ID),但它们不能减少到 3 * 40 = 120。特别是,历史偏移量不同,有时也不会除以 30 或 15 分钟,引入夏令时 (DST)或逐年取消,因此今年与去年或明年不适用相同的规则。等等。
【解决方案2】:
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class MainClass {

    public static void main(String[] argv) {

        Map<String, String> sortedMap = new LinkedHashMap<>();

        List<String> zoneList = new ArrayList<>(ZoneId.getAvailableZoneIds());

        // Get all ZoneIds
        Map<String, String> allZoneIds = getAllZoneIds(zoneList);

        // sort by value, descending order, use values as keys and vice versa
        allZoneIds.entrySet().stream().sorted(Map.Entry.<String, String>comparingByValue().reversed())
                .forEachOrdered(e -> sortedMap.put(e.getValue(), e.getKey()));

        // print map
        sortedMap.forEach((k, v) -> {
            String out = String.format("%5s (UTC%s) %n", k, v);
            System.out.printf(out);
        });
    }

    private static Map<String, String> getAllZoneIds(List<String> zoneList) {

        Map<String, String> result = new HashMap<>();

        LocalDateTime dt = LocalDateTime.now();

        for (String zoneId : zoneList) {

            ZoneId zone = ZoneId.of(zoneId);
            ZonedDateTime zdt = dt.atZone(zone);
            ZoneOffset zos = zdt.getOffset();

            // replace Z to +00:00
            String offset = zos.getId().replaceAll("Z", "+00:00");
            result.put(zone.toString(), offset);

        }
        return result;
    }
}

基于:https://www.mkyong.com/java8/java-display-all-zoneid-and-its-utc-offset/

在创建时区地图时,我将键替换为值,因此我们将 UTC 差异作为键。

这个输出:

-12:00 (UTCEtc/GMT+12) 
-11:00 (UTCPacific/Midway) 
-10:00 (UTCEtc/GMT+10) 
-09:30 (UTCPacific/Marquesas) 
-09:00 (UTCSystemV/YST9YDT) 
-08:00 (UTCUS/Pacific) 
-07:00 (UTCAmerica/Shiprock) 
-06:00 (UTCAmerica/Winnipeg) 
-05:00 (UTCSystemV/EST5EDT) 
-04:00 (UTCSystemV/AST4ADT) 
-03:30 (UTCCanada/Newfoundland) 
-03:00 (UTCAmerica/Argentina/Buenos_Aires) 
-02:00 (UTCAtlantic/South_Georgia) 
-01:00 (UTCAmerica/Scoresbysund) 
+14:00 (UTCEtc/GMT-14) 
+13:45 (UTCPacific/Chatham) 
+13:00 (UTCEtc/GMT-13) 
+12:00 (UTCPacific/Majuro) 
+11:00 (UTCPacific/Guadalcanal) 
+10:30 (UTCAustralia/South) 
+10:00 (UTCAustralia/Lindeman) 
+09:30 (UTCAustralia/Darwin) 
+09:00 (UTCAsia/Tokyo) 
+08:45 (UTCAustralia/Eucla) 
+08:30 (UTCAsia/Pyongyang) 
+08:00 (UTCAsia/Singapore) 
+07:00 (UTCAsia/Saigon) 
+06:30 (UTCIndian/Cocos) 
+06:00 (UTCAsia/Thimphu) 
+05:45 (UTCAsia/Katmandu) 
+05:30 (UTCAsia/Calcutta) 
+05:00 (UTCIndian/Kerguelen) 
+04:30 (UTCAsia/Kabul) 
+04:00 (UTCEurope/Ulyanovsk) 
+03:30 (UTCAsia/Tehran) 
+03:00 (UTCW-SU) 
+02:00 (UTCEurope/Athens) 
+01:00 (UTCEurope/Monaco) 
+00:00 (UTCEtc/UTC)

【讨论】:

  • 我的问题是这不考虑夏令时,否则我只会使用偏移量。 (而且仅仅因为我的偏移量是 +9 就选择东京是很令人困惑的)
  • 然后使用所有时区 + 自动建议。因为它显然在每个区域中不止一个城市,即使您合并所有城市,您也会得到类似Pacific/Palau, Asia/Chita,Dili,Jayapura,Yakutsk,Seoul,Khandyga,Tokyo 的东西,它也不是很实用。关于节省时间,我记得有几个国家/地区取消(然后可能更新)所以不确定它是否可以被 API 跟踪,也许只是为 DST 添加复选框
  • 错误 使用Instant 而不是LocalDateTimeLocalDateTime 类没有时区或从 UTC 偏移的概念。所以它不能代表一个时刻,它不是时间线中的一个点。如果在某个区域(例如夏令时 (DST))发生异常时执行,您的代码可能会产生意想不到的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-03
  • 2022-01-03
  • 2017-10-08
  • 2017-02-25
  • 2016-02-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多