Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: timezone used by implicit conversion #116

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,7 @@ private String convertJavaTypeToSqlString(Object x) throws SQLException {
} else if (java.util.Date.class.isInstance(x)
|| java.sql.Date.class.isInstance(x)
|| java.sql.Time.class.isInstance(x)) {
// TODO: use SimpleDateFormat without a ISO_8601 Calendar
SimpleDateFormat formatter = new SimpleDateFormat(JdbcColumn.ODPS_DATETIME_FORMAT);
return String.format("DATETIME\"%s\"", formatter.format(x));
} else if (Boolean.class.isInstance(x)) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/aliyun/odps/jdbc/OdpsResultSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ private Object transformToJdbcType(Object o, Class jdbcCls, Calendar cal) throws
}
}

return ((AbstractToJdbcDateTypeTransformer) transformer).transform(o, conn.getCharset(), cal, timeZone);
return ((AbstractToJdbcDateTypeTransformer) transformer).transform(o, conn.getCharset(), timeZone);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,23 @@
import java.util.TimeZone;

public abstract class AbstractToJdbcDateTypeTransformer extends AbstractToJdbcTransformer {
static ThreadLocal<SimpleDateFormat> TIMESTAMP_FORMAT = new ThreadLocal<>();
static ThreadLocal<SimpleDateFormat> DATETIME_FORMAT = new ThreadLocal<>();
static ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<>();
static ThreadLocal<SimpleDateFormat> TIME_FORMAT = new ThreadLocal<>();
static {
TIMESTAMP_FORMAT.set(new SimpleDateFormat(JdbcColumn.ODPS_TIMESTAMP_FORMAT));
DATETIME_FORMAT.set(new SimpleDateFormat(JdbcColumn.ODPS_DATETIME_FORMAT));
DATE_FORMAT.set(new SimpleDateFormat(JdbcColumn.ODPS_DATE_FORMAT));
TIME_FORMAT.set(new SimpleDateFormat(JdbcColumn.ODPS_TIME_FORMAT));
}


@Override
public Object transform(Object o, String charset) throws SQLException {
return this.transform(o, charset, null, null);
return this.transform(o, charset, null);
}

/**
* Transform ODPS SDK object to an instance of java.util.Date subclass
* @param o java object from ODPS SDK
* @param charset charset to encode byte array
* @param cal a calendar object to construct java.util.Date object
* @param timeZone time zone. The default value is GMT +0.
* @return JDBC object
* @throws SQLException
*/
public abstract Object transform(
Object o,
String charset,
Calendar cal,
TimeZone timeZone) throws SQLException;

void restoreToDefaultCalendar() {
TIMESTAMP_FORMAT.get().setCalendar(Calendar.getInstance());
DATETIME_FORMAT.get().setCalendar(Calendar.getInstance());
DATE_FORMAT.get().setCalendar(Calendar.getInstance());
TIME_FORMAT.get().setCalendar(Calendar.getInstance());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,35 @@

import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;

import com.aliyun.odps.jdbc.utils.JdbcColumn;


public abstract class AbstractToJdbcTransformer {
static ThreadLocal<Calendar> DEFAULT_CALENDAR = new ThreadLocal<>();
static ThreadLocal<SimpleDateFormat> TIMESTAMP_FORMAT = new ThreadLocal<>();
static ThreadLocal<SimpleDateFormat> DATETIME_FORMAT = new ThreadLocal<>();
static ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<>();
static ThreadLocal<SimpleDateFormat> TIME_FORMAT = new ThreadLocal<>();
static {
DEFAULT_CALENDAR.set(
new Calendar.Builder()
.setCalendarType("iso8601")
.setTimeZone(TimeZone.getTimeZone("GMT"))
.setLenient(true).build());
TIMESTAMP_FORMAT.set(new SimpleDateFormat(JdbcColumn.ODPS_TIMESTAMP_FORMAT));
DATETIME_FORMAT.set(new SimpleDateFormat(JdbcColumn.ODPS_DATETIME_FORMAT));
DATE_FORMAT.set(new SimpleDateFormat(JdbcColumn.ODPS_DATE_FORMAT));
TIME_FORMAT.set(new SimpleDateFormat(JdbcColumn.ODPS_TIME_FORMAT));
TIMESTAMP_FORMAT.get().setCalendar(DEFAULT_CALENDAR.get());
DATETIME_FORMAT.get().setCalendar(DEFAULT_CALENDAR.get());
DATE_FORMAT.get().setCalendar(DEFAULT_CALENDAR.get());
TIME_FORMAT.get().setCalendar(DEFAULT_CALENDAR.get());
}

static final String INVALID_TRANSFORMATION_ERROR_MSG =
"Cannot transform ODPS-SDK Java class %s to %s";
static final String ENCODING_ERR_MSG =
Expand Down Expand Up @@ -59,4 +85,11 @@ public static String encodeBytes(byte[] bytes, String charset) throws SQLExcepti
}
return new String(bytes);
}

void restoreToDefaultCalendar() {
TIMESTAMP_FORMAT.get().setCalendar(DEFAULT_CALENDAR.get());
DATETIME_FORMAT.get().setCalendar(DEFAULT_CALENDAR.get());
DATE_FORMAT.get().setCalendar(DEFAULT_CALENDAR.get());
TIME_FORMAT.get().setCalendar(DEFAULT_CALENDAR.get());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,57 @@

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Calendar.Builder;
import java.util.TimeZone;

import com.aliyun.odps.data.Binary;
import com.aliyun.odps.jdbc.utils.JdbcColumn;


public class ToJdbcByteArrayTransformer extends AbstractToJdbcTransformer {
public class ToJdbcByteArrayTransformer extends AbstractToJdbcDateTypeTransformer {

@Override
public Object transform(Object o, String charset) throws SQLException {
public Object transform(Object o, String charset, TimeZone timeZone) throws SQLException {
if (o == null) {
return null;
}

if (o instanceof byte[]) {
return o;
} else if (java.util.Date.class.isInstance(o)) {
if (java.sql.Timestamp.class.isInstance(o)) {
return o.toString().getBytes();
Calendar calendar = null;
if (timeZone != null) {
Builder calendarBuilder = new Calendar.Builder()
.setCalendarType("iso8601")
.setLenient(true);
calendarBuilder.setTimeZone(timeZone);
calendar = calendarBuilder.build();
}

try {
if (java.sql.Timestamp.class.isInstance(o)) {
// MaxCompute TIMESTAMP
if (calendar != null) {
TIMESTAMP_FORMAT.get().setCalendar(calendar);
}
return TIMESTAMP_FORMAT.get().format(o).getBytes();
} else if (java.sql.Date.class.isInstance(o)) {
// MaxCompute DATE
if (calendar != null) {
DATE_FORMAT.get().setCalendar(calendar);
}
return DATE_FORMAT.get().format(o).getBytes();
} else {
// MaxCompute DATETIME
if (calendar != null) {
DATETIME_FORMAT.get().setCalendar(calendar);
}
return DATETIME_FORMAT.get().format(o).getBytes();
}
} finally {
restoreToDefaultCalendar();
}
SimpleDateFormat dateFormat = new SimpleDateFormat(JdbcColumn.ODPS_DATETIME_FORMAT);
return dateFormat.format(((java.util.Date) o)).getBytes();
} else if (o instanceof Binary) {
return ((Binary) o).data();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Calendar;
import java.util.Calendar.Builder;
import java.util.TimeZone;


Expand All @@ -33,7 +35,6 @@ public class ToJdbcDateTransformer extends AbstractToJdbcDateTypeTransformer {
public Object transform(
Object o,
String charset,
Calendar cal,
TimeZone timeZone) throws SQLException {

if (o == null) {
Expand All @@ -46,14 +47,23 @@ public Object transform(
time += timeZone.getOffset(time);
}
return new java.sql.Date(time);
} else if (o instanceof LocalDate) {
LocalDate localDate = (LocalDate) o;
Calendar calendar = (Calendar) DEFAULT_CALENDAR.get().clone();
calendar.set(
localDate.getYear(),
// Starts from 0
localDate.getMonth().getValue() - 1,
localDate.getDayOfMonth());
long time = calendar.getTime().getTime();
if (timeZone != null) {
time += timeZone.getOffset(time);
}
return new java.sql.Date(time);
} else if (o instanceof byte[]) {
try {
SimpleDateFormat datetimeFormat = DATETIME_FORMAT.get();
SimpleDateFormat dateFormat = DATE_FORMAT.get();
if (cal != null) {
datetimeFormat.setCalendar(cal);
dateFormat.setCalendar(cal);
}
try {
return new java.sql.Date(
datetimeFormat.parse(encodeBytes((byte[]) o, charset)).getTime());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
public class ToJdbcStringTransformer extends AbstractToJdbcDateTypeTransformer {

@Override
public Object transform(Object o, String charset, Calendar cal, TimeZone timeZone)
public Object transform(Object o, String charset, TimeZone timeZone)
throws SQLException {
if (o == null) {
return null;
Expand All @@ -39,26 +39,33 @@ public Object transform(Object o, String charset, Calendar cal, TimeZone timeZon
if (o instanceof byte[]) {
return encodeBytes((byte[]) o, charset);
} else if (java.util.Date.class.isInstance(o)) {
Builder calendarBuilder = new Calendar.Builder()
.setCalendarType("iso8601")
.setLenient(true);
Calendar calendar = null;
if (timeZone != null) {
Builder calendarBuilder = new Calendar.Builder()
.setCalendarType("iso8601")
.setLenient(true);
calendarBuilder.setTimeZone(timeZone);
calendar = calendarBuilder.build();
}
Calendar calendar = calendarBuilder.build();

try {
if (java.sql.Timestamp.class.isInstance(o)) {
// MaxCompute TIMESTAMP
TIMESTAMP_FORMAT.get().setCalendar(calendar);
if (calendar != null) {
TIMESTAMP_FORMAT.get().setCalendar(calendar);
}
return TIMESTAMP_FORMAT.get().format(o);
} else if (java.sql.Date.class.isInstance(o)) {
// MaxCompute DATE
DATE_FORMAT.get().setCalendar(calendar);
if (calendar != null) {
DATE_FORMAT.get().setCalendar(calendar);
}
return DATE_FORMAT.get().format(o);
} else {
// MaxCompute DATETIME
DATETIME_FORMAT.get().setCalendar(calendar);
if (calendar != null) {
DATETIME_FORMAT.get().setCalendar(calendar);
}
return DATETIME_FORMAT.get().format(o);
}
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public class ToJdbcTimeTransfomer extends AbstractToJdbcDateTypeTransformer {
public Object transform(
Object o,
String charset,
Calendar cal,
TimeZone timeZone) throws SQLException {

if (o == null) {
Expand All @@ -50,10 +49,6 @@ public Object transform(
try {
SimpleDateFormat datetimeFormat = DATETIME_FORMAT.get();
SimpleDateFormat timeFormat = TIME_FORMAT.get();
if (cal != null) {
datetimeFormat.setCalendar(cal);
timeFormat.setCalendar(cal);
}
try {
return new java.sql.Time(
datetimeFormat.parse(encodeBytes((byte[]) o, charset)).getTime());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ public class ToJdbcTimestampTransformer extends AbstractToJdbcDateTypeTransforme
public Object transform(
Object o,
String charset,
Calendar cal,
TimeZone timeZone) throws SQLException {

if (o == null) {
Expand All @@ -61,9 +60,6 @@ public Object transform(
try {
// Acceptable pattern yyyy-MM-dd HH:mm:ss[.f...]
SimpleDateFormat datetimeFormat = DATETIME_FORMAT.get();
if (cal != null) {
datetimeFormat.setCalendar(cal);
}

// A timestamp string has two parts: datetime part and nano value part. We will firstly
// process the datetime part and apply the timezone. The nano value part will be set to the
Expand All @@ -85,10 +81,7 @@ public Object transform(
timestamp.setNanos(nanoValue);

return timestamp;
} catch (IllegalArgumentException e) {
String errorMsg = getTransformationErrMsg(o, java.sql.Timestamp.class);
throw new SQLException(errorMsg);
} catch (ParseException e) {
} catch (IllegalArgumentException | ParseException e) {
String errorMsg = getTransformationErrMsg(o, java.sql.Timestamp.class);
throw new SQLException(errorMsg);
} finally {
Expand Down
Loading