mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
Applied patch from Thomas O'Dowd that fixes timestamp parsing. The jdbc code
wasn't updated to handle more than two decimal digits for fractional seconds that now are possible in 7.2. This patch fixes the timestamp parsing logic. I have built and tested on both jdbc1 and jdbc2.
This commit is contained in:
parent
45a6343ebb
commit
3dd85bcb08
@ -491,6 +491,14 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
|
||||
/*
|
||||
* Get the value of a column in the current row as a
|
||||
* java.sql.Timestamp object
|
||||
*
|
||||
* The driver is set to return ISO date formated strings. We modify this
|
||||
* string from the ISO format to a format that Java can understand. Java
|
||||
* expects timezone info as 'GMT+09:00' where as ISO gives '+09'.
|
||||
* Java also expects fractional seconds to 3 places where postgres
|
||||
* will give, none, 2 or 6 depending on the time and postgres version.
|
||||
* From version 7.2 postgres returns fractional seconds to 6 places.
|
||||
* If available, we drop the last 3 digits.
|
||||
*
|
||||
* @param columnIndex the first column is 1, the second is 2...
|
||||
* @return the column value; null if SQL NULL
|
||||
@ -499,102 +507,80 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
|
||||
public Timestamp getTimestamp(int columnIndex) throws SQLException
|
||||
{
|
||||
String s = getString(columnIndex);
|
||||
|
||||
if (s == null)
|
||||
return null;
|
||||
|
||||
boolean subsecond;
|
||||
//if string contains a '.' we have fractional seconds
|
||||
if (s.indexOf('.') == -1)
|
||||
{
|
||||
subsecond = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
subsecond = true;
|
||||
}
|
||||
StringBuffer sbuf = new StringBuffer(s);
|
||||
SimpleDateFormat df = null;
|
||||
|
||||
//here we are modifying the string from ISO format to a format java can understand
|
||||
//java expects timezone info as 'GMT-08:00' instead of '-08' in postgres ISO format
|
||||
//and java expects three digits if fractional seconds are present instead of two for postgres
|
||||
//so this code strips off timezone info and adds on the GMT+/-...
|
||||
//as well as adds a third digit for partial seconds if necessary
|
||||
StringBuffer strBuf = new StringBuffer(s);
|
||||
|
||||
//we are looking to see if the backend has appended on a timezone.
|
||||
//currently postgresql will return +/-HH:MM or +/-HH for timezone offset
|
||||
//(i.e. -06, or +06:30, note the expectation of the leading zero for the
|
||||
//hours, and the use of the : for delimiter between hours and minutes)
|
||||
//if the backend ISO format changes in the future this code will
|
||||
//need to be changed as well
|
||||
char sub = strBuf.charAt(strBuf.length() - 3);
|
||||
if (sub == '+' || sub == '-')
|
||||
if (s.length() > 19)
|
||||
{
|
||||
strBuf.setLength(strBuf.length() - 3);
|
||||
if (subsecond)
|
||||
// The len of the ISO string to the second value is 19 chars. If
|
||||
// greater then 19, there should be tz info and perhaps fractional
|
||||
// second info which we need to change to java to read it.
|
||||
|
||||
// cut the copy to second value "2001-12-07 16:29:22"
|
||||
int i = 19;
|
||||
sbuf.setLength(i);
|
||||
|
||||
char c = s.charAt(i++);
|
||||
if (c == '.')
|
||||
{
|
||||
strBuf.append('0').append("GMT").append(s.substring(s.length() - 3, s.length())).append(":00");
|
||||
// Found a fractional value. Append up to 3 digits including
|
||||
// the leading '.'
|
||||
do
|
||||
{
|
||||
if (i < 24)
|
||||
sbuf.append(c);
|
||||
c = s.charAt(i++);
|
||||
} while (Character.isDigit(c));
|
||||
|
||||
// If there wasn't at least 3 digits we should add some zeros
|
||||
// to make up the 3 digits we tell java to expect.
|
||||
for (int j = i; j < 24; j++)
|
||||
sbuf.append('0');
|
||||
}
|
||||
else
|
||||
{
|
||||
strBuf.append("GMT").append(s.substring(s.length() - 3, s.length())).append(":00");
|
||||
// No fractional seconds, lets add some.
|
||||
sbuf.append(".000");
|
||||
}
|
||||
}
|
||||
else if (sub == ':')
|
||||
{
|
||||
//we may have found timezone info of format +/-HH:MM, or there is no
|
||||
//timezone info at all and this is the : preceding the seconds
|
||||
char sub2 = strBuf.charAt(strBuf.length() - 5);
|
||||
if (sub2 == '+' || sub2 == '-')
|
||||
{
|
||||
//we have found timezone info of format +/-HH:MM
|
||||
strBuf.setLength(strBuf.length() - 5);
|
||||
if (subsecond)
|
||||
{
|
||||
strBuf.append('0').append("GMT").append(s.substring(s.length() - 5));
|
||||
}
|
||||
else
|
||||
{
|
||||
strBuf.append("GMT").append(s.substring(s.length() - 5));
|
||||
}
|
||||
}
|
||||
else if (subsecond)
|
||||
{
|
||||
strBuf.append('0');
|
||||
}
|
||||
}
|
||||
else if (subsecond)
|
||||
{
|
||||
strBuf = strBuf.append('0');
|
||||
}
|
||||
|
||||
s = strBuf.toString();
|
||||
// prepend the GMT part and then add the remaining bit of
|
||||
// the string.
|
||||
sbuf.append(" GMT");
|
||||
sbuf.append(c);
|
||||
sbuf.append(s.substring(i, s.length()));
|
||||
|
||||
SimpleDateFormat df = null;
|
||||
// Lastly, if the tz part doesn't specify the :MM part then
|
||||
// we add ":00" for java.
|
||||
if (s.length() - i < 5)
|
||||
sbuf.append(":00");
|
||||
|
||||
if (s.length() > 23 && subsecond)
|
||||
{
|
||||
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSzzzzzzzzz");
|
||||
// we'll use this dateformat string to parse the result.
|
||||
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
|
||||
}
|
||||
else if (s.length() > 23 && !subsecond)
|
||||
{
|
||||
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:sszzzzzzzzz");
|
||||
}
|
||||
else if (s.length() > 10 && subsecond)
|
||||
{
|
||||
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
}
|
||||
else if (s.length() > 10 && !subsecond)
|
||||
else if (s.length() == 19)
|
||||
{
|
||||
// No tz or fractional second info.
|
||||
// I'm not sure if it is
|
||||
// possible to have a string in this format, as pg
|
||||
// should give us tz qualified timestamps back, but it was
|
||||
// in the old code, so I'm handling it for now.
|
||||
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
else
|
||||
{
|
||||
// We must just have a date. This case is
|
||||
// needed if this method is called on a date column
|
||||
df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return new Timestamp(df.parse(s).getTime());
|
||||
// All that's left is to parse the string and return the ts.
|
||||
return new Timestamp(df.parse(sbuf.toString()).getTime());
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
|
@ -1591,115 +1591,113 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
|
||||
}
|
||||
}
|
||||
|
||||
public static Timestamp toTimestamp(String s, ResultSet resultSet) throws SQLException
|
||||
/**
|
||||
* Parse a string and return a timestamp representing its value.
|
||||
*
|
||||
* The driver is set to return ISO date formated strings. We modify this
|
||||
* string from the ISO format to a format that Java can understand. Java
|
||||
* expects timezone info as 'GMT+09:00' where as ISO gives '+09'.
|
||||
* Java also expects fractional seconds to 3 places where postgres
|
||||
* will give, none, 2 or 6 depending on the time and postgres version.
|
||||
* From version 7.2 postgres returns fractional seconds to 6 places.
|
||||
* If available, we drop the last 3 digits.
|
||||
*
|
||||
* @param s The ISO formated date string to parse.
|
||||
* @param resultSet The ResultSet this date is part of.
|
||||
*
|
||||
* @return null if s is null or a timestamp of the parsed string s.
|
||||
*
|
||||
* @throws SQLException if there is a problem parsing s.
|
||||
**/
|
||||
public static Timestamp toTimestamp(String s, ResultSet resultSet)
|
||||
throws SQLException
|
||||
{
|
||||
if (s == null)
|
||||
return null;
|
||||
|
||||
boolean subsecond;
|
||||
//if string contains a '.' we have fractional seconds
|
||||
if (s.indexOf('.') == -1)
|
||||
{
|
||||
subsecond = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
subsecond = true;
|
||||
}
|
||||
|
||||
//here we are modifying the string from ISO format to a format java can understand
|
||||
//java expects timezone info as 'GMT-08:00' instead of '-08' in postgres ISO format
|
||||
//and java expects three digits if fractional seconds are present instead of two for postgres
|
||||
//so this code strips off timezone info and adds on the GMT+/-...
|
||||
//as well as adds a third digit for partial seconds if necessary
|
||||
// We must be synchronized here incase more theads access the ResultSet
|
||||
// bad practice but possible. Anyhow this is to protect sbuf and
|
||||
// SimpleDateFormat objects
|
||||
synchronized (resultSet)
|
||||
{
|
||||
// We must be synchronized here incase more theads access the ResultSet
|
||||
// bad practice but possible. Anyhow this is to protect sbuf and
|
||||
// SimpleDateFormat objects
|
||||
SimpleDateFormat df = null;
|
||||
|
||||
// First time?
|
||||
// If first time, create the buffer, otherwise clear it.
|
||||
if (resultSet.sbuf == null)
|
||||
resultSet.sbuf = new StringBuffer();
|
||||
else
|
||||
resultSet.sbuf.setLength(0);
|
||||
|
||||
resultSet.sbuf.setLength(0);
|
||||
// Copy s into sbuf for parsing.
|
||||
resultSet.sbuf.append(s);
|
||||
|
||||
//we are looking to see if the backend has appended on a timezone.
|
||||
//currently postgresql will return +/-HH:MM or +/-HH for timezone offset
|
||||
//(i.e. -06, or +06:30, note the expectation of the leading zero for the
|
||||
//hours, and the use of the : for delimiter between hours and minutes)
|
||||
//if the backend ISO format changes in the future this code will
|
||||
//need to be changed as well
|
||||
char sub = resultSet.sbuf.charAt(resultSet.sbuf.length() - 3);
|
||||
if (sub == '+' || sub == '-')
|
||||
if (s.length() > 19)
|
||||
{
|
||||
//we have found timezone info of format +/-HH
|
||||
// The len of the ISO string to the second value is 19 chars. If
|
||||
// greater then 19, there should be tz info and perhaps fractional
|
||||
// second info which we need to change to java to read it.
|
||||
|
||||
resultSet.sbuf.setLength(resultSet.sbuf.length() - 3);
|
||||
if (subsecond)
|
||||
// cut the copy to second value "2001-12-07 16:29:22"
|
||||
int i = 19;
|
||||
resultSet.sbuf.setLength(i);
|
||||
|
||||
char c = s.charAt(i++);
|
||||
if (c == '.')
|
||||
{
|
||||
resultSet.sbuf.append('0').append("GMT").append(s.substring(s.length() - 3)).append(":00");
|
||||
// Found a fractional value. Append up to 3 digits including
|
||||
// the leading '.'
|
||||
do
|
||||
{
|
||||
if (i < 24)
|
||||
resultSet.sbuf.append(c);
|
||||
c = s.charAt(i++);
|
||||
} while (Character.isDigit(c));
|
||||
|
||||
// If there wasn't at least 3 digits we should add some zeros
|
||||
// to make up the 3 digits we tell java to expect.
|
||||
for (int j = i; j < 24; j++)
|
||||
resultSet.sbuf.append('0');
|
||||
}
|
||||
else
|
||||
{
|
||||
resultSet.sbuf.append("GMT").append(s.substring(s.length() - 3)).append(":00");
|
||||
// No fractional seconds, lets add some.
|
||||
resultSet.sbuf.append(".000");
|
||||
}
|
||||
}
|
||||
else if (sub == ':')
|
||||
{
|
||||
//we may have found timezone info of format +/-HH:MM, or there is no
|
||||
//timezone info at all and this is the : preceding the seconds
|
||||
char sub2 = resultSet.sbuf.charAt(resultSet.sbuf.length() - 5);
|
||||
if (sub2 == '+' || sub2 == '-')
|
||||
{
|
||||
//we have found timezone info of format +/-HH:MM
|
||||
resultSet.sbuf.setLength(resultSet.sbuf.length() - 5);
|
||||
if (subsecond)
|
||||
{
|
||||
resultSet.sbuf.append('0').append("GMT").append(s.substring(s.length() - 5));
|
||||
}
|
||||
else
|
||||
{
|
||||
resultSet.sbuf.append("GMT").append(s.substring(s.length() - 5));
|
||||
}
|
||||
}
|
||||
else if (subsecond)
|
||||
{
|
||||
resultSet.sbuf.append('0');
|
||||
}
|
||||
}
|
||||
else if (subsecond)
|
||||
{
|
||||
resultSet.sbuf.append('0');
|
||||
}
|
||||
|
||||
// could optimize this a tad to remove too many object creations...
|
||||
SimpleDateFormat df = null;
|
||||
// prepend the GMT part and then add the remaining bit of
|
||||
// the string.
|
||||
resultSet.sbuf.append(" GMT");
|
||||
resultSet.sbuf.append(c);
|
||||
resultSet.sbuf.append(s.substring(i, s.length()));
|
||||
|
||||
if (resultSet.sbuf.length() > 23 && subsecond)
|
||||
{
|
||||
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSzzzzzzzzz");
|
||||
// Lastly, if the tz part doesn't specify the :MM part then
|
||||
// we add ":00" for java.
|
||||
if (s.length() - i < 5)
|
||||
resultSet.sbuf.append(":00");
|
||||
|
||||
// we'll use this dateformat string to parse the result.
|
||||
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
|
||||
}
|
||||
else if (resultSet.sbuf.length() > 23 && !subsecond)
|
||||
{
|
||||
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:sszzzzzzzzz");
|
||||
}
|
||||
else if (resultSet.sbuf.length() > 10 && subsecond)
|
||||
{
|
||||
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
}
|
||||
else if (resultSet.sbuf.length() > 10 && !subsecond)
|
||||
else if (s.length() == 19)
|
||||
{
|
||||
// No tz or fractional second info.
|
||||
// I'm not sure if it is
|
||||
// possible to have a string in this format, as pg
|
||||
// should give us tz qualified timestamps back, but it was
|
||||
// in the old code, so I'm handling it for now.
|
||||
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
else
|
||||
{
|
||||
// We must just have a date. This case is
|
||||
// needed if this method is called on a date
|
||||
// column
|
||||
df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// All that's left is to parse the string and return the ts.
|
||||
return new Timestamp(df.parse(resultSet.sbuf.toString()).getTime());
|
||||
}
|
||||
catch (ParseException e)
|
||||
@ -1708,7 +1706,5 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user