我有一个DateAdapter
public class DateAdapter extends XmlAdapter<String, Date> {
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
@Override
public String marshal(Date v) throws Exception {
synchronized (dateFormat) {
return dateFormat.format(v);
}
}
@Override
public Date unmarshal(String v) throws Exception {
synchronized (dateFormat) {
return dateFormat.parse(v);
}
}
}
因此,当将字符串传输到日期时,我输入“ 2009-12-31T23:59:59.999 +0000”
但是,当尝试从日期解析为字符串-> 2010-01-01T02:59:59.999 +0300(小时数和时区也发生了变化)
那么,如何禁用时间传输?
答案 0 :(得分:1)
始终使用 java.time 类,绝不要使用诸如java.util.Date
之类的可怕的旧类。要进行互操作,请转换。
我怀疑您实际上打算使用标准的ISO 8601格式,例如2009-12-31T23:59:59.999Z
。
请勿被Date::toString
中的反功能绊倒,该功能会动态将时区应用于UTC实际值。
java.time 类是通过thread-safe设计的immutable objects。因此,不需要synchronized
调用。
public class DateAdapter extends XmlAdapter< String, Date > {
@Override
public String marshal( Date v ) throws Exception { // `Instant` generates standard ISO 8601 strings by default. No need to specify a formatting pattern.
return v.toInstant().toString() ; // Convert from legacy `Date` to modern `Instant`.
}
@Override
public Date unmarshal( String v ) throws Exception { // `Instant` parses standard ISO 8601 strings by default. No need to specify a formatting pattern.
return java.util.Date.from( Instant.parse( v ) ) ; // Convert from modern `Instant` to legacy `Date`.
}
}
您的输入字符串接近标准ISO 8601格式。我强烈建议尽可能使用该标准。在从UTC偏移之前省略SPACE。
而且,最好在小时和分钟之间的偏移量中包含COLON-虽然在标准中是可选的,但某些库希望使用该字符。
String input = "2009-12-31T23:59:59.999+00:00" ;
顺便说一句,从UTC偏移量为零的常见缩写是字母Z
,发音为“ Zulu”。
String input = "2009-12-31T23:59:59.999Z" ;
您正在使用与最早的Java版本捆绑在一起的可怕的日期时间类。这些遗留类完全由 java.time 类取代。
选中see if your libraries have been updated to work with java.time。如果没有,您可以通过调用添加到旧类中的新方法来回转换。
java.util.Date
对象是一个时刻,是UTC时间轴上的一点。现在由java.time.Instant
类代替。
Instant instant = myJavaUtilDate.toInstant() ; // Convert by calling new method added to the old class.
要使用Z
生成标准格式的字符串,只需调用toString
。
String output = instant.toString() ;
使用Instant.parse
可以很容易地解析标准格式的字符串。无需指定格式设置模式。
Instant instant = Instant.parse( "2009-12-31T23:59:59.999Z" ) ;
使用添加到旧类中的另一种新方法进行转换。
java.util.Date d = java.util.Date.from( instant ) ;
如果无法更改为使用标准ISO 8601文本格式,请使用DateTimeFormatter
对象来解析并生成其他格式的字符串。搜索堆栈溢出,因为已经有很多次了。
Date::toString
说谎请注意, java.util.Date::toString
是您的谎言。该方法动态地应用JVM的当前默认时区。内部值以UTC表示,但是此方法以其他方式报告。尽管有很好的意图,但这种反功能并未引起Java程序员的困惑和痛苦。相反, java.time 类直接报告其值,而无需进行此类自以为是的注入。
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。
答案 1 :(得分:0)
我认为您的系统将时区设置为系统时区。对于输出,您可以使用没有时区的另一个SimpleDateFormat
,即
private final SimpleDateFormat noTimeZoneDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
如果根本不需要时区,也可以使用此日期格式进行输入
答案 2 :(得分:0)
您得到的结果是绝对正确的(但显然不是您想要的)。它与您解析的时间完全相同,只是表示方式不同。如何记录给定时刻的时间不计其数,有不计其数的字符串,其中一个参数是首选时区。
您似乎生活在+0300时区中,因此无论输入时区是什么,SimpleDateFormat
都愿意根据该时区来代表任何给定的Date
。
如果您不仅要保留原始时间,还要保留有关源表示的信息(包括指定的时区),那么Date
不能建模(除非您想使用API的过时,不推荐使用的部分),则您必须寻找其他表示形式类。
使用Date
和SimpleDateFormat
,SimpleDateFormat
的属性决定结果的表示形式,一个属性是格式字符串,另一个属性是首选时区。您可以通过在setTimeZone()
实例上调用SimpleDateFormat
来设置后者。这样,您可以决定在格式化时使用哪个(固定)时区,例如您要根据UTC表示所有日期。