【问题标题】:Android time zone and DST issueAndroid 时区和 DST 问题
【发布时间】:2013-03-05 06:47:43
【问题描述】:

我有一个使用时间表的应用程序。用户选择计划应该开始/结束的时间,然后我将开始/结束时间显示给用户。问题是,显示回来的时间是关闭的,因为 DST 改变了。

我可以解决我的时区(东部时间)的问题,或者我可以解决 GMT 的问题,如果我为 GMT 设置特定情况,阿拉斯加时间仍然是错误的。有什么建议吗?

这是我的代码:

正在显示的时间:

long startTimeMillis = (startHour * 1000 * 60 * 60) + (startMin * 1000 * 60) - getTimeOffset();

getTimeOffset:

TimeZone tz = TimeZone.getDefault();

//deal with GMT weirdness
if (tz.getRawOffset() == 0)
    return tz.getRawOffset() + tz.getDSTSavings();
else
    return tz.getRawOffset();

我认为我需要类似的东西:

else if(tz.inDaylightTime(new Date()))
    return tz.getRawOffset() + tz.getDSTSavings();

但如果我这样做,东部时间会比应有的时间少 1 小时,而阿拉斯加时间会少 2 小时。如果我反其道而行之:(- 而不是 +)

else if(tz.inDaylightTime(new Date()))
    return tz.getRawOffset() - tz.getDSTSavings();

那么东部时间比应有的时间多 1 小时,但阿拉斯加时间是正确的。

附录:

我还尝试在每种情况下使用tz.getOffset(new Date().getTime()),而不是tz.getRawOffset()。这实际上是我尝试的第一件事,因为根据谷歌的文档,这个函数应该为你处理夏令时。

结束附录

我也尝试过使用日历,如下所示:

Calendar calendar = GregorianCalendar.getInstance();

return calendar.get(Calendar.ZONE_OFFSET);

这为美国东部标准时间提供了正确的时间,但格林威治标准时间提前 1 小时,阿拉斯加时间落后 1 小时。我已经试过了:

if(tz.inDaylightTime(new Date()))
    return calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
else
    return calendar.get(Calendar.ZONE_OFFSET);

但这让美国东部夏令时间缩短了 1 小时。

我也试过这个:

return tz.getOffset(calendar.get(Calendar.ERA),
            calendar.get(Calendar.YEAR),
            calendar.get(Calendar.MONTH),
            calendar.get(Calendar.DAY_OF_MONTH),
            calendar.get(Calendar.DAY_OF_WEEK),
            calendar.get(Calendar.MILLISECOND));

这也让 EDT 缩短了 1 小时。

如果我使用

,我会得到相同的结果
GregorianCalendar calendar = new GregorianCalendar(tz);

而不是

Calendar calendar = GregorianCalendar.getInstance();

我该如何正确地做到这一点???

【问题讨论】:

  • 好的,你的帖子没有显示用户是如何输入数据的,所以你接受除了starthourstartminute之外的任何数据,一旦你用它们来计算startTimeMillis ,startTimeMillis后面怎么用?
  • 您可能不需要使用getRawOffset()getDSTSavings()。我意识到这很令人困惑; Java 时间实用程序正是 JodaTime 项目如此成功的原因。
  • DST 结果取决于日期(我在您的问题中没有看到任何内容)和确切的 TimeZone 'id',但我希望我有所帮助。因为您非常棒,可以分享您的尝试,并实际检查您的问题,所以我会尽我所能帮助您解决这个问题。如果您使用的日期在 DST 之内(例如今天),那么遵守 DST 的TimeZones 将比不遵守 DST 的日期早一小时。我最喜欢的例子是中西部:“America/Denver”遵守 DST,而“America/Phoenix”和“MST”则没有。今天凤凰城和 MST 显示 08:00 时,丹佛(夏令时)将显示 09:00,因为它“向前跳跃”。
  • startTimeMillis 是计划的开始时间。用户在TimePicker 中输入它,稍后用于显示计划的开始时间,并实际启动计划。所以startTimeMillis是下一个时间表的开始时间。

标签: android dst timezone-offset


【解决方案1】:

好的,我终于想出了如何正确地做到这一点。我就是这样做的:

long startTimeMillis = (startHour * 1000 * 60 * 60) + (startMinute * 1000 * 60);
startTimeMillis  -= getTimeOffset(startTimeMillis);

getTimeOffset():

public static int getTimeOffset(long time)
{
    TimeZone tz = TimeZone.getDefault();

    return tz.getOffset(time);
}

