1小时时差夏令时问题
Posted
技术标签:
【中文标题】1小时时差夏令时问题【英文标题】:1 hour time difference daylight saving time issue 【发布时间】:2018-10-01 22:05:47 【问题描述】:将服务器日期转换为设备本地时间的功能:
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 日期 = 2018 年 4 月 22 日星期日 13:30:00 GMT+01:00 2018
inDaylightTime = true
DST 节省 = 3600000
当地时间 = 2018-04-22 14:30
上面的代码之前运行得非常好,例如,我们在 4 月 1 日有 1 个事件正确显示时间,但从 4 月 21 日开始,它显示了额外的 1 小时时间。
我尝试使用 UTC 和 CET 转换来自服务器的日期,但在这两种情况下,当将其转换为设备本地时间时,它都会显示额外的一小时。
以上示例基于伦敦时区,而当我们在 IST 时区尝试时,它返回了正确的时间。
我们通过检查时区的inDaylightTime
函数处理了不同的 DST 时间,但它不起作用。
我确信有些东西与 DST 相关,但我无法弄清楚。感谢您的帮助?
【问题讨论】:
欢迎来到 SO。请查看此处了解如何改进您的问题(格式化、校对、提供代码等):***.com/help/how-to-ask 好的。谢谢会检查。 @JahanviKariya 我认为你需要使用github.com/dlew/joda-time-android 因为android Calendar 有一些错误 @VishalThakkar 这很奇怪,您对这些错误有任何了解吗?我的意思是任何参考链接来验证这一点,因为我在 ios Swift 3 上也遇到了同样的问题。 @JahanviKariya ***.com/questions/44346152/… 【参考方案1】:首先,您使用的是旧的和过时的日期和时间类:SimpleDateFormat
、Date
、Calendar
和 TimeZone
。这些以设计不佳而闻名,有时使用起来很麻烦。我的第一个建议是您使用现代 Java 日期和时间 API java.time
重写您的代码。它的错误要少得多,我希望您能更轻松地开发出正确的代码。
也就是说,无论您使用老式课程还是现代课程,都不要自己处理暑期课程。图书馆课程将为您完成。你的工作是让时区正确。不要增加或减少一个小时来补偿夏季时间。看看其他关于从一个时区转换到另一个时区的问题,有很多。
不要使用三个和四个字母的时区缩写。 CET 不是时区。 IST 是模棱两可的,它可能表示爱尔兰夏令时间、以色列标准时间或印度标准时间。冬季使用 CET 的欧洲国家自 2018 年 3 月 26 日起使用 CEST(中欧夏令时)。
如果这是服务器时区,请将服务器时区指定为 continent/city,例如 Europe/London
。这是明确的。
还要确保将您的设备时区设置为真实时区。似乎您已将其设置为 GMT+01:00,这是 GMT 偏移量,而不是时区。它与欧洲/伦敦时区和冬季的 CET 一致,但不是在 3 月 26 日之后。
最后,您将 添加 1 小时到您的 Calendar
,将其向前 1 小时,然后调用您从它获得的 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。
org.threeten.bp
导入日期和时间类以及子包。
链接
List of tz database time zones Oracle tutorial: Date Time 解释如何使用java.time
。
Java Specification Request (JSR) 310,其中首次描述了 java.time
。
ThreeTen Backport project,java.time
到 Java 6 和 7(JSR-310 的 ThreeTen)的反向移植。
ThreeTenABP,Android 版 ThreeTen Backport
Question: How to use ThreeTenABP in Android Project,解释得很透彻。
【讨论】:
【参考方案2】:我没有经过测试,所以先试试吧。
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;
【讨论】:
以上是关于1小时时差夏令时问题的主要内容,如果未能解决你的问题,请参考以下文章