【问题标题】:Hive function: add month to dateHive 功能:添加月份到日期
【发布时间】:2014-12-19 14:18:52
【问题描述】:

我正在 Hive 中搜索一个函数,它将添加月份至今。

例如:

add_month('2014-01-01',1) -> '2014-02-01'
add_month('2013-12-01',1) -> '2014-01-01'

【问题讨论】:

  • 如果在 1 月 31 日加上 1 个月会怎样?
  • 我的情况比较简单,我总是需要在月份的第一天加上1个月,例如:2014-01-01 -> 2014-02-01; 2013-12-01 -> 2014-01-01
  • 在标准 SQL 中,这将是 date '2014-01-01' + interval '1' month。不知道 Hive 是否支持 SQL 标准。

标签: date hive


【解决方案1】:

只需输入:

 select add_months('2014-01-01', 1);

【讨论】:

    【解决方案2】:

    您可以创建通用 UDF (GenericUDF)。

    这是一个示例 UDF:

    import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
    import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
    import org.apache.hadoop.hive.ql.metadata.HiveException;
    import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
    import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
    import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorUtils;
    import org.apache.hadoop.hive.serde2.objectinspector.primitive.IntObjectInspector;
    import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
    import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;
    import org.joda.time.LocalDate;
    import org.joda.time.format.DateTimeFormat;
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.Text;
    
    public class AddMonth extends GenericUDF {
    
        @Override
        public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
            if (arguments.length != 2) {
                throw new UDFArgumentLengthException("The function add_month(local_date, months_to_add) requires 2 arguments.");
            }
    
            ObjectInspector localDateVal = arguments[0];
            ObjectInspector monthsToAddVal = arguments[1];
    
            if (!(localDateVal instanceof StringObjectInspector)) {
                throw new UDFArgumentException("First argument must be of type String (local_date as String)");
            }
            if (!(monthsToAddVal instanceof IntObjectInspector)) {
                throw new UDFArgumentException("Second argument must be of type int (Month to add)");
            }
            return PrimitiveObjectInspectorFactory.writableStringObjectInspector;
        }
    
        @Override
        public Object evaluate(DeferredObject[] arguments) throws HiveException {
            String localDateVal = (String) ObjectInspectorUtils.copyToStandardJavaObject(arguments[0].get(),
                    PrimitiveObjectInspectorFactory.javaStringObjectInspector);
            IntWritable monthsToAddVal = (IntWritable) ObjectInspectorUtils.copyToStandardJavaObject(arguments[1].get(),
                    PrimitiveObjectInspectorFactory.javaIntObjectInspector);
    
            LocalDate localDate = null;
            try {
                localDate = LocalDate.parse(localDateVal, DateTimeFormat.forPattern("yyyy-MM-dd"));
            } catch (Exception ex) {
                return null;
            }
    
            return new Text(localDate.plusMonths(monthsToAddVal.get().toString());
        }
    
        @Override
        public String getDisplayString(String[] arguments) {
            assert (arguments.length == 2);
            return "add_month(" + arguments[0] + ", " + arguments[1] + ")";
        }
    }
    

    证明正确性的测试用例:

    import static org.hamcrest.CoreMatchers.is;
    import static org.junit.Assert.assertNull;
    import static org.junit.Assert.assertThat;
    
    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.objectinspector.ObjectInspector;
    import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
    import org.junit.Test;
    
    public class AddMonthTest {
        private final String TEST_DATA = "2014-01-01";
        private final AddMonth addMonth = new AddMonth();
        ObjectInspector ob = PrimitiveObjectInspectorFactory.javaStringObjectInspector;
        ObjectInspector ob1 = PrimitiveObjectInspectorFactory.javaIntObjectInspector;
        private final ObjectInspector[]arg = { ob, ob1 };
    
        @Test
        public void testAdd1Month() throws Exception {
            DeferredJavaObject def1 = new DeferredJavaObject(TEST_DATA);
            DeferredJavaObject def2 = new DeferredJavaObject(1);
    
            addMonth.initialize(arg);
    
            DeferredObject[] def = { def1, def2 };
            String resultData = addMonth.evaluate(def).toString();
            assertThat(resultData, is("2014-02-01"));
        }
    
        @Test
        public void testAdd12Month() throws Exception {
            DeferredJavaObject def1 = new DeferredJavaObject(TEST_DATA);
            DeferredJavaObject def2 = new DeferredJavaObject(12);
    
            addMonth.initialize(arg);
    
            DeferredObject[] def = { def1, def2 };
            String resultData = addMonth.evaluate(def).toString();
            assertThat(resultData, is("2015-01-01"));
        }
    
        @Test
        public void testSub1Month() throws Exception {
            DeferredJavaObject def1 = new DeferredJavaObject(TEST_DATA);
            DeferredJavaObject def2 = new DeferredJavaObject(-1);
    
            addMonth.initialize(arg);
    
            DeferredObject[] def = { def1, def2 };
            String resultData = addMonth.evaluate(def).toString();
            assertThat(resultData, is("2013-12-01"));
        }
    
        @Test
        public void testSub12Month() throws Exception {
            DeferredJavaObject def1 = new DeferredJavaObject(TEST_DATA);
            DeferredJavaObject def2 = new DeferredJavaObject(-12);
    
            addMonth.initialize(arg);
    
            DeferredObject[] def = { def1, def2 };
            String resultData = addMonth.evaluate(def).toString();
            assertThat(resultData, is("2013-01-01"));
        }
    
        @Test
        public void incorrectInput() throws Exception {
            DeferredJavaObject def1 = new DeferredJavaObject("InvalidString");
            DeferredJavaObject def2 = new DeferredJavaObject(12);
    
            addMonth.initialize(arg);
    
            DeferredObject[] def = { def1, def2 };
            Object resultData = addMonth.evaluate(def);
            assertNull(resultData);
        }
    }
    

    你可以使用如下函数:

    CREATE TEMPORARY FUNCTION add_month AS 'AddMonth';
    
    SELECT
        add_month ('2014-01-01',1) 
    FROM
        TAB_NAME;
    

    预期输出将是:

    2014-02-01
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多