提交 2e4f8843 编写于 作者: S serge-rider

#9777 Add TimeZone property to stream imports


Former-commit-id: 8cb31d8b
上级 4325b564
......@@ -146,7 +146,11 @@ dataTransfer.producer.stream.processor.csv.property.emptyStringNull.description
dataTransfer.producer.stream.processor.csv.property.nullString.name = NULL value mark
dataTransfer.producer.stream.processor.csv.property.nullString.description = String literal used as NULL value mark. \nSuch strings will be converted into NULL during data import
dataTransfer.producer.stream.processor.csv.property.timestampFormat.name = Date/time format
dataTransfer.producer.stream.processor.csv.property.timestampFormat.description = Date/time format pattern. Use this to clarify the date format present\n in the data source, not to change output data
dataTransfer.producer.stream.processor.csv.property.timestampFormat.description = Date/time format pattern. Use this to clarify the date format in CSV file, not to change output data.\nSearch for 'java DateTimeFormatter' for format details.
dataTransfer.producer.stream.processor.csv.property.timestampZone.name = Timezone ID
dataTransfer.producer.stream.processor.csv.property.timestampZone.description = Timezone ID. By default local machine timezone is used.\n3 ways to specify zone:\n\t-Local zone offset (+3, -04:30)\n\t-Specific zone offset (GMT+2, UTC+01:00)\n\t-Region based (UTC, ECT, PST, etc)
task.category.name.common = Common
task.category.description.common = Common database tasks
task.name.export = Data export
......
......@@ -51,6 +51,7 @@
<property id="nullString" label="%dataTransfer.producer.stream.processor.csv.property.nullString.name" type="string" description="%dataTransfer.producer.stream.processor.csv.property.nullString.description" defaultValue="" required="false"/>
<property id="emptyStringNull" label="%dataTransfer.producer.stream.processor.csv.property.emptyStringNull.name" type="boolean" description="%dataTransfer.producer.stream.processor.csv.property.emptyStringNull.description" defaultValue="" required="false"/>
<property id="timestampFormat" label="%dataTransfer.producer.stream.processor.csv.property.timestampFormat.name" type="string" description="%dataTransfer.producer.stream.processor.csv.property.timestampFormat.description" defaultValue="yyyy-MM-dd[ HH:mm:ss[.SSS]]" required="false"/>
<property id="timestampZone" label="%dataTransfer.producer.stream.processor.csv.property.timestampZone.name" type="string" description="%dataTransfer.producer.stream.processor.csv.property.timestampZone.description" defaultValue="" required="false"/>
</propertyGroup>
</processor>
</node>
......
......@@ -28,6 +28,7 @@ import org.jkiss.utils.CommonUtils;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
......@@ -50,6 +51,7 @@ public class StreamTransferResultSet implements DBCResultSet {
private Object[] streamRow;
private final List<StreamDataImporterColumnInfo> attributeMappings;
private DateTimeFormatter dateTimeFormat;
private ZoneId dateTimeZoneId;
public StreamTransferResultSet(DBCSession session, DBCStatement statement, StreamEntityMapping entityMapping) {
this.session = session;
......@@ -97,6 +99,14 @@ public class StreamTransferResultSet implements DBCResultSet {
value = java.util.Date.from(zdt.toInstant());
} catch (Exception e) {
LocalDateTime localDT = LocalDateTime.from(ta);
if (dateTimeZoneId != null) {
// Shift LocalDateTime to specified zone
// https://stackoverflow.com/questions/42280454/changing-localdatetime-based-on-time-difference-in-current-time-zone-vs-eastern
localDT = localDT
.atZone(ZoneId.systemDefault())
.withZoneSameInstant(dateTimeZoneId)
.toLocalDateTime();
}
// We use java.sql.Timestamp.valueOf because classic date/time conversion turns "pre-historic" Gregorian
// dates into incorrect SQL timestamps (in Julian calendar). E.g. 0001-01-01->0001-01-03
value = Timestamp.valueOf(localDT);
......@@ -160,7 +170,16 @@ public class StreamTransferResultSet implements DBCResultSet {
return dateTimeFormat;
}
public void setDateTimeFormat(DateTimeFormatter dateTimeFormat) {
public void setDateTimeFormat(DateTimeFormatter dateTimeFormat, ZoneId dateTimeZoneId) {
this.dateTimeFormat = dateTimeFormat;
this.dateTimeZoneId = dateTimeZoneId;
if (this.dateTimeFormat != null && this.dateTimeZoneId != null) {
// Set zone to the format.
// FIXME: it looks like a good idea but in fact iti s not. We can't convert ZonedDateTime into
// FIXME: proper SQL timestamp for pre-historic (pre-Gregorian) dates.
// FIXME: so we will shift LocalDateTime in getAttributeValue instead
// FIXME: https://stackoverflow.com/questions/23975205/why-does-converting-java-dates-before-1582-to-localdate-with-instant-give-a-diff
//this.dateTimeFormat = this.dateTimeFormat.withZone(dateTimeZoneId);
}
}
}
......@@ -49,7 +49,6 @@ public class DataImporterCSV extends StreamImporterAbstract {
private static final String PROP_NULL_STRING = "nullString";
private static final String PROP_EMPTY_STRING_NULL = "emptyStringNull";
private static final String PROP_ESCAPE_CHAR = "escapeChar";
private static final String PROP_TIMESTAMP_FORMAT = "timestampFormat";
enum HeaderPosition {
none,
......@@ -135,7 +134,7 @@ public class DataImporterCSV extends StreamImporterAbstract {
consumer.fetchStart(producerSession, resultSet, -1, -1);
applyTransformHints(resultSet, consumer, getTimeStampFormat(properties, PROP_TIMESTAMP_FORMAT));
applyTransformHints(resultSet, consumer, properties, PROP_TIMESTAMP_FORMAT, PROP_TIMESTAMP_ZONE);
try (Reader reader = openStreamReader(inputStream, properties)) {
try (CSVReader csvReader = openCSVReader(reader, properties)) {
......
......@@ -31,6 +31,7 @@ import org.jkiss.dbeaver.tools.transfer.stream.StreamDataImporterColumnInfo;
import org.jkiss.dbeaver.tools.transfer.stream.StreamTransferResultSet;
import org.jkiss.utils.CommonUtils;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Map;
......@@ -41,6 +42,9 @@ public abstract class StreamImporterAbstract implements IStreamDataImporter {
private static final Log log = Log.getLog(StreamImporterAbstract.class);
protected static final String PROP_TIMESTAMP_FORMAT = "timestampFormat";
protected static final String PROP_TIMESTAMP_ZONE = "timestampZone";
private IStreamDataImporterSite site;
public IStreamDataImporterSite getSite()
......@@ -61,10 +65,10 @@ public abstract class StreamImporterAbstract implements IStreamDataImporter {
}
@Nullable
protected DateTimeFormatter getTimeStampFormat(Map<String, Object> properties, String propName) {
protected DateTimeFormatter getTimeStampFormat(Map<String, Object> properties, String formatPropName) {
DateTimeFormatter tsFormat = null;
String tsFormatPattern = CommonUtils.toString(properties.get(propName));
String tsFormatPattern = CommonUtils.toString(properties.get(formatPropName));
if (!CommonUtils.isEmpty(tsFormatPattern)) {
try {
tsFormat = DateTimeFormatter.ofPattern(tsFormatPattern);
......@@ -75,9 +79,17 @@ public abstract class StreamImporterAbstract implements IStreamDataImporter {
return tsFormat;
}
protected void applyTransformHints(StreamTransferResultSet resultSet, IDataTransferConsumer consumer, DateTimeFormatter tsFormat) throws DBException {
protected void applyTransformHints(StreamTransferResultSet resultSet, IDataTransferConsumer consumer, Map<String, Object> properties, String formatPropName, String zoneIdPropName) throws DBException {
DateTimeFormatter tsFormat = formatPropName == null ? null : getTimeStampFormat(properties, formatPropName);
ZoneId tsZoneId = null;
if (zoneIdPropName != null) {
String zoneId = CommonUtils.toString(properties.get(zoneIdPropName));
if (!CommonUtils.isEmpty(zoneId)) {
tsZoneId = ZoneId.of(zoneId);
}
}
if (tsFormat != null) {
resultSet.setDateTimeFormat(tsFormat);
resultSet.setDateTimeFormat(tsFormat, tsZoneId);
}
// Try to find source/target attributes
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册