我从这样的XML文件中获得带有UTC时间戳的字符串:
2019-05-24T00:59:55.1-05:00
我使用以下方法将字符串转换为日期。
private Date getUTC2JavaDateB(String dateStr) {
String dateS = dateStr;
String timePattern = "";
Date d = null;
SimpleDateFormat formatter = null;
if (dateS.length() >= 19) {
dateS = dateS.substring(0, 19);
}
timePattern = "yyyy-MM-dd'T'hh:mm:ss";
formatter = new SimpleDateFormat(timePattern);
d = formatter.parse(dateS, new ParsePosition(0));
return d;
}
现在这是我的问题。我想将其从UTC转换为当地时间。
我在其他一些线程中发现了一些代码片段,但它们对我而言仍然无效。
private Date toLocalTimeStamp(Date date) {
try {
DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
DateFormat currentTFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
currentTFormat.setTimeZone(TimeZone.getTimeZone(getCurrentTimeZone()));
return currentTFormat.format(date);
} catch (Exception ex) {
return date;
}
}
我得到一个异常“字符串不能转换为日期”-这对我来说很清楚。但是,现在如何将字符串转换为日期?我将UTC转换为本地日期的方法正确吗?
任何帮助将不胜感激! :-)
答案 0 :(得分:1)
import org.threeten.bp.OffsetDateTime;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZonedDateTime;
public class ConvertUtcDateTimeToLocalInJava16 {
public static void main(String[] args) {
String dateStr = "2019-05-24T00:59:55.1-05:00";
OffsetDateTime dateTime = OffsetDateTime.parse(dateStr);
ZonedDateTime dateTimeInMyTimeZone
= dateTime.atZoneSameInstant(ZoneId.systemDefault());
System.out.println(dateTimeInMyTimeZone);
}
}
我在Java 1.7.0_67上运行了该程序。输出为:
2019-05-24T07:59:55.100 + 02:00 [欧洲/哥本哈根]
我自己没有安装Java 1.6,但是至少运行该程序证明它不需要Java 1.8。我敢声称它也可以在Java 1.6上运行。您只需要在您的项目中添加ThreeTen Backport。使用底部的链接。
ThreeTen Backport是Java.time(现代Java日期和时间API)到Java 6和7的反向移植。
我正在利用您的日期时间字符串为ISO 8601格式的事实,该格式是java.time中的类将其解析为默认格式(并打印)的格式。如您所知,字符串末尾的-05:00
是UTC偏移量,表示比UTC落后5小时(因此您的时间00:59:55.1对应于05:59:55.1 UTC)。
即使在Java 1.6上,也不需要使用Date
和SimpleDateFormat
。这些类的设计总是很差,尤其是后者特别麻烦。因此,请考虑不使用它们。
ZoneId.systemDefault()
为您提供了JVM的时区设置。这应该是您要求的“本地时区”,但它很脆弱,因为可以随时通过程序的另一部分或在同一JVM中运行的任何其他程序来更改设置。如果您有一种了解正确时区的方法,则最好明确地指定它。例如:
ZonedDateTime dateTimeInMyTimeZone
= dateTime.atZoneSameInstant(ZoneId.of("Africa/Algiers"));
2019-05-24T06:59:55.100 + 01:00 [非洲/阿尔及尔]
首先,我怀疑您的期望是错误的。您的两种转换方法均返回Date
,但是Date
不能具有时区,因此将毫无用处。 Date
是一个时间点,仅此而已。与Date
相反,java.time提供了一个带有UTC偏移量的日期和时间OffsetDateTime
和一个带有时区的日期和时间ZonedDateTime
。
格式模式字符串中的小写hh
不正确。它是从01到12的AM或PM内的一个小时。字符串中的小时是从00到23的24小时制。为此,您需要像第二种方法那样使用大写HH
。
接下来,您将不会从字符串中解析UTC偏移量,因此可能会得到错误的时间(在这种情况下,SimpleDateFormat
使用默认时区)。您还忽略了小数(在示例中为.1
)是一个细节,引入了小于一秒的错误。无论如何,SimpleDateFormat
不可能正确地在秒上解析一个十进制数(它仅支持精确的三个十进制数)。
java.time
。java.time
向Java 6和7(JSR-310的ThreeTen)的反向端口。答案 1 :(得分:0)
您的字符串上已经有一个时区指示符。如果由于某种原因而坚持使用Java 6(请参阅my comment),则可以使用SimpleDateFormat
轻松地稍稍更新字符串,然后解析包括时区在内的整个字符串:
// Remove the colon in the timezone indicator
assert str.charAt(str.length() - 3) == ':';
str = str.substring(0, str.length() - 3) + str.substring(str.length() - 2);
// Parse the result
Date dt = (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).parse(str);
答案 2 :(得分:0)
如果您不熟悉Java 6并且没有更新的时间处理库(Joda Time,310 backport等)...
您要解析的日期是ISO-8601格式的,这是XML DateTime数据类型使用的格式。
JAXB实现附带的Java 6提供了许多XML处理工具,包括解析ISO 8601日期类型。这里特别令人感兴趣的是GregorianXMLCalendar
所以这会给你一个java.util.Date
:
java.util.Date date = DatatypeFactory.newInstance()
.newXMLGregorianCalendar("2019-05-24T00:59:55.1-05:00")
.toGregorianCalendar()
.getTime()
然后您将能够在您感兴趣的区域中显示和格式化...
// What is the UTC hour of 00:59:55.1 at -5 offset ?
SimpleDateFormat utc = new SimpleDateFormat("HH:mm");
utc.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(utc.format(date)); // --> 05:59
// What would it be in Paris ?
SimpleDateFormat paris = new SimpleDateFormat("HH:mm");
paris.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));
System.out.println(paris.format(date)); // -> 07:59 Paris is UTC+2 in the summer, so it's OK.