1小时时差夏令时问题

时间:2018-04-21 09:34:44

标签: java android datetime dst timezone-offset

将服务器日期转换为设备本地时间的功能:

public static String convertIntoLocalTime(String strTime, String whichTimeZone, String dateFormat) {
    String strLocalTime = null;
    try {
        SimpleDateFormat sdf = getSimpleDateFormat(dateFormat, whichTimeZone);
        Date date = sdf.parse(strTime);

        AppLog.e(TAG,"Timezone = " + whichTimeZone);
        AppLog.e(TAG,"Date = " + strTime);
        AppLog.e(TAG,"Date in CET = " + date.toString());
        AppLog.e(TAG,"inDaylightTime = " + sdf.getTimeZone().inDaylightTime(date));
        AppLog.e(TAG,"DST savings = " + sdf.getTimeZone().getDSTSavings());

        if (sdf.getTimeZone().getDSTSavings() == 3600000) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(Calendar.HOUR, 1);
            Date oneHourBack = cal.getTime();

            SimpleDateFormat local = getLocalSimpleDateFormat(dateFormat);
            strLocalTime = local.format(oneHourBack);
        } else {
            SimpleDateFormat local = getLocalSimpleDateFormat(dateFormat);
            strLocalTime = local.format(date);
        }
    } catch (ParseException e) {
        AppLog.e(TAG, e.getMessage(), e);
    }

    AppLog.e(TAG,"Local Time = " + strLocalTime);
    return strLocalTime;
}

获取简单日期格式的功能:

private static SimpleDateFormat getSimpleDateFormat(String format, String tz) {
        TimeZone timeZone = TimeZone.getTimeZone(tz);
        timeZone.useDaylightTime();

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, Locale.getDefault());
        simpleDateFormat.setTimeZone(timeZone);
        return simpleDateFormat;
    }

获取本地设备转换的简单日期格式的功能:

/**
     * @param format
     * @return
     */
    private static SimpleDateFormat getLocalSimpleDateFormat(String format) {
        TimeZone timeZone = TimeZone.getDefault();
        timeZone.useDaylightTime();

        SimpleDateFormat localSdf = new SimpleDateFormat(format, Locale.getDefault());
        localSdf.setTimeZone(timeZone);
        return localSdf;
    }

输出:

  

日期= 2018-04-22 14:30

     

CET日期=太阳4月22日13:30:00 GMT + 01:00 2018

     

inDaylightTime = true

     

DST节省= 3600000

     

当地时间= 2018-04-22 14:30

上面的代码在之前工作得非常好,例如我们在4月1日有一个正确显示时间的事件,但是从4月21日开始,它显示了额外的1小时时间。

我曾尝试使用UTC和CET转换来自服务器的日期,但在这两种情况下,当它转换为设备本地时间时,它会向我显示额外的一小时。

以上示例基于伦敦时区,而当我们在IST时区尝试时,它返回了正确的时间。

我们通过查看inDaylightTime时区功能来处理DST时间不同,但它无效。

我确信有与DST有关的东西,但我无法弄清楚。谢谢你的帮助?

2 个答案:

答案 0 :(得分:1)

首先,您使用的是旧的和过时的日期和时间类:SimpleDateFormatDateCalendarTimeZone。这些都因设计糟糕而且有时候很麻烦而闻名。我的第一个建议是使用现代Java日期和时间API java.time重写代码。它的错误要少得多,我希望您能更轻松地开发出正确的代码。

尽管如此,无论你是使用老式课还是现代课,都不要自己处理夏令时。图书馆课程将为您完成。你的工作是让时区正确。不要增加或减少一小时来弥补夏令时。看看有关从一个时区转换到另一个时区的其他问题,有很多。

请勿使用三个和四个字母的时区缩写。 CET不是时区。 IST含糊不清,可能意味着爱尔兰夏令时,以色列标准时间或印度标准时间。欧洲冬季使用CET的国家自2018年3月26日起使用CEST(中欧夏季时间)。

如果这是服务器时区,则将服务器时区指定为 continent / city ,例如Europe/London。这是毫不含糊的。

还要确保将设备时区设置为真正的时区。看来你已经将它设置为GMT + 01:00,这是GMT偏移,而不是时区。它同意欧洲/伦敦时区和冬季的CET,但不是在3月26日之后。

最后,您向<{1}}添加 1小时,向前转1小时,然后拨打Calendar从中获取Date oneHourBack。这看起来不错。你的意思是减去1小时,还是你的意思是变量应该是oneHourForward

编辑:我可能还没有确切地知道哪些时区对你来说是正确的,因此不是你的代码的正确输出。因此,请将以下内容仅作为您想要完成的内容的猜测。请填写正确的时区。

public static String convertIntoLocalTime(
        String strTime, String serverTimeZone, String dateFormat) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
    ZonedDateTime serverDateTime = LocalDateTime.parse(strTime, formatter)
            .atZone(ZoneId.of(serverTimeZone));

    AppLog.e(TAG, "Server timezone = " + serverTimeZone);
    AppLog.e(TAG, "Date = " + strTime);
    AppLog.e(TAG, "Date in server timezone = " + serverDateTime.toString());

    ZonedDateTime deviceTime = serverDateTime
            .withZoneSameInstant(ZoneId.systemDefault());
    String strLocalTime = deviceTime.format(formatter);

    AppLog.e(TAG, "Device Time = " + deviceTime);
    AppLog.e(TAG, "Local Time = " + strLocalTime);

    return strLocalTime;
}

我尝试将我的时区设置为欧洲/伦敦并发出以下呼叫:

    convertIntoLocalTime("2018-04-22 14:30", "Europe/Berlin", "yyyy-MM-dd HH:mm")

我得到的输出是:

Server timezone = Europe/Berlin
Date = 2018-04-22 14:30
Date in server timezone = 2018-04-22T14:30+02:00[Europe/Berlin]
Device Time = 2018-04-22T13:30+01:00[Europe/London]
Local Time = 2018-04-22 13:30

问题:我可以在Android上使用java.time吗?

是的,java.time适用于较旧和较新的Android设备。它只需要至少Java 6

  • 在Java 8及更高版本和更新的Android设备上(来自API级别26,我被告知)现代API内置。
  • 在Java 6和7中获取ThreeTen Backport,新类的后端端口(适用于JSR 310的ThreeTen;请参阅底部的链接)。
  • On(较旧)Android使用Android版的ThreeTen Backport。它被称为ThreeTenABP。并确保使用子包从org.threeten.bp导入日期和时间类。

链接

答案 1 :(得分:0)

我没有经过测试,所以先尝试一下。

 public  String convertIntoLocalTime(String strTime, String whichTimeZone, String dateFormat) {
    String strLocalTime = null;
    strLocalTime=convertDateToUserTimeZone(strTime,whichTimeZone,dateFormat);


    return strLocalTime;
}



public String convertDateToUserTimeZone(String strTime, String whichTimeZone, String dateFormat) {
    String ourdate;
    try {
        SimpleDateFormat formatter = new SimpleDateFormat(dateFormat, Locale.UK);
        formatter.setTimeZone(TimeZone.getTimeZone(whichTimeZone));
        Date value = formatter.parse(strTime);
        TimeZone timeZone = TimeZone.getTimeZone("Asia/Kolkata");
        SimpleDateFormat dateFormatter = new SimpleDateFormat(dateFormat, Locale.UK); //this format changeable
        dateFormatter.setTimeZone(timeZone);
        ourdate = dateFormatter.format(value);

        //Log.d("OurDate", OurDate);
    } catch (Exception e) {
        ourdate = "00-00-0000 00:00";
    }
    return ourdate;
}