All Products
Search
Document Center

MaxCompute:TIMESTAMP_NTZ data type

Last Updated:Mar 25, 2026

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:

TIMESTAMPTIMESTAMP_NTZ
Internal storageUTC offset from epoch (1970-01-01 00:00:00 UTC)Wall-clock time, no time zone reference
Display behaviorAdjusted to the current session time zoneAlways returns the value as written
Time zone conversionRequired on readNone
SQL standardHive 2 compatibleSQL: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 | true

Arithmetic 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.000000000

Add 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:00

Add 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:00

Date 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=1

Aggregate 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