Android 将字符串转换为日期会在不同的设备上生成不同的结果
例如,我正在以Android 将字符串转换为日期会在不同的设备上生成不同的结果,android,timezone,date-parsing,Android,Timezone,Date Parsing,例如,我正在以2018-09-20T17:00:00Z的形式检索名为date的字符串,并使用 SimpleDateFormat dateConvert = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'", Locale.US); convertedDate = new Date(); try { convertedDate = dateConvert.parse(date); } catch (ParseException e) {
2018-09-20T17:00:00Z
的形式检索名为date
的字符串,并使用
SimpleDateFormat dateConvert = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'", Locale.US);
convertedDate = new Date();
try {
convertedDate = dateConvert.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
然而,在不同的设备上,我得到了不同的结果。有人给出了2018年10月20日星期四英国夏令时17:00:00(英国夏季时间,相当于格林尼治标准时间+01:00),但后来证明这有问题。是否有办法确保按照GMT偏移量(即GMT+01:00而不是BST)格式化日期?您只是在执行两步流程中的第1步:
date
对象SimpleDateFormat
获取解析后的Date
对象和format
格式李>
那么,您已经正确地完成了第一步,下面是您必须对第二步执行的操作,请尝试以下操作:
final String formattedDateString = new SimpleDateFormat("EEE MMM dd HH:mm:ss 'GMT'XXX yyyy").format(convertedDate);
您只需执行两步流程中的第1步:
date
对象SimpleDateFormat
获取解析后的Date
对象和format
格式李>
那么,您已经正确地完成了第一步,下面是您必须对第二步执行的操作,请尝试以下操作:
final String formattedDateString = new SimpleDateFormat("EEE MMM dd HH:mm:ss 'GMT'XXX yyyy").format(convertedDate);
java.time
即时
(就像日期
)表示独立于时区的时间点。所以你很好。作为额外的奖励,您的2018-09-20T17:00:00Z
字符串暂时采用ISO 8601格式,因此instant
类无需指定格式即可对其进行解析
编辑:在英国夏季将其格式化为人类可读的字符串,使用明确的UTC偏移量,例如:
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
ZonedDateTime dateTime = convertInstant.atZone(ZoneId.of("Europe/London"));
String formatted = dateTime.format(formatter);
System.out.println(formatted);
此代码段已打印:
2018年9月20日星期四18:00:00+0100
18:00是偏移量+01:00处的正确时间。原始字符串末尾的Z
表示偏移量为零,也称为“祖鲁时区”,偏移量为零处的17与偏移量+01:00处的18:00是同一时间点。我从您自己的答案中接管了格式模式字符串
编辑2
我想根据您自己的答案向您提出我的建议,重新编写Fixture
类:
public class Fixture implements Comparable<Fixture> {
private static DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
public Instant date;
/** @param date Date string from either web service or persistence */
public Fixture(String date) {
this.date = Instant.parse(date);
}
/** @return a string for persistence, e.g., Firebase */
public String getDateForPersistence() {
return date.toString();
}
/** @return a string for the user in the default time zone of the device */
public String getFormattedDate() {
return date.atZone(ZoneId.systemDefault()).format(formatter);
}
@Override
public int compareTo(Fixture other) {
return date.compareTo(other.date);
}
@Override
public String toString() {
return "Fixture [date=" + date + "]";
}
}
当我在欧洲/伦敦时区运行此片段时,我得到:
Date for user: Mon Sep 24 12:30:00 +0100 2018
Date for Firebase: 2018-09-24T11:30:00Z
因此,用户可以按照您的要求,使用自己的UTC偏移量获取日期和时间。在欧洲/柏林时区尝试相同的片段:
Date for user: Mon Sep 24 13:30:00 +0200 2018
Date for Firebase: 2018-09-24T11:30:00Z
我们看到德国的用户被告知比赛时间是13:30,而不是12:30,这与他或她的时钟一致。要在Firebase中持久化的日期保持不变,这也是您想要的
你的代码出了什么问题
格式模式字符串中有两个错误,yyyy-MM-dd'T'hh:MM:ss'Z'
:
- 小写的
表示从01到12的AM或PM内的小时,并且只有AM/PM标记才有意义。在实践中,您将得到正确的结果,除非解析12小时,这将被理解为00hh
- 通过将
解析为文本,您不会从字符串中获得UTC偏移量信息。相反,Z
将使用JVM的时区设置。这一点在不同的设备上明显不同,并解释了为什么在不同的设备上会得到不同且相互冲突的结果SimpleDataFormat
Date.toString
的特殊行为:此方法获取JVM的时区设置并使用它生成字符串。因此,当一台设备设置为欧洲/伦敦,另一台设备设置为GMT+01:00时,相同的Date
对象将在这些设备上以不同方式呈现。这种行为使许多人感到困惑
问题:我可以在Android上使用java.time吗?
是的,java.time
在较旧和较新的Android设备上运行良好。它至少需要Java6
- 在Java8和更高版本以及更新的Android设备上(我听说是API级别26),现代API是内置的
- 在Java6和Java7中,获取三个后端口,即新类的后端口(三个用于JSR310;请参阅底部的链接)。上面的代码是用
从后台开发和运行的org.threeten.bp.Duration
- 在(较旧的)Android上使用Android版本的ThreeTen Backport。它叫ThreeTenABP。并确保从带有子包的
导入日期和时间类org.threeten.bp
- 解释如何使用
java.time
- ,其中首先描述了
java.time
- ,java.time的后端口到Java6和Java7(JSR-310为三十)
- ,Android版Three Ten Backport
- ,解释得非常透彻
即时
(就像日期
)表示独立于时区的时间点。所以你很好。作为额外的奖励,您的2018-09-20T17:00:00Z
字符串暂时采用ISO 8601格式,因此instant
类无需指定格式即可对其进行解析
编辑:在英国夏季将其格式化为人类可读的字符串,使用明确的UTC偏移量,例如:
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
ZonedDateTime dateTime = convertInstant.atZone(ZoneId.of("Europe/London"));
String formatted = dateTime.format(formatter);
System.out.println(formatted);
此代码段已打印:
2018年9月20日星期四18:00:00+0100
18:00是偏移量+01:00处的正确时间。原始字符串末尾的Z
表示偏移量为零,也称为“祖鲁时区”,偏移量为零处的17与偏移量+01:00处的18:00是同一时间点。我从您自己的答案中接管了格式模式字符串
编辑2
我想根据您自己的答案向您提出我的建议,重新编写Fixture
类:
public class Fixture implements Comparable<Fixture> {
private static DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
public Instant date;
/** @param date Date string from either web service or persistence */
public Fixture(String date) {
this.date = Instant.parse(date);
}
/** @return a string for persistence, e.g., Firebase */
public String getDateForPersistence() {
return date.toString();
}
/** @return a string for the user in the default time zone of the device */
public String getFormattedDate() {
return date.atZone(ZoneId.systemDefault()).format(formatter);
}
@Override
public int compareTo(Fixture other) {
return date.compareTo(other.date);
}
@Override
public String toString() {
return "Fixture [date=" + date + "]";
}
}
当我在欧洲/伦敦时区运行此片段时,我得到:
Date for user: Mon Sep 24 12:30:00 +0100 2018
Date for Firebase: 2018-09-24T11:30:00Z
因此,用户可以按照您的要求,使用自己的UTC偏移量获取日期和时间。正在用欧元尝试相同的代码片段