/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ package org.apache.hadoop.hive.ql.udf.generic; import java.sql.Date; import java.sql.Timestamp; import org.apache.hadoop.hive.ql.metadata.HiveException; import org.apache.hadoop.hive.ql.udf.generic.GenericUDF.DeferredJavaObject; import org.apache.hadoop.hive.ql.udf.generic.GenericUDF.DeferredObject; import org.apache.hadoop.hive.serde2.io.DateWritable; import org.apache.hadoop.hive.serde2.io.TimestampWritable; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory; import org.apache.hadoop.io.BooleanWritable; import org.apache.hadoop.io.DoubleWritable; import org.apache.hadoop.io.Text; import junit.framework.TestCase; public class TestGenericUDFMonthsBetween extends TestCase { public void testMonthsBetweenForString() throws HiveException { // Default run GenericUDFMonthsBetween udf = new GenericUDFMonthsBetween(); ObjectInspector valueOI1 = PrimitiveObjectInspectorFactory.writableStringObjectInspector; ObjectInspector valueOI2 = PrimitiveObjectInspectorFactory.writableStringObjectInspector; ObjectInspector[] arguments = { valueOI1, valueOI2 }; udf.initialize(arguments); testMonthsBetweenForString(udf); // Run without round-off GenericUDFMonthsBetween udfWithoutRoundOff = new GenericUDFMonthsBetween(); ObjectInspector vOI1 = PrimitiveObjectInspectorFactory.writableStringObjectInspector; ObjectInspector vOI2 = PrimitiveObjectInspectorFactory.writableStringObjectInspector; ObjectInspector vOI3 = PrimitiveObjectInspectorFactory .getPrimitiveWritableConstantObjectInspector(TypeInfoFactory.booleanTypeInfo, new BooleanWritable(false)); ObjectInspector[] args = { vOI1, vOI2, vOI3 }; udfWithoutRoundOff.initialize(args); testMonthsBetweenForString(udf); } public void testMonthsBetweenForString(GenericUDFMonthsBetween udf) throws HiveException { // test month diff with fraction considering time components runTestStr("1995-02-02", "1995-01-01", 1.03225806, udf); runTestStr("2003-07-17", "2005-07-06", -23.64516129, udf); // test the last day of month runTestStr("2001-06-30", "2000-05-31", 13.0, udf); // test the same day of month runTestStr("2000-06-01", "2004-07-01", -49.0, udf); // test February of non-leap year, 2/28 runTestStr("2002-02-28", "2002-03-01", -0.12903226, udf); // test February of non-leap year, 2/31 is viewd as 3/3 due to 3 days diff // from 2/31 to 2/28 runTestStr("2002-02-31", "2002-03-01", 0.06451613, udf); // test Feb of leap year, 2/29 runTestStr("2012-02-29", "2012-03-01", -0.09677419, udf); // test february of leap year, 2/31 is viewed as 3/2 due to 2 days diff from // 2/31 to 2/29 runTestStr("2012-02-31", "2012-03-01", 0.03225806, udf); // time part // test that there is no lead second adjustment runTestStr("1976-01-01 00:00:00", "1975-12-31 23:59:59", 0.00000037, udf); // test UDF considers the difference in time components date1 and date2 runTestStr("1997-02-28 10:30:00", "1996-10-30", 3.94959677, udf); runTestStr("1996-10-30", "1997-02-28 10:30:00", -3.94959677, udf); // if both are last day of the month then time part should be ignored runTestStr("2002-03-31", "2002-02-28", 1.0, udf); runTestStr("2002-03-31", "2002-02-28 10:30:00", 1.0, udf); runTestStr("2002-03-31 10:30:00", "2002-02-28", 1.0, udf); // if the same day of the month then time part should be ignored runTestStr("2002-03-24", "2002-02-24", 1.0, udf); runTestStr("2002-03-24", "2002-02-24 10:30:00", 1.0, udf); runTestStr("2002-03-24 10:30:00", "2002-02-24", 1.0, udf); // partial time. time part will be skipped runTestStr("1995-02-02 10:39", "1995-01-01", 1.03225806, udf); runTestStr("1995-02-02", "1995-01-01 10:39", 1.03225806, udf); // no leading 0 for month and day should work runTestStr("1995-02-2", "1995-1-01", 1.03225806, udf); runTestStr("1995-2-02", "1995-01-1", 1.03225806, udf); // short year should work runTestStr("495-2-02", "495-01-1", 1.03225806, udf); runTestStr("95-2-02", "95-01-1", 1.03225806, udf); runTestStr("5-2-02", "5-01-1", 1.03225806, udf); // Test with null args runTestStr(null, "2002-03-01", null, udf); runTestStr("2002-02-28", null, null, udf); runTestStr(null, null, null, udf); // string dates without day should be parsed to null runTestStr("2002-03", "2002-02-24", null, udf); runTestStr("2002-03-24", "2002-02", null, udf); runTestStr("2003-04-23", "2002-04-24", 11.96774194, udf); } public void testMonthsBetweenForTimestamp() throws HiveException { GenericUDFMonthsBetween udf = new GenericUDFMonthsBetween(); ObjectInspector valueOI1 = PrimitiveObjectInspectorFactory.writableTimestampObjectInspector; ObjectInspector valueOI2 = PrimitiveObjectInspectorFactory.writableTimestampObjectInspector; ObjectInspector[] arguments = { valueOI1, valueOI2 }; udf.initialize(arguments); testMonthsBetweenForTimestamp(udf); // Run without round-off GenericUDFMonthsBetween udfWithoutRoundOff = new GenericUDFMonthsBetween(); ObjectInspector vOI1 = PrimitiveObjectInspectorFactory.writableTimestampObjectInspector; ObjectInspector vOI2 = PrimitiveObjectInspectorFactory.writableTimestampObjectInspector; ObjectInspector vOI3 = PrimitiveObjectInspectorFactory .getPrimitiveWritableConstantObjectInspector(TypeInfoFactory.booleanTypeInfo, new BooleanWritable(false)); ObjectInspector[] args = { vOI1, vOI2, vOI3 }; udfWithoutRoundOff.initialize(args); testMonthsBetweenForTimestamp(udfWithoutRoundOff); } public void testMonthsBetweenForTimestamp(GenericUDFMonthsBetween udf) throws HiveException { // test month diff with fraction considering time components runTestTs("1995-02-02 00:00:00", "1995-01-01 00:00:00", 1.03225806, udf); runTestTs("2003-07-17 00:00:00", "2005-07-06 00:00:00", -23.64516129, udf); // test the last day of month runTestTs("2001-06-30 00:00:00", "2000-05-31 00:00:00", 13.0, udf); // test the same day of month runTestTs("2000-06-01 00:00:00", "2004-07-01 00:00:00", -49.0, udf); // test February of non-leap year, 2/28 runTestTs("2002-02-28 00:00:00", "2002-03-01 00:00:00", -0.12903226, udf); // test February of non-leap year, 2/31 is viewd as 3/3 due to 3 days diff // from 2/31 to 2/28 runTestTs("2002-02-31 00:00:00", "2002-03-01 00:00:00", 0.06451613, udf); // test Feb of leap year, 2/29 runTestTs("2012-02-29 00:00:00", "2012-03-01 00:00:00", -0.09677419, udf); // test february of leap year, 2/31 is viewed as 3/2 due to 2 days diff from // 2/31 to 2/29 runTestTs("2012-02-31 00:00:00", "2012-03-01 00:00:00", 0.03225806, udf); // time part // test that there is no lead second adjustment runTestTs("1976-01-01 00:00:00", "1975-12-31 23:59:59", 0.00000037, udf); // test UDF considers the difference in time components date1 and date2 runTestTs("1997-02-28 10:30:00", "1996-10-30 00:00:00", 3.94959677, udf); runTestTs("1996-10-30 00:00:00", "1997-02-28 10:30:00", -3.94959677, udf); // if both are last day of the month then time part should be ignored runTestTs("2002-03-31 00:00:00", "2002-02-28 00:00:00", 1.0, udf); runTestTs("2002-03-31 00:00:00", "2002-02-28 10:30:00", 1.0, udf); runTestTs("2002-03-31 10:30:00", "2002-02-28 00:00:00", 1.0, udf); // if the same day of the month then time part should be ignored runTestTs("2002-03-24 00:00:00", "2002-02-24 00:00:00", 1.0, udf); runTestTs("2002-03-24 00:00:00", "2002-02-24 10:30:00", 1.0, udf); runTestTs("2002-03-24 10:30:00", "2002-02-24 00:00:00", 1.0, udf); runTestTs("2003-04-23 23:59:59", "2003-03-24 00:0:0", 0.99999963, udf); // Test with null args runTestTs(null, "2002-03-01 00:00:00", null, udf); runTestTs("2002-02-28 00:00:00", null, null, udf); runTestTs(null, null, null, udf); } public void testMonthsBetweenForDate() throws HiveException { GenericUDFMonthsBetween udf = new GenericUDFMonthsBetween(); ObjectInspector valueOI1 = PrimitiveObjectInspectorFactory.writableDateObjectInspector; ObjectInspector valueOI2 = PrimitiveObjectInspectorFactory.writableDateObjectInspector; ObjectInspector[] arguments = { valueOI1, valueOI2 }; udf.initialize(arguments); testMonthsBetweenForDate(udf); // Run without round-off GenericUDFMonthsBetween udfWithoutRoundOff = new GenericUDFMonthsBetween(); ObjectInspector vOI1 = PrimitiveObjectInspectorFactory.writableDateObjectInspector; ObjectInspector vOI2 = PrimitiveObjectInspectorFactory.writableDateObjectInspector; ObjectInspector vOI3 = PrimitiveObjectInspectorFactory .getPrimitiveWritableConstantObjectInspector(TypeInfoFactory.booleanTypeInfo, new BooleanWritable(false)); ObjectInspector[] args = { vOI1, vOI2, vOI3 }; udfWithoutRoundOff.initialize(args); testMonthsBetweenForDate(udfWithoutRoundOff); } public void testMonthsBetweenForDate(GenericUDFMonthsBetween udf) throws HiveException { // test month diff with fraction considering time components runTestDt("1995-02-02", "1995-01-01", 1.03225806, udf); runTestDt("2003-07-17", "2005-07-06", -23.64516129, udf); // test the last day of month runTestDt("2001-06-30", "2000-05-31", 13.0, udf); // test the same day of month runTestDt("2000-06-01", "2004-07-01", -49.0, udf); // test February of non-leap year, 2/28 runTestDt("2002-02-28", "2002-03-01", -0.12903226, udf); // test February of non-leap year, 2/31 is viewd as 3/3 due to 3 days diff // from 2/31 to 2/28 runTestDt("2002-02-31", "2002-03-01", 0.06451613, udf); // test Feb of leap year, 2/29 runTestDt("2012-02-29", "2012-03-01", -0.09677419, udf); // test february of leap year, 2/31 is viewed as 3/2 due to 2 days diff from // 2/31 to 2/29 runTestDt("2012-02-31", "2012-03-01", 0.03225806, udf); // Test with null args runTestDt(null, "2002-03-01", null, udf); runTestDt("2002-02-28", null, null, udf); runTestDt(null, null, null, udf); } protected void runTestStr(String date1, String date2, Double expDiff, GenericUDFMonthsBetween udf) throws HiveException { DeferredJavaObject valueObj1 = new DeferredJavaObject(date1 == null ? null : new Text(date1)); DeferredJavaObject valueObj2 = new DeferredJavaObject(date2 == null ? null : new Text(date2)); DeferredObject[] args = new DeferredObject[] { valueObj1, valueObj2 }; DoubleWritable output = (DoubleWritable) udf.evaluate(args); if (expDiff == null) { assertNull("months_between() test for NULL STRING failed", output); } else { assertNotNull("months_between() test for NOT NULL STRING failed", output); assertEquals("months_between() test for STRING failed", expDiff, output.get(), 0.00000001D); } } protected void runTestTs(String ts1, String ts2, Double expDiff, GenericUDFMonthsBetween udf) throws HiveException { TimestampWritable tsWr1 = ts1 == null ? null : new TimestampWritable(Timestamp.valueOf(ts1)); TimestampWritable tsWr2 = ts2 == null ? null : new TimestampWritable(Timestamp.valueOf(ts2)); DeferredJavaObject valueObj1 = new DeferredJavaObject(tsWr1); DeferredJavaObject valueObj2 = new DeferredJavaObject(tsWr2); DeferredObject[] args = new DeferredObject[] { valueObj1, valueObj2 }; DoubleWritable output = (DoubleWritable) udf.evaluate(args); if (expDiff == null) { assertNull("months_between() test for NULL TIMESTAMP failed", output); } else { assertNotNull("months_between() test for NOT NULL TIMESTAMP failed", output); assertEquals("months_between() test for TIMESTAMP failed", expDiff, output.get(), 0.00000001D); } } protected void runTestDt(String dt1, String dt2, Double expDiff, GenericUDFMonthsBetween udf) throws HiveException { DateWritable dtWr1 = dt1 == null ? null : new DateWritable(Date.valueOf(dt1)); DateWritable dtWr2 = dt2 == null ? null : new DateWritable(Date.valueOf(dt2)); DeferredJavaObject valueObj1 = new DeferredJavaObject(dtWr1); DeferredJavaObject valueObj2 = new DeferredJavaObject(dtWr2); DeferredObject[] args = new DeferredObject[] { valueObj1, valueObj2 }; DoubleWritable output = (DoubleWritable) udf.evaluate(args); if (expDiff == null) { assertNull("months_between() test for NULL DATE failed", output); } else { assertNotNull("months_between() test for NOT NULL DATE failed", output); assertEquals("months_between() test for DATE failed", expDiff, output.get(), 0.00000001D); } } }