【讨论】:

    【解决方案2】:

    听起来您正在设置模拟器时区,您正在通过tz.getDefault() 检索该时区。日历将在内部处理夏令时 - 如果它们设置为完全遵守夏令时的TimeZone。某些时区,例如“America/Phoenix”和“MDT”不观察节省时间,而“America/Denver”可以。

    阿拉斯加时区通过从协调世界时 (UTC-9) 中减去九小时来遵守标准时间。在夏令时期间,其时间偏移量为八小时 (UTC-8)。 https://en.wikipedia.org/wiki/Alaska_Time_Zone

    您可以使用TimeZone.getAvailableIDs() 获取所有时区名称/键的列表。查看America/AnchorageEtc/GMT+9America/Alaska 之间的区别。

    编辑:更新的代码下面是一些示例代码,您可以通过几种方法来处理日期和 DST:

    package com.codeshane.examples;
    
    import java.text.DateFormat;
    import java.util.Calendar;
    import java.util.TimeZone;
    
    public class Times {
    public static final String[] yourZoneKeys =
      {"America/Anchorage", "America/Juneau", "America/Nome", "America/Yakutat",
       "Etc/GMT+9", "Pacific/Gambier", "SystemV/YST9", "SystemV/YST9YDT","US/Alaska"};
    
    public static void main(String[] args){
        for (String timezoneKey: yourZoneKeys){
            TimeZone tz = getSelectedTimezone(timezoneKey);
            displayTimezoneInfo(tz);
            showTimeInNewCalendar(tz);
        }       
    }
    
    static void displayTimezoneInfo(TimeZone tz){
        System.out.println(
          "\n> TZ ID:" + tz.getID() +
          "  Display:" + tz.getDisplayName() +
          "  savings:" + tz.getDSTSavings() +
          "   offset:" + tz.getRawOffset() +
          ""
        );
    }
    
    static void showTimeInNewCalendar(TimeZone tz) {
        DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
    
        /***** DST US 2013 = Mar 10 - Nov 3
         * Daylight Saving Time (United States) 2013
         * began at 2:00 AM on Sunday, March 10
         *  ends at 2:00 AM on Sunday, November 3
         **/
    
        //The Calendar method output the same results, but since both
        //methods went through the DateFormat, I went ahead and just
        //used the DateFormat's internal date via getCalendar().set(..)
        //but left the Calendar code (commented out) for you to compare.
    
        //Calendar gc = Calendar.getInstance();
        //gc.setTimeZone(tz);
        //gc.set(2013, 2, 10, 1, 30, 0);
    
        // Setting the Calendar's date and time
        df.getCalendar().set(2013, 2, 10, 1, 30, 0);
    
        // Display some times at 30 minute intervals
        for (int i =0;i<3;i++){
    
            df.setTimeZone(tz);
            System.out.println(
              "\n " + tz.getID() +
              " " + df.format(df.getCalendar().getTime()) +// sdf. .format(myDateFormat, gc) +
              //" gc date:" + df.format(gc.getTime()) +
              "  " + tz.inDaylightTime(df.getCalendar().getTime()) +
              ""
            );
            df.getCalendar().add(Calendar.MINUTE, 30);
            //gc.add(Calendar.MINUTE, 30);
        }
    }
    
    private static TimeZone getSelectedTimezone(String timezoneKey){
        if (null==timezoneKey) return TimeZone.getDefault(); // system/network-provided
        return TimeZone.getTimeZone(timezoneKey); // Gets specified tz, or "GMT" if tzKey is invalid
    }
    
    }
    

    编辑:添加输出您会注意到,在我们刚刚在 2013 年 3 月 10 日观察到的“春季前进”时间添加 30 分钟时,一些时区会向前跳跃,而其他时区则不会吨。如果您选择这些遵守 DST 的时区,您将获得更改;而其他人则不会。

    TZ ID:美国/安克雷奇显示:阿拉斯加标准时间节省:3600000 偏移量:-32400000

    美国/安克雷奇 2013 年 3 月 10 日星期日 1:30:00 AM AKST false

    美国/安克雷奇 2013 年 3 月 10 日星期日凌晨 3:00:00 AKDT true

    美国/安克雷奇 2013 年 3 月 10 日星期日凌晨 3:30:00 AKDT true

    TZ ID:美国/朱诺显示:阿拉斯加标准时间节省:3600000 偏移量:-32400000

    美国/朱诺 2013 年 3 月 10 日星期日上午 1:30:00 AKST 错误

    美国/朱诺 2013 年 3 月 10 日星期日凌晨 3:00:00 AKDT 正确

    美国/朱诺 2013 年 3 月 10 日星期日 3:30:00 AM AKDT true

    TZ ID:美国/Nome 显示:阿拉斯加标准时间节省:3600000 偏移量:-32400000

    美国/诺姆 2013 年 3 月 10 日星期日上午 1:30:00 AKST 错误

    America/Nome 2013 年 3 月 10 日星期日凌晨 3:00:00 AKDT true

    America/Nome 2013 年 3 月 10 日星期日 3:30:00 AM AKDT true

    TZ ID:美国/雅库塔特显示:阿拉斯加标准时间节省:3600000 偏移量:-32400000

    美国/雅库塔特 2013 年 3 月 10 日星期日 1:30:00 AM AKST false

    美国/雅库塔特 2013 年 3 月 10 日星期日 3:00:00 AM AKDT true

    美国/雅库塔特 2013 年 3 月 10 日星期日 3:30:00 AM AKDT true

    TZ ID:Etc/GMT+9 显示:GMT-09:00 储蓄:0 偏移:-32400000

    Etc/GMT+9 2013 年 3 月 10 日星期日 1:30:00 AM GMT-09:00 false

    Etc/GMT+9 2013 年 3 月 10 日星期日 2:00:00 AM GMT-09:00 false

    Etc/GMT+9 2013 年 3 月 10 日星期日 2:30:00 AM GMT-09:00 false

    TZ ID:Pacific/Gambier 显示:Gambier 节省时间:0 偏移量:-32400000

    太平洋/甘比尔 2013 年 3 月 10 日星期日凌晨 1:30:00 GAMT 错误

    太平洋/甘比尔 2013 年 3 月 10 日星期日凌晨 2:00:00 GAMT 错误

    太平洋/甘比尔 2013 年 3 月 10 日星期日凌晨 2:30:00 GAMT 错误

    TZ ID:SystemV/YST9 显示:阿拉斯加标准时间节省:0 偏移量:-32400000

    SystemV/YST9 2013 年 3 月 10 日星期日上午 1:30:00 AKST 错误

    SystemV/YST9 2013 年 3 月 10 日星期日 2:00:00 AM AKST 错误

    SystemV/YST9 2013 年 3 月 10 日星期日 2:30:00 AM AKST 错误

    TZ ID:SystemV/YST9YDT 显示:阿拉斯加标准时间节省:3600000 偏移量:-32400000

    SystemV/YST9YDT 2013 年 3 月 10 日星期日上午 1:30:00 AKST 错误

    SystemV/YST9YDT 2013 年 3 月 10 日星期日 2:00:00 AM AKST 错误

    SystemV/YST9YDT 2013 年 3 月 10 日星期日上午 2:30:00 AKST 错误

    TZ ID:美国/阿拉斯加显示:阿拉斯加标准时间节省:3600000 偏移量:-32400000

    美国/阿拉斯加 2013 年 3 月 10 日星期日凌晨 1:30:00 AKST 错误

    美国/阿拉斯加 2013 年 3 月 10 日星期日凌晨 3:00:00 AKDT 正确

    美国/阿拉斯加 2013 年 3 月 10 日星期日凌晨 3:30:00 AKDT 正确

    我还推荐http://www.worldtimeserver.com,因为它可以让您将您的结果与他们应该的结果进行比较。

    【讨论】:

    • 感谢您的意见,但我也尝试过使用日历,但我也遇到了同样的问题。我将使用我尝试过的一些日历代码来编辑我的原始问题。
    • 我不应该为每个时区进行自定义设置......这有点像 TimeZone 类,它为每个 TZ 提供偏移量和 DST 偏移量。但是这些偏移量似乎无法正常工作,所以我可能不得不为 TZ 制作一些特定的场景,比如 GMT 和 Alaska,这些场景不能正常工作。
    • 嗯.. 你的还不清楚,但我已尽力更新我的并添加了输出,所以除非你想修补,否则你不需要运行它。
    • 非常感谢您的帮助。我终于自己弄清楚了,但您的建议为我指明了正确的方向。
    猜你喜欢
    • 2019-04-06
    • 2015-06-07
    • 2012-07-23
    • 2011-04-17
    • 2016-02-19
    • 2019-05-06
    • 2017-02-08
    • 1970-01-01
    • 2015-01-06
    相关资源
    最近更新 更多