/** * Licensed 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.io.parquet.timestamp; import java.sql.Timestamp; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.TimeZone; import java.util.concurrent.TimeUnit; import junit.framework.TestCase; /** * Tests util-libraries used for parquet-timestamp. */ public class TestParquetTimestampConverter extends TestCase { public void testJulianDay() { //check if May 23, 1968 is Julian Day 2440000 Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, 1968); cal.set(Calendar.MONTH, Calendar.MAY); cal.set(Calendar.DAY_OF_MONTH, 23); cal.set(Calendar.HOUR_OF_DAY, 0); cal.setTimeZone(TimeZone.getTimeZone("GMT")); Timestamp ts = new Timestamp(cal.getTimeInMillis()); NanoTime nt = NanoTimeUtils.getNanoTime(ts, false); assertEquals(nt.getJulianDay(), 2440000); Timestamp tsFetched = NanoTimeUtils.getTimestamp(nt, false); assertEquals(tsFetched, ts); //check if 30 Julian Days between Jan 1, 2005 and Jan 31, 2005. Calendar cal1 = Calendar.getInstance(); cal1.set(Calendar.YEAR, 2005); cal1.set(Calendar.MONTH, Calendar.JANUARY); cal1.set(Calendar.DAY_OF_MONTH, 1); cal1.set(Calendar.HOUR_OF_DAY, 0); cal1.setTimeZone(TimeZone.getTimeZone("GMT")); Timestamp ts1 = new Timestamp(cal1.getTimeInMillis()); NanoTime nt1 = NanoTimeUtils.getNanoTime(ts1, false); Timestamp ts1Fetched = NanoTimeUtils.getTimestamp(nt1, false); assertEquals(ts1Fetched, ts1); Calendar cal2 = Calendar.getInstance(); cal2.set(Calendar.YEAR, 2005); cal2.set(Calendar.MONTH, Calendar.JANUARY); cal2.set(Calendar.DAY_OF_MONTH, 31); cal2.set(Calendar.HOUR_OF_DAY, 0); cal2.setTimeZone(TimeZone.getTimeZone("UTC")); Timestamp ts2 = new Timestamp(cal2.getTimeInMillis()); NanoTime nt2 = NanoTimeUtils.getNanoTime(ts2, false); Timestamp ts2Fetched = NanoTimeUtils.getTimestamp(nt2, false); assertEquals(ts2Fetched, ts2); assertEquals(nt2.getJulianDay() - nt1.getJulianDay(), 30); //check if 1464305 Julian Days between Jan 1, 2005 BC and Jan 31, 2005. cal1 = Calendar.getInstance(); cal1.set(Calendar.ERA, GregorianCalendar.BC); cal1.set(Calendar.YEAR, 2005); cal1.set(Calendar.MONTH, Calendar.JANUARY); cal1.set(Calendar.DAY_OF_MONTH, 1); cal1.set(Calendar.HOUR_OF_DAY, 0); cal1.setTimeZone(TimeZone.getTimeZone("GMT")); ts1 = new Timestamp(cal1.getTimeInMillis()); nt1 = NanoTimeUtils.getNanoTime(ts1, false); ts1Fetched = NanoTimeUtils.getTimestamp(nt1, false); assertEquals(ts1Fetched, ts1); cal2 = Calendar.getInstance(); cal2.set(Calendar.YEAR, 2005); cal2.set(Calendar.MONTH, Calendar.JANUARY); cal2.set(Calendar.DAY_OF_MONTH, 31); cal2.set(Calendar.HOUR_OF_DAY, 0); cal2.setTimeZone(TimeZone.getTimeZone("UTC")); ts2 = new Timestamp(cal2.getTimeInMillis()); nt2 = NanoTimeUtils.getNanoTime(ts2, false); ts2Fetched = NanoTimeUtils.getTimestamp(nt2, false); assertEquals(ts2Fetched, ts2); assertEquals(nt2.getJulianDay() - nt1.getJulianDay(), 1464305); } public void testNanos() { //case 1: 01:01:01.0000000001 Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, 1968); cal.set(Calendar.MONTH, Calendar.MAY); cal.set(Calendar.DAY_OF_MONTH, 23); cal.set(Calendar.HOUR_OF_DAY, 1); cal.set(Calendar.MINUTE, 1); cal.set(Calendar.SECOND, 1); cal.setTimeZone(TimeZone.getTimeZone("GMT")); Timestamp ts = new Timestamp(cal.getTimeInMillis()); ts.setNanos(1); //(1*60*60 + 1*60 + 1) * 10e9 + 1 NanoTime nt = NanoTimeUtils.getNanoTime(ts, false); assertEquals(nt.getTimeOfDayNanos(), 3661000000001L); //case 2: 23:59:59.999999999 cal = Calendar.getInstance(); cal.set(Calendar.YEAR, 1968); cal.set(Calendar.MONTH, Calendar.MAY); cal.set(Calendar.DAY_OF_MONTH, 23); cal.set(Calendar.HOUR_OF_DAY, 23); cal.set(Calendar.MINUTE, 59); cal.set(Calendar.SECOND, 59); cal.setTimeZone(TimeZone.getTimeZone("GMT")); ts = new Timestamp(cal.getTimeInMillis()); ts.setNanos(999999999); //(23*60*60 + 59*60 + 59)*10e9 + 999999999 nt = NanoTimeUtils.getNanoTime(ts, false); assertEquals(nt.getTimeOfDayNanos(), 86399999999999L); //case 3: verify the difference. Calendar cal2 = Calendar.getInstance(); cal2.set(Calendar.YEAR, 1968); cal2.set(Calendar.MONTH, Calendar.MAY); cal2.set(Calendar.DAY_OF_MONTH, 23); cal2.set(Calendar.HOUR_OF_DAY, 0); cal2.set(Calendar.MINUTE, 10); cal2.set(Calendar.SECOND, 0); cal2.setTimeZone(TimeZone.getTimeZone("GMT")); Timestamp ts2 = new Timestamp(cal2.getTimeInMillis()); ts2.setNanos(10); Calendar cal1 = Calendar.getInstance(); cal1.set(Calendar.YEAR, 1968); cal1.set(Calendar.MONTH, Calendar.MAY); cal1.set(Calendar.DAY_OF_MONTH, 23); cal1.set(Calendar.HOUR_OF_DAY, 0); cal1.set(Calendar.MINUTE, 0); cal1.set(Calendar.SECOND, 0); cal1.setTimeZone(TimeZone.getTimeZone("GMT")); Timestamp ts1 = new Timestamp(cal1.getTimeInMillis()); ts1.setNanos(1); NanoTime n2 = NanoTimeUtils.getNanoTime(ts2, false); NanoTime n1 = NanoTimeUtils.getNanoTime(ts1, false); assertEquals(n2.getTimeOfDayNanos() - n1.getTimeOfDayNanos(), 600000000009L); NanoTime n3 = new NanoTime(n1.getJulianDay() - 1, n1.getTimeOfDayNanos() + TimeUnit.DAYS.toNanos(1)); assertEquals(ts1, NanoTimeUtils.getTimestamp(n3, false)); n3 = new NanoTime(n1.getJulianDay() + 3, n1.getTimeOfDayNanos() - TimeUnit.DAYS.toNanos(3)); assertEquals(ts1, NanoTimeUtils.getTimestamp(n3, false)); } public void testTimezone() { Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, 1968); cal.set(Calendar.MONTH, Calendar.MAY); cal.set(Calendar.DAY_OF_MONTH, 23); cal.set(Calendar.HOUR_OF_DAY, 17); cal.set(Calendar.MINUTE, 1); cal.set(Calendar.SECOND, 1); cal.setTimeZone(TimeZone.getTimeZone("US/Pacific")); Timestamp ts = new Timestamp(cal.getTimeInMillis()); ts.setNanos(1); /** * 17:00 PDT = 00:00 GMT (daylight-savings) * (0*60*60 + 1*60 + 1)*10e9 + 1 = 61000000001, or * * 17:00 PST = 01:00 GMT (if not daylight savings) * (1*60*60 + 1*60 + 1)*10e9 + 1 = 3661000000001 */ NanoTime nt = NanoTimeUtils.getNanoTime(ts, false); long timeOfDayNanos = nt.getTimeOfDayNanos(); assertTrue(timeOfDayNanos == 61000000001L || timeOfDayNanos == 3661000000001L); //in both cases, this will be the next day in GMT assertEquals(nt.getJulianDay(), 2440001); } public void testTimezoneless() { Timestamp ts1 = Timestamp.valueOf("2011-01-01 00:30:30.111111111"); NanoTime nt1 = NanoTimeUtils.getNanoTime(ts1, true); assertEquals(nt1.getJulianDay(), 2455563); assertEquals(nt1.getTimeOfDayNanos(), 1830111111111L); Timestamp ts1Fetched = NanoTimeUtils.getTimestamp(nt1, true); assertEquals(ts1Fetched.toString(), ts1.toString()); Timestamp ts2 = Timestamp.valueOf("2011-02-02 08:30:30.222222222"); NanoTime nt2 = NanoTimeUtils.getNanoTime(ts2, true); assertEquals(nt2.getJulianDay(), 2455595); assertEquals(nt2.getTimeOfDayNanos(), 30630222222222L); Timestamp ts2Fetched = NanoTimeUtils.getTimestamp(nt2, true); assertEquals(ts2Fetched.toString(), ts2.toString()); } public void testTimezoneValues() { // Test with different timezone IDs strings valueTest(Calendar.getInstance(TimeZone.getTimeZone("GMT"))); valueTest(Calendar.getInstance(TimeZone.getTimeZone("CST"))); valueTest(Calendar.getInstance(TimeZone.getTimeZone("CST"))); valueTest(Calendar.getInstance(TimeZone.getTimeZone("PST"))); valueTest(Calendar.getInstance(TimeZone.getTimeZone("UTC"))); valueTest(Calendar.getInstance(TimeZone.getTimeZone("America/Los_Angeles"))); valueTest(Calendar.getInstance(TimeZone.getTimeZone("US/Pacific"))); valueTest(Calendar.getInstance(TimeZone.getTimeZone("Etc/GMT+7"))); valueTest(Calendar.getInstance(TimeZone.getTimeZone("Etc/GMT-1"))); valueTest(Calendar.getInstance(TimeZone.getTimeZone("Mexico/General"))); valueTest(Calendar.getInstance(TimeZone.getDefault())); } private void valueTest(Calendar calendar) { //exercise a broad range of timestamps close to the present. verifyTsString("2011-01-01 01:01:01.111111111", calendar); verifyTsString("2012-02-02 02:02:02.222222222", calendar); verifyTsString("2013-03-03 03:03:03.333333333", calendar); verifyTsString("2014-04-04 04:04:04.444444444", calendar); verifyTsString("2015-05-05 05:05:05.555555555", calendar); verifyTsString("2016-06-06 06:06:06.666666666", calendar); verifyTsString("2017-07-07 07:07:07.777777777", calendar); verifyTsString("2018-08-08 08:08:08.888888888", calendar); verifyTsString("2019-09-09 09:09:09.999999999", calendar); verifyTsString("2020-10-10 10:10:10.101010101", calendar); verifyTsString("2021-11-11 11:11:11.111111111", calendar); verifyTsString("2022-12-12 12:12:12.121212121", calendar); verifyTsString("2023-01-02 13:13:13.131313131", calendar); verifyTsString("2024-02-02 14:14:14.141414141", calendar); verifyTsString("2025-03-03 15:15:15.151515151", calendar); verifyTsString("2026-04-04 16:16:16.161616161", calendar); verifyTsString("2027-05-05 17:17:17.171717171", calendar); verifyTsString("2028-06-06 18:18:18.181818181", calendar); verifyTsString("2029-07-07 19:19:19.191919191", calendar); verifyTsString("2030-08-08 20:20:20.202020202", calendar); verifyTsString("2031-09-09 21:21:21.212121212", calendar); //test some extreme cases. verifyTsString("9999-09-09 09:09:09.999999999", calendar); verifyTsString("0001-01-01 00:00:00.0", calendar); } private void verifyTsString(String tsString, Calendar calendar) { Timestamp ts = Timestamp.valueOf(tsString); NanoTime nt = NanoTimeUtils.getNanoTime(ts, calendar); Timestamp tsFetched = NanoTimeUtils.getTimestamp(nt, calendar); assertEquals(tsString, tsFetched.toString()); } }