TIMESTAMP_NTZ is a timezone-free timestamp type in the MaxCompute V2.0 data type edition. It stores the exact "wall-clock" time you write and always returns that value unchanged, regardless of the session time zone. This makes time comparisons and arithmetic predictable without requiring any timezone conversion.
How it works
TIMESTAMP and TIMESTAMP_NTZ store time differently:
| TIMESTAMP | TIMESTAMP_NTZ | |
|---|---|---|
| Internal storage | UTC offset from epoch (1970-01-01 00:00:00 UTC) | Wall-clock time, no time zone reference |
| Display behavior | Adjusted to the current session time zone | Always returns the value as written |
| Time zone conversion | Required on read | None |
| SQL standard | Hive 2 compatible | SQL:2003 / Hive 3 compatible |
For example, a TIMESTAMP value written as 1970-01-01 00:00:00 in UTC+8 displays as 1969-12-31 16:00:00 when the session switches to UTC. The same input stored as TIMESTAMP_NTZ always displays as 1970-01-01 00:00:00, regardless of the session time zone.
The following example demonstrates this difference. Enable the MaxCompute V2.0 data type edition and set the time zone to UTC+8 (the default for MaxCompute projects):
-- Enable the MaxCompute V2.0 data type edition
SET odps.sql.type.system.odps2=true;
-- Confirm the current time zone (default: Asia/Shanghai, which is UTC+8)
setproject;
-- If your project time zone is not UTC+8, set it explicitly
SET odps.sql.timezone=Asia/Shanghai;Create a table with both types and insert the same timestamp value:
-- Create a table with both types for comparison
CREATE TABLE ts_test02(a timestamp, b timestamp_ntz);
INSERT INTO TABLE ts_test02 VALUES(timestamp '1970-01-01 00:00:00', timestamp_ntz '1970-01-01 00:00:00');
-- Query results in UTC+8
SELECT * FROM ts_test02;Output:
+---------------------+---------------------+
| a | b |
+---------------------+---------------------+
| 1970-01-01 00:00:00 | 1970-01-01 00:00:00 |
+---------------------+---------------------+Switch the session time zone to UTC and query again:
SET odps.sql.timezone=UTC;
SELECT * FROM ts_test02;Output — field a (TIMESTAMP) shifts by 8 hours; field b (TIMESTAMP_NTZ) is unchanged:
+---------------------+---------------------+
| a | b |
+---------------------+---------------------+
| 1969-12-31 16:00:00 | 1970-01-01 00:00:00 |
+---------------------+---------------------+Prerequisites
Before you begin, ensure that you have:
The MaxCompute V2.0 data type edition enabled (
SET odps.sql.type.system.odps2=true)(For UDF examples) SQL statements submitted in script mode — see SQL in script mode
Limitations
Hologres: Cannot read or write TIMESTAMP_NTZ data.
Platform for AI (PAI): AlgoTask and PS jobs cannot read or write TIMESTAMP_NTZ data.
MaxCompute client (odpscmd): Version 0.46 or later is required.
Use TIMESTAMP_NTZ in a table
After enabling the MaxCompute V2.0 data type edition, use timestamp_ntz as the column type in CREATE TABLE:
SET odps.sql.type.system.odps2=true;
CREATE TABLE ts_test01(ts timestamp_ntz) lifecycle 1;
INSERT INTO TABLE ts_test01 VALUES(timestamp_ntz '1970-01-01 00:00:00');
SELECT * FROM ts_test01;Output:
+---------------------+
| ts |
+---------------------+
| 1970-01-01 00:00:00 |
+---------------------+Generate TIMESTAMP_NTZ values
Literals
Use the TIMESTAMP_NTZ keyword followed by a datetime string:
-- Returns 2017-11-11 00:00:00.123456789
SELECT TIMESTAMP_NTZ '2017-11-11 00:00:00.123456789';Type conversion with CAST
Use the CAST function to convert other types to TIMESTAMP_NTZ. All examples require the MaxCompute V2.0 data type edition.
Time types to TIMESTAMP_NTZ
SET odps.sql.type.system.odps2=true;
SELECT
cast(date '1970-01-01' AS timestamp_ntz) AS date_cast_result,
cast(datetime '1970-01-01 00:00:00' AS timestamp_ntz) AS datetime_cast_result,
cast(timestamp '1970-01-01 00:00:00' AS timestamp_ntz) AS timestamp_cast_result;Output:
+---------------------+---------------------+-----------------------+
| date_cast_result | datetime_cast_result | timestamp_cast_result |
+---------------------+---------------------+-----------------------+
| 1970-01-01 00:00:00 | 1970-01-01 00:00:00 | 1970-01-01 00:00:00 |
+---------------------+---------------------+-----------------------+Numeric types to TIMESTAMP_NTZ
SET odps.sql.type.system.odps2=true;
SELECT
cast(1L AS timestamp_ntz) AS bigint_cast_result,
cast(1BD AS timestamp_ntz) AS decimal_cast_result,
cast(1.5f AS timestamp_ntz) AS float_cast_result,
cast(1.5 AS timestamp_ntz) AS double_cast_result;Output:
+---------------------+---------------------+-----------------------+---------------------+
| bigint_cast_result | decimal_cast_result | float_cast_result | double_cast_result |
+---------------------+---------------------+-----------------------+---------------------+
| 1970-01-01 00:00:01 | 1970-01-01 00:00:01 | 1970-01-01 00:00:01.5 | 1970-01-01 00:00:01.5 |
+---------------------+---------------------+-----------------------+---------------------+String types to TIMESTAMP_NTZ
SET odps.sql.type.system.odps2=true;
SELECT
cast(s AS timestamp_ntz) AS string_cast_result,
cast(cast(s AS char(50)) AS timestamp_ntz) AS char_cast_result,
cast(cast(s AS varchar(100)) AS timestamp_ntz) AS varchar_cast_result
FROM VALUES('1970-01-01 00:00:01.2345') AS t(s);Output:
+--------------------------+--------------------------+------------------------------+
| string_cast_result | char_cast_result | varchar_cast_result |
+--------------------------+--------------------------+------------------------------+
| 1970-01-01 00:00:01.2345 | 1970-01-01 00:00:01.2345 | 1970-01-01 00:00:01.2345 |
+--------------------------+--------------------------+------------------------------+Function return values
The functions FROM_UTC_TIMESTAMP, TO_UTC_TIMESTAMP, and CURRENT_TIMESTAMP return TIMESTAMP by default. Set odps.sql.timestamp.function.ntz=true to make them return TIMESTAMP_NTZ instead:
SET odps.sql.type.system.odps2=true;
SET odps.sql.timestamp.function.ntz=true;
SELECT
current_timestamp() AS current_result,
from_utc_timestamp(0L, 'UTC') AS from_result,
to_utc_timestamp(0L, 'UTC') AS to_result;Output (the current_result value reflects the actual system time at execution):
+-------------------------+---------------------+---------------------+
| current_result | from_result | to_result |
+-------------------------+---------------------+---------------------+
| 2023-07-01 21:22:39.066 | 1970-01-01 00:00:00 | 1970-01-01 00:00:00 |
+-------------------------+---------------------+---------------------+To confirm the return types, run EXPLAIN on the query:
EXPLAIN SELECT current_timestamp() AS current_result, from_utc_timestamp(0L, 'UTC') AS from_result, to_utc_timestamp(0L, 'UTC') AS to_result;The execution plan shows all three output fields as timestamp_ntz:
FS: output: Screen
schema:
current_result (timestamp_ntz)
from_result (timestamp_ntz)
to_result (timestamp_ntz)Supported operations
Relational operators
TIMESTAMP_NTZ supports all standard relational operators. For more information, see Relational operators.
SET odps.sql.type.system.odps2=true;
-- Equals (=), Not Equals (!=), and Eqns (<=>)
SELECT
a = b AS eq_result,
a != b AS neq_result,
a <=> b AS eqns_result
FROM VALUES(timestamp_ntz '1970-01-01 00:00:00', timestamp_ntz '1970-01-01 00:00:00') AS t(a, b);
-- Output: true | false | true
-- GT (>), GE (>=), LT (<), LE (<=)
SELECT
a > b AS gt_result,
a >= b AS ge_result,
a < b AS lt_result,
a <= b AS le_result
FROM VALUES(timestamp_ntz '1970-01-01 00:00:00', timestamp_ntz '1970-01-01 00:00:00') AS t(a, b);
-- Output: false | true | false | trueArithmetic operations
For more information, see Operators.
Subtract two TIMESTAMP_NTZ values — the result is INTERVAL_DAY_TIME:
SET odps.sql.type.system.odps2=true;
SELECT timestamp_ntz '1970-01-01 00:01:30' - timestamp_ntz '1970-01-01 00:00:00';
-- Output: 0 00:01:30.000000000Add or subtract INTERVAL_YEAR_MONTH:
SET odps.sql.type.system.odps2=true;
SELECT a+b AS plus_result, a-b AS minus_result
FROM VALUES(timestamp_ntz '1970-01-01 00:00:00', interval '1' year) AS t(a, b);
-- Output: plus_result=1971-01-01 00:00:00 | minus_result=1969-01-01 00:00:00Add or subtract INTERVAL_DAY_TIME:
SET odps.sql.type.system.odps2=true;
SELECT a+b AS plus_result, a-b AS minus_result
FROM VALUES(timestamp_ntz '1970-01-01 00:00:00', interval '1' day) AS t(a, b);
-- Output: plus_result=1970-01-02 00:00:00 | minus_result=1969-12-31 00:00:00Date and time functions
Date and time functions accept both TIMESTAMP and TIMESTAMP_NTZ as input. For the full function reference, see Date functions.
SET odps.sql.type.system.odps2=true;
-- DATEADD: add 1 day to both types
SELECT dateadd(a, 1, 'dd') AS a_result, dateadd(b, 1, 'dd') AS b_result
FROM VALUES(timestamp '1970-01-01 00:00:00', timestamp_ntz '1970-01-01 00:00:00') t(a, b);
-- Output: a_result=1970-01-02 00:00:00 | b_result=1970-01-02 00:00:00
-- MONTH: extract the month from both types
SELECT month(a) AS a_result, month(b) AS b_result
FROM VALUES(timestamp '1970-01-01 00:00:00', timestamp_ntz '1970-01-01 00:00:00') t(a, b);
-- Output: a_result=1 | b_result=1Aggregate functions
MAX and MIN support TIMESTAMP_NTZ:
SET odps.sql.type.system.odps2=true;
SELECT max(a) AS max_result, min(a) AS min_result
FROM VALUES
(timestamp_ntz '1970-01-01 00:00:00'),
(timestamp_ntz '1970-01-01 01:00:00'),
(timestamp_ntz '1970-01-01 02:00:00') AS t(a);Output:
+---------------------+---------------------+
| max_result | min_result |
+---------------------+---------------------+
| 1970-01-01 02:00:00 | 1970-01-01 00:00:00 |
+---------------------+---------------------+UDFs
Java user-defined functions (UDFs) use java.time.LocalDateTime to map TIMESTAMP_NTZ input and output parameters.
Submit the following as a script-mode SQL job. For more information, see Code-embedded UDFs and SQL in script mode.
SET odps.sql.type.system.odps2=true;
-- Define a UDF that sets the millisecond component to 999
CREATE TEMPORARY FUNCTION foo_udf AS 'com.mypackage.Test' USING
#CODE ('lang'='JAVA')
package com.mypackage;
import com.aliyun.odps.udf.UDF;
public class Test extends UDF {
public java.time.LocalDateTime evaluate(java.time.LocalDateTime ld) {
if (ld == null) return null;
java.time.LocalDateTime result = java.time.LocalDateTime.of(
ld.getYear(), ld.getMonthValue(), ld.getDayOfMonth(),
ld.getHour(), ld.getMinute(), ld.getSecond(), 999000000);
return result;
}
}
#END CODE;
-- Pass a TIMESTAMP_NTZ value to the UDF
SELECT foo_udf(a) FROM VALUES(timestamp_ntz '1970-01-01 00:00:00') AS t(a);Output:
+-------------------------+
| _c0 |
+-------------------------+
| 1970-01-01 00:00:00.999 |
+-------------------------+What's next
Time zones — supported time zones in MaxCompute
Date functions — full reference for date and time functions
Relational operators — relational operator reference
Operators — arithmetic operator reference
CAST function — type conversion reference
Code-embedded UDFs — UDF authoring guide