This is an automated email from the ASF dual-hosted git repository.

richardantal pushed a commit to branch 5.1
in repository https://gitbox.apache.org/repos/asf/phoenix.git


The following commit(s) were added to refs/heads/5.1 by this push:
     new 5a02b3d  PHOENIX-6486 Phoenix uses inconsistent chronologies 
internally, breaking pre-Gregorian date handling
5a02b3d is described below

commit 5a02b3dad96088c5128fdff92cdd86da60b1aa4b
Author: Richard Antal <antal97rich...@gmail.com>
AuthorDate: Wed Aug 25 11:48:36 2021 +0200

    PHOENIX-6486 Phoenix uses inconsistent chronologies internally, breaking 
pre-Gregorian date handling
---
 .../org/apache/phoenix/end2end/DateTimeIT.java     | 212 ++++++++++++++++++++-
 .../expression/function/DayOfMonthFunction.java    |   3 +-
 .../expression/function/DayOfWeekFunction.java     |   3 +-
 .../expression/function/DayOfYearFunction.java     |   3 +-
 .../phoenix/expression/function/HourFunction.java  |   5 +-
 .../expression/function/MinuteFunction.java        |   5 +-
 .../phoenix/expression/function/MonthFunction.java |   3 +-
 .../function/RoundJodaDateExpression.java          |   2 +-
 .../expression/function/SecondFunction.java        |   5 +-
 .../phoenix/expression/function/WeekFunction.java  |   3 +-
 .../phoenix/expression/function/YearFunction.java  |   3 +-
 .../java/org/apache/phoenix/util/DateUtil.java     |  31 +--
 12 files changed, 253 insertions(+), 25 deletions(-)

diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DateTimeIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DateTimeIT.java
index 98c0e30..a0d017f 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DateTimeIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DateTimeIT.java
@@ -35,6 +35,7 @@ import static org.apache.phoenix.util.TestUtil.ROW9;
 import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -52,10 +53,13 @@ import java.sql.Timestamp;
 import java.sql.Types;
 import java.text.Format;
 import java.time.LocalDate;
+import java.time.ZoneOffset;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 import java.util.Properties;
 import java.util.TimeZone;
+import java.util.List;
+import java.util.Arrays;
 
 import org.apache.commons.lang3.time.FastDateFormat;
 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
