gpt4 book ai didi

android - Android设备错误地解析了服务器中的日期时间

转载 作者:可可西里 更新时间:2023-11-01 16:54:19 25 4
gpt4 key购买 nike

我正在开发一个应用程序,其中一部分是向服务器发出http请求,然后从头部解析服务器日期和时间。按以下方式进行:

//The format used here typically looks like this: "Tue, 08 Jul 2124 13:34:21 GMT-8"
final SimpleDateFormat serverDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
String string = response.headers.get("Date"); // this is where we get the Date and Time value
Date date = serverDateFormat.parse(string); // this is where we parse that string into the Date format
long result = date.getTime(); // this is where we translate it into millisec format
Log.e(TAG,"Date in milliseconds: "+result);

注意,my SimpleDateFormat忽略解析字符串中的时区。这是保持原始服务器时间所必需的。如果我们分析时区, Date变量将自动将时间调整到设备的时区(因此,如果他得到格林尼治标准时间21点,并且设备的时区是格林尼治标准时间2,那么输出将是19点)。
现在这在我用过的一些设备上运行得很好…除了一个。它总是产生一个比输入大一两个小时的结果(所以当服务器时间是21点时,函数将返回22点或23点)。由于设备不属于我,而且,就这一点而言,它处于完全不同的状态,所以我很难获得logcat。
老实说,这个问题对我来说没什么意义。我甚至想不出一个可能的原因,使时间不一致关闭一台设备。
如果这有什么不同的话,设备规格如下:pixel xl,android 7.1.2,pst时区。应用程序在nexus 5x(7.1.2,pst)、galaxy s4(6.0.1,cst)、galaxy s7(7.1.2,cst)上进行了测试,结果都是正确的。
如果有人知道可能的原因,我很感激你的回答!

最佳答案

