不要认为java.sql.Timestamp 是java.util.Date 的子类
虽然java.sql.Timestamp 在技术上确实继承自java.util.Date,但课程文档的最后一段声明您不应该这样认为,您应该忽略这一事实。
由于上面提到的 Timestamp 类和 java.util.Date 类之间的差异,建议代码不要将 Timestamp 值一般视为 java.util.Date 的实例。 Timestamp 和 java.util.Date 的继承关系实际上是实现继承,而不是类型继承。
换句话说,这个类结构是一个笨拙的 hack。早期 Java 中的日期时间类很仓促,没有经过深思熟虑。
转换的一个问题是java.sql.Timestamp有纳秒的分辨率,而java.util.Date只有毫秒,所以数据会丢失。
请注意,Vaadin 在 SQLContainer 支持 Grid(并且可能是 Table)时犯了这个错误。 SQLContainer 中的 java.sql.Timestamp 列被视为 java.util.Date(超类),因此如果涉及微秒或纳秒,则会丢失数据。 (请参阅下面的转换器实现作为解决方法。)
java.time
Java 8 及更高版本中的新java.time package 是对那些旧类的重新思考,是从头开始的重新设计。这些新类的灵感来自Joda-Time,由JSR 310 定义,并由ThreeTen-Extra project 扩展。
java.time 类是为纳秒级分辨率而构建的。因此在 java.time.Instant 和 java.sql.Timestamp 之间转换时不会丢失数据。
新旧日期时间类都有在新旧之间来回转换的方法。注意下面调用的java.sql.Timestamp::toInstant 和Timestamp.from( instant ) 方法。
java.time.Instant ↔ java.sql.Timestamp 字符串的转换器
这个例子可能会也可能不会帮助回答这个问题。我正在将 java.sql.Timestamp 数据转换为 java.time.Instant 的字符串。
除了文本格式,请记住我的转换器和默认转换器之间有一个大区别:没有数据丢失! (参见上面的讨论)这个示例屏幕截图发生没有任何小数秒。但如果它确实有微秒或纳秒,则该数据将被保留并根据需要显示。
这里有一些代码对从 java.sql.Timestamp 转换而来的 Instant 进行字符串表示。换句话说:
-
Presentation: 字符串(使用ISO_INSTANT 格式化程序的即时)
-
型号: java.sql.Timestamp
此代码是从与 Vaadin 7 捆绑的 com.vaadin.data.util.converter.StringToDateConverter 类的 source code 修改而来的。
这段代码对我有用,可以在 Grid 中的 Vaadin 7.5.2 中显示 SQLContainer 对象的 java.sql.Timestamp 列。我还没有尝试过Table,但也应该在那里工作。
在为我工作时,此代码可能需要进行一些清理。特别是,(a) cmets 可能是错误的,并且 (b) 我已经调用了 SLF4J 日志记录,您可能需要更改/删除。
默认的ISO 8601 格式对人类来说有点难以阅读,所以我正在寻找一种替代方法来更改格式和调整时区。
要使用此类,您必须在 Grid.Column 对象上调用 setConverter。或者按照this wiki page 中的说明配置ConverterFactory。
package com.powerwrangler.util;
import com.vaadin.data.util.converter.Converter;
import java.text.DateFormat;
import java.time.format.DateTimeParseException;
import java.sql.Timestamp;
import java.util.Locale;
import java.time.Instant;
import org.slf4j.LoggerFactory;
/**
*
* Converts java.sql.Date objects for presentation as String in format of a java.time.Instant object.
*
* String format by default is DateTimeFormatter.ISO_INSTANT, such as '2011-12-03T10:15:30Z'.
*
* Based on code from Vaadin’s bundled StringToDateConverter.java
*
* PRESENTATION: String (of an Instant)
*
* MODEL: java.sql.Date
*
* @author Basil Bourque.
*
* This code is derived from the com.vaadin.data.util.converter.StringToDateConverter class bundled with Vaadin 7.
* That original class was published with this Copyright:
*
* Copyright 2000-2014 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
public class StringOfInstantToSqlTimestampConverter implements Converter<String , Timestamp>
{
// Member vars.
final org.slf4j.Logger logger = LoggerFactory.getLogger( this.getClass() );
/**
* Returns the format used by {@link #convertToPresentation(Date, Class,Locale)} and
* {@link #convertToModel(String, Class, Locale)}.
*
* @param locale The locale to use
*
* @return A DateFormat instance
*/
protected DateFormat getFormat ( Locale locale ) {
if ( locale == null ) {
locale = Locale.getDefault();
}
DateFormat f = DateFormat.getDateTimeInstance( DateFormat.MEDIUM , DateFormat.MEDIUM , locale );
f.setLenient( false );
return f;
}
/*
* (non-Javadoc)
*
* @see com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, java.lang.Class, java.util.Locale)
*/
@Override
public Timestamp convertToModel ( String value , Class<? extends Timestamp> targetType , Locale locale )
throws com.vaadin.data.util.converter.Converter.ConversionException {
if ( targetType != getModelType() ) {
throw new Converter.ConversionException( "Converter only supports "
+ getModelType().getName() + " (targetType was "
+ targetType.getName() + ")" );
}
if ( value == null ) {
return null;
}
// Remove leading and trailing white space
String trimmed = value.trim();
// ParsePosition parsePosition = new ParsePosition( 0 );
// Date parsedValue = this.getFormat( locale ).parse( trimmed , parsePosition );
// if ( parsePosition.getIndex() != trimmed.length() ) {
// throw new Converter.ConversionException( "Could not convert '" + trimmed + "' to " + getModelType().getName() );
// }
Instant instant = null;
try {
instant = Instant.parse( trimmed ); // Uses DateTimeFormatter.ISO_INSTANT.
} catch ( DateTimeParseException e ) {
throw new Converter.ConversionException( "Could not convert '" + trimmed + "' to java.time.Instant on the way to get " + getModelType().getName() );
}
if ( instant == null ) {
logger.error( "The instant is null after parsing. Should not be possible. Message # ACE6DA4E-44C8-434C-A2AD-F946E5CFAEFD." );
throw new Converter.ConversionException( "The Instant is null after parsing while attempting to convert '" + trimmed + "' to java.time.Instant on the way to get " + getModelType().getName() + "Message # 77A767AB-7D42-490F-9C2F-2775F4443A8D." );
}
Timestamp parsedValue = Timestamp.from( instant );
return parsedValue;
}
/*
* (non-Javadoc)
*
* @see com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang .Object, java.lang.Class,
* java.util.Locale)
*/
@Override
public String convertToPresentation ( Timestamp value , Class<? extends String> targetType , Locale locale )
throws com.vaadin.data.util.converter.Converter.ConversionException {
if ( value == null ) {
return null;
}
Instant instant = value.toInstant();
String dateTimeStringInIsoFormat = instant.toString(); // Uses DateTimeFormatter.ISO_INSTANT.
return dateTimeStringInIsoFormat;
//return getFormat( locale ).format( value );
}
/*
* (non-Javadoc)
*
* @see com.vaadin.data.util.converter.Converter#getModelType()
*/
@Override
public Class<Timestamp> getModelType () {
return Timestamp.class;
}
/*
* (non-Javadoc)
*
* @see com.vaadin.data.util.converter.Converter#getPresentationType()
*/
@Override
public Class<String> getPresentationType () {
return String.class;
}
}