@@ -560,7 +564,7 @@ public class DateTimeIT extends ParallelStatsDisabledIT {
     @Test
     public void testYearFunctionDate() throws SQLException {
 
-        assertEquals(2008, callYearFunction("\"YEAR\"(TO_DATE('2008-01-01', 
'yyyy-MM-dd', 'local'))"));
+        assertEquals(2008, callYearFunction("\"YEAR\"(TO_DATE('2008-01-01', 
'yyyy-MM-dd'))"));
 
         assertEquals(2004,
             callYearFunction("\"YEAR\"(TO_DATE('2004-12-13 10:13:18', 
'yyyy-MM-dd hh:mm:ss'))"));
@@ -1939,6 +1943,212 @@ public class DateTimeIT extends ParallelStatsDisabledIT 
{
         }
     }
 
+    private String getFormattedDate(List<String> dateList) {
+        return String.join("-", dateList.subList(0, 3)) + " "
+                + String.join(":", dateList.subList(3, 6)) + "." + 
dateList.get(6);
+    }
+
+    @Test
+    public void testAncientDates() throws Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(url, props);
+        Statement stmt = conn.createStatement();
+        String tableName = generateUniqueName();
+
+        List<String> date1list = Arrays.asList("0010", "10", "10", "10", "10", 
"10", "111");
+        List<String> date2list = Arrays.asList("1001", "02", "03", "04", "05", 
"06", "000");
+        List<String> date3list = Arrays.asList("0001", "12", "31", "23", "59", 
"59", "000");
+        List<List<String>> dateLists = Arrays.asList(date1list, date2list, 
date3list, date2list);
+
+        String date1 = getFormattedDate(date1list); // 0010-10-10 10:10:10.111
+        String date2 = getFormattedDate(date2list); // 1000-02-03 04:05:06.000
+        String date3 = getFormattedDate(date3list); // 0001-12-31 23:59:59.000
+        List<String> dates = Arrays.asList(date1, date2, date3, date2);
+
+
+        stmt.execute("CREATE TABLE " + tableName + " ( id INTEGER not null 
PRIMARY KEY," +
+                " date DATE, time TIME, timestamp TIMESTAMP)");
+
+        stmt.execute("UPSERT INTO " + tableName + " VALUES(1, TO_DATE('" + 
date1
+                + "'), TO_TIME('" + date1 + "'), TO_TIMESTAMP('" + date1 + 
"'))");
+
+        PreparedStatement pstmt = conn.prepareStatement("UPSERT INTO " + 
tableName + " values (?, ?, ?, ?)");
+        pstmt.setInt(1, 2);
+        Timestamp t = new Timestamp(DateUtil.parseDate(date2).getTime());
+        pstmt.setDate(2, new Date(t.getTime()));
+        pstmt.setTime(3, new Time(t.getTime()));
+        pstmt.setTimestamp(4, t);
+        pstmt.execute();
+
+        pstmt.setInt(1, 3);
+        t = new Timestamp(DateUtil.parseDate(date3).getTime());
+        pstmt.setDate(2, new Date(t.getTime()));
+        pstmt.setTime(3, new Time(t.getTime()));
+        pstmt.setTimestamp(4, t);
+        pstmt.execute();
+
+        String f = " GMT', 'yyyy-MM-dd HH:mm:ss.SSS z', 'UTC";
+        stmt.execute("UPSERT INTO " + tableName + " VALUES(4, TO_DATE('" + 
date2 + f
+                + "'), TO_TIME('" + date2 + f + "'), TO_TIMESTAMP('" + date2 + 
f + "'))");
+        conn.commit();
+
+        ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName + " 
ORDER BY id");
+
+        for (int i = 0; i < dates.size(); i++) {
+            assertTrue(rs.next());
+            String actualDate = dates.get(i);
+            Timestamp expectedTimestamp = DateUtil.parseTimestamp(actualDate);
+
+            assertEquals(i + 1, rs.getInt(1));
+            Date expectedDate = new Date(expectedTimestamp.getTime());
+            assertEquals(expectedDate, rs.getDate(2));
+            assertEquals(rs.getDate(2), rs.getObject(2));
+            assertEquals(actualDate, rs.getString(2));
+
+            Time expectedTime = new Time(expectedTimestamp.getTime());
+            assertEquals(new Timestamp(expectedTime.getTime()), new 
Timestamp(rs.getTime(3).getTime()));
+            assertEquals(expectedTime, rs.getTime(3));
+            assertEquals(rs.getTime(3), rs.getObject(3));
+            assertEquals(actualDate, rs.getString(3));
+
+            assertEquals(expectedTimestamp, rs.getTimestamp(4));
+            assertEquals(rs.getTimestamp(4), rs.getObject(4));
+            assertEquals(actualDate, rs.getString(4));
+        }
+
+        String query = "SELECT year(timestamp), month(timestamp), 
dayofmonth(timestamp),"
+                + " hour(timestamp), minute(timestamp), second(timestamp) FROM 
" + tableName
+                + " ORDER BY id";
+        rs = stmt.executeQuery(query);
+
+        for (int i = 0; i < dates.size(); i++) {
+            assertTrue(rs.next());
+            List<String> dateList = dateLists.get(i);
+            for (int j = 0; j < 6; j++) {
+                int expected = Integer.parseInt(dateList.get(j));
+                int value = rs.getInt(j + 1);
+                String readFunc = query.split("\\s+")[j + 1];
+                assertTrue("Expected for " + readFunc.substring(0, 
readFunc.length() - 1) + ": " + expected + ", got: " + value,
+                        expected == value);
+            }
+        }
+
+        pstmt = conn.prepareStatement("UPSERT INTO " + tableName + " values 
(?, ?, ?, ?)");
+        pstmt.setInt(1, 5);
+        long l = -123456789100000L;
+        Timestamp inserted = new Timestamp(l);
+        pstmt.setDate(2, new Date(inserted.getTime()));
+        pstmt.setTime(3, new Time(inserted.getTime()));
+        pstmt.setTimestamp(4, inserted);
+        pstmt.execute();
+        conn.commit();
+
+        rs = stmt.executeQuery("SELECT * FROM " + tableName + " WHERE id=5 
ORDER BY id");
+        assertTrue(rs.next());
+        Timestamp read = rs.getTimestamp(4);
+        assertEquals(inserted, read);
+    }
+
+    @Test
+    public void testAncientDatesWithJavaTime() throws Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(url, props);
+        Statement stmt = conn.createStatement();
+        String tableName = generateUniqueName();
+
+        stmt.execute("CREATE TABLE " + tableName + " ( id INTEGER not null 
PRIMARY KEY," +
+                "timestamp TIMESTAMP)");
+
+        String date = "0010-10-10T10:10:10.111Z";
+
+        java.time.Instant instant = java.time.Instant.parse(date);
+        // 0010-10-10T10:10:10.111Z parsed in ISO chronology
+
+        PreparedStatement pstmt = conn.prepareStatement("UPSERT INTO " + 
tableName + " values (?, ?)");
+        pstmt.setInt(1, 1);
+        Timestamp inserted = new Timestamp(instant.toEpochMilli());
+        // java.sql.timestamp value will be 0010-10-12 because of GJ 
chronology used by java.sql.timestamp
+
+        pstmt.setTimestamp(2, inserted);
+        pstmt.execute();
+        conn.commit();
+
+        ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName + " 
WHERE id=1");
+        assertTrue(rs.next());
+        Timestamp read = rs.getTimestamp(2); // read back the 0010-10-12 in GJ
+        assertEquals(inserted, read);
+        // java.time.Instant value will be 0010-10-10 in ISO
+        assertEquals(instant, java.time.Instant.ofEpochMilli(read.getTime()));
+
+        assertEquals(instant.toEpochMilli(), read.getTime());
+        // same long value interpreted in different chronology results 
different date.
+        // Note that the string output is inconsistent but it is expected 
because of the different chronologies
+        assertEquals(read.toString().split("\\s+")[0], "0010-10-12");
+        assertEquals(instant.toString().split("T")[0], "0010-10-10");
+
+        // test for getdayofMonth will be broken see below because we stored 
the 0010-10-12 data
+
+        java.time.LocalDateTime localDateTime = java.time.LocalDateTime.of(10, 
10, 10, 10, 10, 10);
+        pstmt.setInt(1, 2);
+        inserted = java.sql.Timestamp.valueOf(localDateTime);
+
+        pstmt.setTimestamp(2, inserted);
+        pstmt.execute();
+        conn.commit();
+
+        rs = stmt.executeQuery("SELECT * FROM " + tableName + " WHERE id=2");
+        assertTrue(rs.next());
+        read = rs.getTimestamp(2);
+        assertEquals(inserted, read);
+        assertEquals(localDateTime, read.toLocalDateTime());
+        assertEquals(localDateTime.toEpochSecond(ZoneOffset.UTC),
+                read.toLocalDateTime().toEpochSecond(ZoneOffset.UTC));
+
+        // Inserting via java.sql.Timestamp.valueOf(localDateTime) will result 
the same toString result
+
+        assertEquals(read.toString().split("\\s+")[0], "0010-10-10");
+        assertEquals(instant.toString().split("T")[0], "0010-10-10");
+
+        // the long value that represents the the Date will be different 
thought
+        // can be expected because it resulted the same output string using 
different chronology
+        assertNotEquals(instant.toEpochMilli(), read.getTime());
+
+        // Converting Instant to LocalDateTime will behave like the 
LocalDateTime example
+        pstmt.setInt(1, 3);
+        java.time.LocalDateTime localDateTime1 = 
java.time.LocalDateTime.ofInstant(instant, java.time.ZoneId.of("GMT"));
+        inserted = java.sql.Timestamp.valueOf(localDateTime1);
+
+        pstmt.setTimestamp(2, inserted);
+        pstmt.execute();
+        conn.commit();
+
+        rs = stmt.executeQuery("SELECT * FROM " + tableName + " WHERE id=3");
+        assertTrue(rs.next());
+        read = rs.getTimestamp(2);
+        assertEquals(inserted, read);
+        assertEquals(localDateTime1, read.toLocalDateTime());
+        assertEquals(read.toString().split("\\s+")[0], "0010-10-10");
+        assertEquals(localDateTime1.toString().split("T")[0], "0010-10-10");
+
+        java.time.Instant inst = localDateTime1.toInstant(ZoneOffset.UTC);
+        assertEquals(instant, inst);
+        assertNotEquals(inst.toEpochMilli(), inserted.getTime());
+
+
+        String query = "SELECT dayofmonth(timestamp) FROM " + tableName;
+        rs = stmt.executeQuery(query);
+        assertTrue(rs.next());
+        // Timestamp inserted = new Timestamp(instant.toEpochMilli());
+        assertEquals(12, rs.getInt(1));
+        assertTrue(rs.next());
+        // inserted = java.sql.Timestamp.valueOf(localDateTime);
+        assertEquals(10, rs.getInt(1));
+        assertTrue(rs.next());
+        // inserted = 
java.sql.Timestamp.valueOf(java.time.LocalDateTime.ofInstant(instant, 
java.time.ZoneId.of("GMT")));
+        assertEquals(10, rs.getInt(1));
+        assertFalse(rs.next());
+    }
+
     public void testDateFormatTimeZone(String timeZoneId) throws Exception {
         Properties props = new Properties();
         props.setProperty("phoenix.query.dateFormatTimeZone", timeZoneId);
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfMonthFunction.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfMonthFunction.java
index fb5a68a..721f8e6 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfMonthFunction.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfMonthFunction.java
@@ -29,6 +29,7 @@ import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PInteger;
 import org.apache.phoenix.schema.types.PTimestamp;
 import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
 
 /**
  * 
@@ -58,7 +59,7 @@ public class DayOfMonthFunction extends DateScalarFunction {
             return true; //means null
         }
         long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
-        DateTime dt = new DateTime(dateTime);
+        DateTime dt = new DateTime(dateTime, GJChronology.getInstanceUTC());
         int day = dt.getDayOfMonth();
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfWeekFunction.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfWeekFunction.java
index e4d3d5f..1dbcc10 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfWeekFunction.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfWeekFunction.java
@@ -28,6 +28,7 @@ import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PInteger;
 import org.apache.phoenix.schema.types.PTimestamp;
 import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
 
 /**
  * Implementation of DayOfWeekFunction(Date/Timestamp)
@@ -69,7 +70,7 @@ public class DayOfWeekFunction extends DateScalarFunction {
             return true;
         }
         long dateTime = inputCodec.decodeLong(ptr, arg.getSortOrder());
-        DateTime jodaDT = new DateTime(dateTime);
+        DateTime jodaDT = new DateTime(dateTime, 
GJChronology.getInstanceUTC());
         int day = jodaDT.getDayOfWeek();
         PDataType returnDataType = getDataType();
         byte[] byteValue = new byte[returnDataType.getByteSize()];
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfYearFunction.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfYearFunction.java
index 8da51d7..2cde41e 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfYearFunction.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/DayOfYearFunction.java
@@ -28,6 +28,7 @@ import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PInteger;
 import org.apache.phoenix.schema.types.PTimestamp;
 import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
 
 /**
  * Implementation of DayOfYearFunction(Date/Timestamp)
@@ -62,7 +63,7 @@ public class DayOfYearFunction extends DateScalarFunction {
             return true;
         }
         long dateTime = inputCodec.decodeLong(ptr, arg.getSortOrder());
-        DateTime jodaDT = new DateTime(dateTime);
+        DateTime jodaDT = new DateTime(dateTime, 
GJChronology.getInstanceUTC());
         int day = jodaDT.getDayOfYear();
         PDataType returnDataType = getDataType();
         byte[] byteValue = new byte[returnDataType.getByteSize()];
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/HourFunction.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/HourFunction.java
index 7b9c8c0..f9ceb68 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/HourFunction.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/HourFunction.java
@@ -28,6 +28,8 @@ import org.apache.phoenix.schema.tuple.Tuple;
 import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PInteger;
 import org.apache.phoenix.schema.types.PTimestamp;
+import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
 
 /**
  * 
@@ -57,7 +59,8 @@ public class HourFunction extends DateScalarFunction {
             return true; //means null
         }
         long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
-        int hour = (int)(((dateTime/1000) % (24*3600))/3600);
+        DateTime dt = new DateTime(dateTime, GJChronology.getInstanceUTC());
+        int hour = dt.getHourOfDay();
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];
         returnType.getCodec().encodeInt(hour, byteValue, 0);
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MinuteFunction.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MinuteFunction.java
index 6766e35..1ba6729 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MinuteFunction.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MinuteFunction.java
@@ -28,6 +28,8 @@ import org.apache.phoenix.schema.tuple.Tuple;
 import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PInteger;
 import org.apache.phoenix.schema.types.PTimestamp;
+import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
 
 /**
  * 
@@ -57,7 +59,8 @@ public class MinuteFunction extends DateScalarFunction {
             return true; //means null
         }
         long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
-        int minute = (int)(((dateTime/1000) % 3600)/60);
+        DateTime dt = new DateTime(dateTime, GJChronology.getInstanceUTC());
+        int minute = dt.getMinuteOfHour();
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];
         returnType.getCodec().encodeInt(minute, byteValue, 0);
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MonthFunction.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MonthFunction.java
index bd6ff3e..cb6ce3b 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MonthFunction.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/MonthFunction.java
@@ -29,6 +29,7 @@ import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PInteger;
 import org.apache.phoenix.schema.types.PTimestamp;
 import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
 
 /**
  * 
@@ -58,7 +59,7 @@ public class MonthFunction extends DateScalarFunction {
             return true; //means null
         }
         long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
-        DateTime dt = new DateTime(dateTime);
+        DateTime dt = new DateTime(dateTime, GJChronology.getInstanceUTC());
         int month = dt.getMonthOfYear();
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
index 356c85f..aa9ef07 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
@@ -48,7 +48,7 @@ public abstract class RoundJodaDateExpression extends 
RoundDateExpression{
             }
             PDataType dataType = getDataType();
             long time = dataType.getCodec().decodeLong(ptr, 
children.get(0).getSortOrder());
-            DateTime dt = new DateTime(time,ISOChronology.getInstanceUTC());
+            DateTime dt = new DateTime(time, ISOChronology.getInstanceUTC());
             long value = roundDateTime(dt);
             Date d = new Date(value);
             byte[] byteValue = dataType.toBytes(d);
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SecondFunction.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SecondFunction.java
index 02bc455..09e3058 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SecondFunction.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SecondFunction.java
@@ -28,6 +28,8 @@ import org.apache.phoenix.schema.tuple.Tuple;
 import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PInteger;
 import org.apache.phoenix.schema.types.PTimestamp;
+import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
 
 /**
  * 
@@ -57,7 +59,8 @@ public class SecondFunction extends DateScalarFunction {
             return true; //means null
         }
         long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
-        int sec = (int)((dateTime/1000) % 60);
+        DateTime dt = new DateTime(dateTime, GJChronology.getInstanceUTC());
+        int sec = dt.getSecondOfMinute();
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];
         returnType.getCodec().encodeInt(sec, byteValue, 0);
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/WeekFunction.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/WeekFunction.java
index 3f6d772..f3032bf 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/WeekFunction.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/WeekFunction.java
@@ -29,6 +29,7 @@ import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PInteger;
 import org.apache.phoenix.schema.types.PTimestamp;
 import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
 
 /**
  * 
@@ -58,7 +59,7 @@ public class WeekFunction extends DateScalarFunction {
             return true; //means null
         }
         long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
-        DateTime dt = new DateTime(dateTime);
+        DateTime dt = new DateTime(dateTime, GJChronology.getInstanceUTC());
         int week = dt.getWeekOfWeekyear();
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/YearFunction.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/YearFunction.java
index fcab8d2..ee10ead 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/YearFunction.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/YearFunction.java
@@ -29,6 +29,7 @@ import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PInteger;
 import org.apache.phoenix.schema.types.PTimestamp;
 import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
 
 /**
  * 
@@ -57,7 +58,7 @@ public class YearFunction extends DateScalarFunction {
             return true; //means null
         }
         long dateTime = inputCodec.decodeLong(ptr, expression.getSortOrder());
-        DateTime dt = new DateTime(dateTime);
+        DateTime dt = new DateTime(dateTime, GJChronology.getInstanceUTC());
         int year = dt.getYear();
         PDataType returnType = getDataType();
         byte[] byteValue = new byte[returnType.getByteSize()];
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/DateUtil.java 
b/phoenix-core/src/main/java/org/apache/phoenix/util/DateUtil.java
index 9eee9dd..cc16eb6 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/DateUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/DateUtil.java
@@ -40,8 +40,10 @@ import org.apache.phoenix.schema.types.PDate;
 import org.apache.phoenix.schema.types.PTimestamp;
 import org.apache.phoenix.schema.types.PUnsignedDate;
 import org.apache.phoenix.schema.types.PUnsignedTimestamp;
+import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.chrono.ISOChronology;
+import org.joda.time.chrono.GJChronology;
 import org.joda.time.format.DateTimeFormatter;
 import org.joda.time.format.DateTimeFormatterBuilder;
 import org.joda.time.format.ISODateTimeFormat;
@@ -70,13 +72,13 @@ public class DateUtil {
     public static final String DEFAULT_TIMESTAMP_FORMAT = 
DEFAULT_MS_DATE_FORMAT;
     public static final Format DEFAULT_TIMESTAMP_FORMATTER = 
DEFAULT_MS_DATE_FORMATTER;
 
-    private static final DateTimeFormatter ISO_DATE_TIME_FORMATTER = new 
DateTimeFormatterBuilder()
+    private static final DateTimeFormatter JULIAN_DATE_TIME_FORMATTER = new 
DateTimeFormatterBuilder()
         .append(ISODateTimeFormat.dateParser())
         .appendOptional(new DateTimeFormatterBuilder()
                 .appendLiteral(' ').toParser())
         .appendOptional(new DateTimeFormatterBuilder()
                 .append(ISODateTimeFormat.timeParser()).toParser())
-        .toFormatter().withChronology(ISOChronology.getInstanceUTC());
+        .toFormatter().withChronology(GJChronology.getInstanceUTC());
     
     private DateUtil() {
     }
@@ -154,7 +156,7 @@ public class DateUtil {
             pattern = defaultPattern;
         }
         if(defaultPattern.equals(pattern)) {
-            return ISODateFormatParserFactory.getParser(timeZone);
+            return JulianDateFormatParserFactory.getParser(timeZone);
         } else {
             return new SimpleDateFormatParser(pattern, timeZone);
         }
@@ -187,7 +189,7 @@ public class DateUtil {
     }
 
     private static long parseDateTime(String dateTimeValue) {
-        return ISODateFormatParser.getInstance().parseDateTime(dateTimeValue);
+        return 
JulianDateFormatParser.getInstance().parseDateTime(dateTimeValue);
     }
 
     public static Date parseDate(String dateValue) {
@@ -287,17 +289,17 @@ public class DateUtil {
         }
     }
 
-    private static class ISODateFormatParserFactory {
-        private ISODateFormatParserFactory() {}
-        
+    private static class JulianDateFormatParserFactory {
+        private JulianDateFormatParserFactory() {}
+
         public static DateTimeParser getParser(final TimeZone timeZone) {
             // If timeZone matches default, get singleton DateTimeParser
             if (timeZone.equals(DEFAULT_TIME_ZONE)) {
-                return ISODateFormatParser.getInstance();
+                return JulianDateFormatParser.getInstance();
             }
             // Otherwise, create new DateTimeParser
             return new DateTimeParser() {
-                private final DateTimeFormatter formatter = 
ISO_DATE_TIME_FORMATTER
+                private final DateTimeFormatter formatter = 
JULIAN_DATE_TIME_FORMATTER
                         .withZone(DateTimeZone.forTimeZone(timeZone));
 
                 @Override
@@ -316,19 +318,20 @@ public class DateUtil {
             };
         }
     }
+
     /**
      * This class is our default DateTime string parser
      */
-    private static class ISODateFormatParser implements DateTimeParser {
-        private static final ISODateFormatParser INSTANCE = new 
ISODateFormatParser();
+    private static class JulianDateFormatParser implements DateTimeParser {
+        private static final JulianDateFormatParser INSTANCE = new 
JulianDateFormatParser();
 
-        public static ISODateFormatParser getInstance() {
+        public static JulianDateFormatParser getInstance() {
             return INSTANCE;
         }
 
-        private final DateTimeFormatter formatter = 
ISO_DATE_TIME_FORMATTER.withZone(DateTimeZone.UTC);
+        private final DateTimeFormatter formatter = 
JULIAN_DATE_TIME_FORMATTER.withZone(DateTimeZone.UTC);
 
-        private ISODateFormatParser() {}
+        private JulianDateFormatParser() {}
 
         @Override
         public long parseDateTime(String dateTimeString) throws 
IllegalDataException {

Reply via email to