正如@Matt's answer中所解释的,忽略偏移量(gmt-8)并不是一件好事,因为SimpleDateFormat将使用系统的默认时区-并且此时区在每个设备/环境中可能不同,并且您无法控制它。即使默认时区是正确的,它也可以更改,即使是在运行时,所以您不能假设它总是您所需要的。
示例:我的默认时区是America/Sao_Paulo,当前偏移量是-03:00(或GMT-3,或比UTC晚3小时)。如果我使用您的代码,它将假定它在圣保罗是13:34(在UTC中是16:34-毫秒值是4876130061000,这是错误的,因为它不等于原始输入(在GMT-8中是13:34)。
只有当我将默认时区更改为GMT-8时,代码才会给出正确的值。要不依赖于此,可以设置格式化程序的时区。
SimpleDateFormathas some patterns to parse timezone/offset,但它们都不能与GMT-8一起工作(它似乎只接受GMT-08:00),因此一种解决方案是从输入中删除它,并使用它为格式化程序设置正确的时区:

String input = "Tue, 08 Jul 2124 13:34:21 GMT-8";
String[] v = input.split(" GMT"); // split the string, before and after "GMT"
SimpleDateFormat serverDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss", Locale.ENGLISH);
// set the formatter timezone to the offset (in this case, to "GMT-8")
serverDateFormat.setTimeZone(TimeZone.getTimeZone("GMT" + v[1]));
// parse the date/time part
Date date = serverDateFormat.parse(v[0]);

日期毫秒值将是 4876148061000,相当于 2124-07-08T21:34:21Z(21:34 UTC=13:34,GMT-8)。
另一个细节是,当你这样做时:
System.out.println(date);

它调用 Date::toString方法,该方法获取millis值并转换为系统的默认时区,给人一种错误的印象,即日期对象具有时区- but that's wrong:日期只包含自 1970-01-01T00:00Z以来的毫秒数。
toString通常在调试器中看到日期时也会调用
如果要打印某些特定时区的等效日期和时间值,可以使用 SimpleDateFormat并在此格式化程序中设置所需的时区。使用 Date::toString总是误导您关于值的认识。
要使用服务器使用的相同偏移量打印日期/时间,可以创建 SimpleDateFormat并将 GMT-8设置为它,如下所示:
// display the date in a specific format
SimpleDateFormat outputFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
// use the same offset used by the server (GMT-8)
outputFormat.setTimeZone(TimeZone.getTimeZone("GMT-8"));
System.out.println(outputFormat.format(date)); // 08/07/2124 13:34:21

输出为:
2012年7月8日13:34:21
如果不指定时区,它将使用设备/系统的默认值,根据设备的配置给出不同的结果。
注意,我还使用 Locale.ENGLISH来解析输入。这是必需的,因为一周中的月和日都是英文的。如果我没有指定 java.util.Locale,格式化程序将使用系统的默认值,并且不能保证它总是英文的。这也可以在运行时更改,因此最好使用显式的,而不是依赖默认值。
Java新的日期/时间API
旧的类( DateCalendarSimpleDateFormat)有 lots of problemsdesign issues,它们正在被新的api替换。
在android中,您可以使用 ThreeTen Backport,这是java 8新的日期/时间类的一个很好的后台端口。要使其工作,您还需要 ThreeTenABP(有关如何使用它的更多信息)。
由于输入有日期、时间和偏移量,可以使用 org.threeten.bp.OffsetDateTime将其解析为 org.threeten.bp.format.DateTimeFormatter
一个细节是,7月8日2124是星期六,所以我不得不更改输入字符串,否则我会得到一个错误。 SimpleDateFormat没有给出这个错误,因为大家都知道它过于宽大,忽略了很多错误,并试图以不那么聪明的方式“修复”(这可能有点基于意见,但许多人认为这是一件坏事,这就是为什么新的api对此更加严格的原因)。
String input = "Sat, 08 Jul 2124 13:34:21 GMT-8";
DateTimeFormatter parser = DateTimeFormatter.ofPattern("EE, dd MMM yyyy HH:mm:ss O", Locale.ENGLISH);
OffsetDateTime odt = OffsetDateTime.parse(input, parser);

odt相当于 2124-07-08T13:34:21-08:00
不需要在格式化程序中设置时区,因为它可以正确地解析输入的偏移量。要获得millis值,只需执行以下操作:
// the same  value as date.getTime()
long millis = odt.toInstant().toEpochMilli();

要转换为 java.util.Date,可以使用 org.threeten.bp.DateTimeUtils类:
// convert to java.util.Date
Date date = DateTimeUtils.toDate(odt.toInstant());

要向用户显示,可以使用不同的 DateTimeFormatter。由于 OffsetDateTime保持正确的值,因此无需在格式化程序中设置时区:
// display date in a specific format
DateTimeFormatter outputFormat = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
System.out.println(odt.format(outputFormat)); // 08/07/2124 13:34:21

输出为:
2012年7月8日13:34:21
要转换到另一个时区或偏移量,可以使用类 org.threeten.bp.ZoneIdorg.threeten.bp.ZoneOffset
// convert to UTC
System.out.println(outputFormat.format(odt.withOffsetSameInstant(ZoneOffset.UTC)));
// convert to offset +05:00
System.out.println(outputFormat.format(odt.withOffsetSameInstant(ZoneOffset.ofHours(5))));
// convert to Europe/Berlin timezone
System.out.println(outputFormat.format(odt.atZoneSameInstant(ZoneId.of("Europe/Berlin"))));

输出为:
2012年7月8日21:34:21
2012年7月9日02:34:21
2012年7月8日23:34:21
注意,我使用了时区 Europe/Berlin
api使用 here(始终采用 Continent/City格式,如 America/Sao_PauloEurope/Berlin)。
避免使用3个字母的缩写(如 CSTPST),因为它们是 IANA timezones names
您可以使用 ZoneId.getAvailableZoneIds()获得所有可用时区的列表(并相应地选择)。

关于android - Android设备错误地解析了服务器中的日期时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45643745/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com