从 GMT 值计算时区 - Android

Posted

技术标签:

【中文标题】从 GMT 值计算时区 - Android【英文标题】:Calculating timezone from GMT value - Android 【发布时间】:2013-05-05 21:15:46 【问题描述】:

android 表单中,我接受来自用户的 GMT 值(偏移量),例如 +5:30、+3:00。 从这个值,我想计算“印度/德里”的时区。

关于如何做的任何想法......Plzz

【问题讨论】:

您必须搜索时区才能找到匹配项(显然,可以有多个) 您甚至知道发生偏移的日期/时间吗?这至少会缩小一点…… 【参考方案1】:

如果您已经有一个特定的时间偏移量有效,您可以执行以下操作:

import java.util.*;

public class Test 

    public static void main(String [] args) throws Exception 
        // Five and a half hours
        int offsetMilliseconds = (5 * 60 + 30) * 60 * 1000;
        for (String id : findTimeZones(System.currentTimeMillis(),
                                       offsetMilliseconds)) 
            System.out.println(id);
        
    

    public static List<String> findTimeZones(long instant,
                                             int offsetMilliseconds) 
        List<String> ret = new ArrayList<String>();
        for (String id : TimeZone.getAvailableIDs()) 
            TimeZone zone = TimeZone.getTimeZone(id);
            if (zone.getOffset(instant) == offsetMilliseconds) 
                ret.add(id);
            
        
        return ret;
    

在我的盒子上打印:

Asia/Calcutta
Asia/Colombo
Asia/Kolkata
IST

(据我所知,India/Delhi 不是有效的 zoneinfo ID。)

如果您不知道偏移有效的时刻,那么真正正确地做到这一点变得相当困难。这是一个版本:

public static List<String> findTimeZones(int offsetMilliseconds) 
    List<String> ret = new ArrayList<String>();
    for (String id : TimeZone.getAvailableIDs()) 
        TimeZone zone = TimeZone.getTimeZone(id);
        if (zone.getRawOffset() == offsetMilliseconds ||
            zone.getRawOffset() + zone.getDSTSavings() == offsetMilliseconds) 
            ret.add(id);
        
    
    return ret;

...但是假设每个时区只有两个偏移量,而实际上时区在历史上可能会发生很大变化。当然,它还为您提供了更广泛的 ID。例如,一小时的偏移量将包括 Europe/London 和 Europe/Paris,因为在夏季时间伦敦是 UTC+1,而在冬季巴黎是 UTC+1。

【讨论】:

+1 不错的答案。我可以得到 id,但不知道你必须在毫秒内匹配 @Raghunandan:“以毫秒为单位的匹配”是什么意思?这只是getOffset 在...中返回值的单位。 我错过了这个 (zone.getOffset(instant) == offsetMilliseconds) 部分是我的意思。 乔恩一如既往的好答案!【参考方案2】:

许多时区 ID 可以有相同的时区偏移量

通常,时区 ID 和时区偏移量之间的关系是多对一的,即多个时区 ID 可以具有相同的时区偏移量。事实上,由于DST,一个时区 ID 可以有两个时区偏移量,例如时区 ID“欧洲/伦敦”的时区偏移量分别为“+00:00”和“+01:00”in the summer and in the winter。

除此之外,在某些情况下,国家的时区偏移已被其统治者/政治家多次更改,正如 Ole V.V. 也提到的那样。在以下评论中:

时区ID和时区偏移量之间的关系是多对一的…… 如果您正在考虑某个时间点,则为真。如果看历史, 真的是多对多。

因此,考虑到夏令时和这些历史事件,我们可以说时区 ID 和时区偏移量之间的关系是多对多的。

使用现代日期时间 API java.time 的解决方案:

您可以遍历ZoneId.getAvailableZoneIds()来过滤和收集ZoneOffset等于使用输入偏移字符串创建的ZoneOffsetZoneId

演示:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class Main 
    public static void main(String[] args) 
        // Test
        System.out.println(getTimeZoneId("+5:30"));
        System.out.println(getTimeZoneId("-5:00"));
    

    static List<String> getTimeZoneId(String input) 
        List<String> list = new ArrayList<>();
        // Convert +5:30 to +05:30; similarly, -5:00 to -05:00
        String[] arr = input.split(":");
        if (arr.length == 2) 
            input = arr[0].substring(0, 1) + String.format("%02d", Integer.parseInt(arr[0].replaceAll("\\D", ""))) + ":"
                    + arr[1];

            ZoneOffset offset = ZoneOffset.of(input);
            Instant now = Instant.now();

            list = ZoneId.getAvailableZoneIds()
                    .stream()
                    .filter(tzId -> ZoneId.of(tzId).getRules().getOffset(now).equals(offset))
                    .collect(Collectors.toList());
        
        return list;
    

输出:

[Asia/Kolkata, Asia/Colombo, Asia/Calcutta]
[America/Panama, America/Chicago, America/Eirunepe, Etc/GMT+5, Mexico/General, America/Porto_Acre, America/Guayaquil, America/Rankin_Inlet, US/Central, America/Rainy_River, America/Indiana/Knox, America/North_Dakota/Beulah, America/Monterrey, America/Jamaica, America/Atikokan, America/Coral_Harbour, America/North_Dakota/Center, America/Cayman, America/Indiana/Tell_City, America/Mexico_City, America/Matamoros, CST6CDT, America/Knox_IN, America/Bogota, America/Menominee, America/Resolute, SystemV/EST5, Canada/Central, Brazil/Acre, America/Cancun, America/Lima, America/Bahia_Banderas, US/Indiana-Starke, America/Rio_Branco, SystemV/CST6CDT, Jamaica, America/Merida, America/North_Dakota/New_Salem, America/Winnipeg]

ONLINE DEMO

注意:正则表达式模式\D指定一个非数字字符。

Trail: Date Time 了解有关现代日期时间 API 的更多信息。


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

【讨论】:

【参考方案3】:

如果我正确解释了您的问题,那么试试这个,

final SimpleDateFormat date=
        new SimpleDateFormat("EEE, MMM d, yyyy hh:mm:ss a z");
date.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("GMT time: " + date.format(currentTime));

在此您可以添加偏移量。看看这对你有没有帮助。

【讨论】:

不,据我所知,这根本不能回答问题。 OP 不是在谈论文本格式。他说的是时区检测。

以上是关于从 GMT 值计算时区 - Android的主要内容,如果未能解决你的问题,请参考以下文章

来自区域 ID 的 GMT 时区

从 GMT 到本地的时区转换

将日期从 GMT 时区转换为本地时区——使用 ISO_OFFSET_DATE_TIME

无法连接到 mySQL,因为无法识别服务器时区值“GMT Summer Time”

如何将日期/时间从 GMT 转换为本地时区

如何在 android 中将日期从 GMT 时区解析为 IST 时区和反之亦然