diff --git a/docs/user/BuiltInFunctions.md b/docs/user/BuiltInFunctions.md index 98c9f9cfcd..5408504719 100644 --- a/docs/user/BuiltInFunctions.md +++ b/docs/user/BuiltInFunctions.md @@ -764,3 +764,62 @@ Examples ```sql UTCNOW() -- 2017-10-13T16:02:11.123Z ``` + +### UNIX_TIMESTAMP + +With no `timestamp` argument, returns the number of seconds since the last epoch ('1970-01-01 00:00:00' UTC). + +With a `timestamp` argument, returns the number of seconds from the last epoch to the given `timestamp` +(possibly negative). + +Signature : `UNIX_TIMESTAMP: [Timestamp] -> Integer|Decimal` + +Header : `UNIX_TIMESTAMP([timestamp])` + +Purpose : `UNIX_TIMESTAMP()` called without a `timestamp` argument returns the number of whole seconds since the last +epoch ('1970-01-01 00:00:00' UTC) as an Integer using `UTCNOW`. + +`UNIX_TIMESTAMP()` called with a `timestamp` argument returns returns the number of seconds from the last epoch to the +`timestamp` argument. +If given a `timestamp` before the last epoch, `UNIX_TIMESTAMP` will return the number of seconds before the last epoch as a negative +number. +The return value will be a Decimal if and only if the given `timestamp` has a fractional seconds part. + +Examples : +```sql +UNIX_TIMESTAMP() -- 1507910531 (if current time is `2017-10-13T16:02:11Z`; # of seconds since last epoch as an Integer) +UNIX_TIMESTAMP(`2020T`) -- 1577836800 (seconds from 2020 to the last epoch as an Integer) +UNIX_TIMESTAMP(`2020-01T`) -- '' +UNIX_TIMESTAMP(`2020-01-01T`) -- '' +UNIX_TIMESTAMP(`2020-01-01T00:00Z`) -- '' +UNIX_TIMESTAMP(`2020-01-01T00:00:00Z`) -- '' +UNIX_TIMESTAMP(`2020-01-01T00:00:00.0Z`) -- 1577836800. (seconds from 2020 to the last epoch as a Decimal) +UNIX_TIMESTAMP(`2020-01-01T00:00:00.00Z`) -- '' +UNIX_TIMESTAMP(`2020-01-01T00:00:00.000Z`) -- '' +UNIX_TIMESTAMP(`2020-01-01T00:00:00.100Z`) -- 1577836800.1 +UNIX_TIMESTAMP(`1969T`) -- -31536000 (timestamp is before last epoch) +``` + +### FROM_UNIXTIME + +Converts the given unix epoch into a timestamp. + +Signature : `FROM_UNIXTIME: Integer|Decimal -> Timestamp` + +Header : `FROM_UNIXTIME(unix_timestamp)` + +Purpose : When given a non-negative numeric value, returns a timestamp after the last epoch. +When given a negative numeric value, returns a timestamp before the last epoch. +The returned timestamp has fractional seconds depending on if the value is a decimal. + +Examples : +```sql +FROM_UNIXTIME(-1) -- `1969-12-31T23:59:59-00:00` (negative unix_timestamp; returns timestamp before last epoch) +FROM_UNIXTIME(-0.1) -- `1969-12-31T23:59:59.9-00:00` (unix_timestamp is decimal so timestamp has fractional seconds) +FROM_UNIXTIME(0) -- `1970-01-01T00:00:00.000-00:00` +FROM_UNIXTIME(0.001) -- `1970-01-01T00:00:00.001-00:00` (decimal precision to fractional second precision) +FROM_UNIXTIME(0.01) -- `1970-01-01T00:00:00.01-00:00` +FROM_UNIXTIME(0.1) -- `1970-01-01T00:00:00.1-00:00` +FROM_UNIXTIME(1) -- `1970-01-01T00:00:01-00:00` +FROM_UNIXTIME(1577836800) -- `2020-01-01T00:00:00-00:00` (unix_timestamp is Integer so no fractional seconds) +``` diff --git a/lang/src/org/partiql/lang/eval/builtins/FromUnixTimeFunction.kt b/lang/src/org/partiql/lang/eval/builtins/FromUnixTimeFunction.kt index 12122673d7..595cc4a704 100644 --- a/lang/src/org/partiql/lang/eval/builtins/FromUnixTimeFunction.kt +++ b/lang/src/org/partiql/lang/eval/builtins/FromUnixTimeFunction.kt @@ -15,9 +15,10 @@ import java.math.BigDecimal * Syntax: `FROM_UNIXTIME(unix_timestamp)` * Where unix_timestamp is a non-negative (potentially decimal) numeric value. * - * When given a negative numeric value, this function returns a PartiQL `NULL` [ExprValue]. - * When given a non-negative numeric value, this function returns a PartiQL `TIMESTAMP` [ExprValue] that has fractional - * seconds depending on if the value is a decimal. + * When given a negative numeric value, this function returns a PartiQL `TIMESTAMP` [ExprValue] before the last epoch. + * When given a non-negative numeric value, this function returns a PartiQL `TIMESTAMP` [ExprValue] after the last + * epoch. + * The returned `TIMESTAMP` has fractional seconds depending on if the value is a decimal. */ internal class FromUnixTimeFunction(valueFactory: ExprValueFactory) : NullPropagatingExprFunction("from_unixtime", 1, valueFactory) { private val millisPerSecond = BigDecimal(1000) @@ -27,10 +28,6 @@ internal class FromUnixTimeFunction(valueFactory: ExprValueFactory) : NullPropag val numMillis = unixTimestamp.times(millisPerSecond).stripTrailingZeros() - if (unixTimestamp < BigDecimal.ZERO) { - return valueFactory.nullValue - } - val timestamp = Timestamp.forMillis(numMillis, null) return valueFactory.newTimestamp(timestamp) } diff --git a/lang/src/org/partiql/lang/eval/builtins/UnixTimestampFunction.kt b/lang/src/org/partiql/lang/eval/builtins/UnixTimestampFunction.kt index 020cff9804..978b3faf5d 100644 --- a/lang/src/org/partiql/lang/eval/builtins/UnixTimestampFunction.kt +++ b/lang/src/org/partiql/lang/eval/builtins/UnixTimestampFunction.kt @@ -17,11 +17,11 @@ import java.math.BigDecimal * '1970-01-01 00:00:00' UTC as a PartiQL `INT` [ExprValue] * * If UNIX_TIMESTAMP() is called with a [timestamp] argument, it returns the number of seconds from - * '1970-01-01 00:00:00' UTC to the given [timestamp] argument. The return value will be a decimal if and only if - * the given [timestamp] has a fractional seconds part. + * '1970-01-01 00:00:00' UTC to the given [timestamp] argument. If given a [timestamp] before the last epoch, will + * return the number of seconds before the last epoch as a negative number. The return value will be a decimal if and + * only if the given [timestamp] has a fractional seconds part. * - * The valid range of argument values is from '1970-01-01 00:00:01.000000' UTC up to the maximum PartiQL `TIMESTAMP` - * value. If given a [timestamp] out of this range, UNIX_TIMESTAMP() will return 0. + * The valid range of argument values is the range of PartiQL's `TIMESTAMP` value. */ internal class UnixTimestampFunction(valueFactory: ExprValueFactory) : NullPropagatingExprFunction("unix_timestamp", 0..1, valueFactory) { private val millisPerSecond = BigDecimal(1000) @@ -34,11 +34,6 @@ internal class UnixTimestampFunction(valueFactory: ExprValueFactory) : NullPropa } val numMillis = timestamp.decimalMillis - - if (numMillis < BigDecimal.ZERO) { - return valueFactory.newInt(0) - } - val epochTime = numMillis.divide(millisPerSecond) if (timestamp.decimalSecond.scale() == 0 || args.isEmpty()) { diff --git a/lang/test/org/partiql/lang/eval/builtins/FromUnixTimeFunctionTest.kt b/lang/test/org/partiql/lang/eval/builtins/FromUnixTimeFunctionTest.kt index c763c81971..b8741c9dc7 100644 --- a/lang/test/org/partiql/lang/eval/builtins/FromUnixTimeFunctionTest.kt +++ b/lang/test/org/partiql/lang/eval/builtins/FromUnixTimeFunctionTest.kt @@ -46,10 +46,10 @@ class FromUnixTimeFunctionTest : EvaluatorTestBase() { class FromUnixTimeTests : ArgumentsProviderBase() { override fun getParameters(): List = listOf( - // negative unix epochs output null - FromUnixTimeTestCase("from_unixtime(-1)", "null"), - FromUnixTimeTestCase("from_unixtime(-0.1)", "null"), - // non-negative cases outputting a timestamp + // negative unix epochs output timestamp before last epoch + FromUnixTimeTestCase("from_unixtime(-1)", "1969-12-31T23:59:59-00:00"), + FromUnixTimeTestCase("from_unixtime(-0.1)", "1969-12-31T23:59:59.9-00:00"), + // non-negative cases outputting a timestamp after last epoch FromUnixTimeTestCase("from_unixtime(0)", "1970-01-01T00:00:00.000-00:00"), FromUnixTimeTestCase("from_unixtime(0.001)", "1970-01-01T00:00:00.001-00:00"), FromUnixTimeTestCase("from_unixtime(0.01)", "1970-01-01T00:00:00.01-00:00"), diff --git a/lang/test/org/partiql/lang/eval/builtins/UnixTimestampFunctionTest.kt b/lang/test/org/partiql/lang/eval/builtins/UnixTimestampFunctionTest.kt index bc0eb5a39f..21f026914d 100644 --- a/lang/test/org/partiql/lang/eval/builtins/UnixTimestampFunctionTest.kt +++ b/lang/test/org/partiql/lang/eval/builtins/UnixTimestampFunctionTest.kt @@ -66,8 +66,8 @@ class UnixTimestampFunctionTest : EvaluatorTestBase() { override fun getParameters(): List = listOf( // time before the last epoch - UnixTimestampOneArgTestCase("unix_timestamp(`1969T`)", "0"), - UnixTimestampOneArgTestCase("unix_timestamp(`1969-12-31T23:59:59.999Z`)", "0"), + UnixTimestampOneArgTestCase("unix_timestamp(`1969T`)", "-31536000"), + UnixTimestampOneArgTestCase("unix_timestamp(`1969-12-31T23:59:59.999Z`)", "-0.001"), // exactly the last epoch UnixTimestampOneArgTestCase("unix_timestamp(`1970T`)", "0"), UnixTimestampOneArgTestCase("unix_timestamp(`1970-01-01T00:00:00.000Z`)", "0."),