
# 日期/时间类型

MAXIR 支持主要的日期和时间数据类型，如下表所示。

| 名称 | 别名 | 存储大小 | 取值范围 | 精度 | 描述 |
| :- | :- | :- | :- | :- | :- |
| `date` | N/A | 4 字节 | 0001-01-01 到 9999-12-31 | 1 天 | 自 1970 年 1 月 1 日以来的天数。<br/>对时区差异不敏感。 | 
| `timestamp` | `timestamp without time zone` | 8 字节 | 0001-01-01 00:00:00 到 9999-12-31 23:59:59 | 1 微秒/14 位数 | 自 1970 年 1 月 1 日以来经过的秒数，不涉及时区。 |
| `timestamp with time zone` | `timestamptz` | 8 字节 | 0001-01-01 00:00:00～9999-12-31 23:59:59 (UTC) | 1 微秒/14 位数 | 自 1970 年 1 月 1 日以来经过的秒数，涉及时区。|
| `interval` | N/A | 16 字节 | -178000000 年到 178000000 年 | 1 微秒/14 位数 | 时间间隔。<br/>对时区差异敏感。 |

<br/>

!>重要 <br/>
MAXIR 不支持在 DDL 中定义数据类型为 `interval` 的列，因为 MAXIR 不支持存储 `interval` 类型的数据。




<br/>

有关日期/时间数据类型可执行操作的信息：

- 如计算引擎为 Hybrid DPS，请参考 PostgreSQL 文档中的 [Date/Time Functions and Operators](https://www.postgresql.org/docs/12/functions-datetime.html)。

- 如计算引擎为 Extreme DPS，请参考 [日期/时间函数和运算符](/docs/maxir/Reference_Manual/extreme-dps-functions/date-time-functions)。

日期/时间类型的输出样式因使用的客户端而异，本文不做展开。

>说明
>- `timestamptz` 可以作为 `timestamp with time zone` 的缩写使用。
>- 日期按照公历来计算，即使是引入公历之前的年份。更多详细信息，请参考 PostgreSQL 文档中的 [History of Units](https://www.postgresql.org/docs/current/datetime-units-history.html)。



## 日期

MAXIR 支持 ISO 8601 中的日期/时间输入。

使用一对单引号（`' '`）括起任何日期或时间文字输入，例如，`'2022-07-01'` 或 `'2022-7-1'`。 


---
## 时间戳

时间戳类型接受日期和时间的连接格式的有效输入。

MAXIR 支持两种时间戳类型：`timestamp with time zone` 和 `timestamp`，建议你在指定值之前确定是否需要时区。如果你选择 `timestamp with time zone`，使用 +/- 符号指定时区偏移量。如果指定时间戳类型为 `timestamp`，MAXIR 会忽略时间戳数据中包含的时区信息。

对于 `timestamp with time zone`，MAXIR 内部以 UTC 进行存储。具有明确时区的输入值将使用正确的偏移量转换为 UTC。如果输入字符串缺少时区指示，`TimeZone` 系统参数的值将用作时区。转换为 UTC 使用该时区的 UTC 偏移量。

当 `timestamp with time zone` 值输出时，显示的值是从 UTC 转换后的时区的本地时间。

如果你在 `timestamp with time zone` 类型和 `timestamp` 类型之间转换值，`timestamp` 值通常被视为时区的本地时间。 


!>重要 <br/>
MAXIR 不允许使用大写字母 `T` 来连接值中的日期部分和时间部分，请使用空格代替。

<br/>

MAXIR 支持两种时间戳的输入样式。

| 样式规范 | 格式 | 示例 | 描述 |
| :- | :- | :- | :- |
| `ISO` | 时区名称全称 | `2022-07-01 12:00:00 Asia/Shanghai` | 符合标准化的IANA时区数据库中的时区全称，例如，Asia/Shanghai。 |
| `POSIX` | 偏移量 | `2022-07-01 12:00:00+8` 或 <br/>`2022-07-01 12:00:00+8:01` | 偏移字段指定与 UTC 的小时数，以及可选的分钟数和秒数，格式为 "hh[:mm]"。可以使用前导符号 `+` 或 `-`。 |

<br/>

---
## 时区

时区以及时区规范，受到政治决策的影响，而不仅仅是物理地理位置。虽然从 1900 年代开始，世界各地的时区逐渐开始变得标准化，但是随意更改仍时有发生，特别是关于夏令时的规则。出于标准化考虑，MAXIR 使用通用的 IANA（Olson）时区数据库获取有关历史时区规则的信息。对于未来的时间，MAXIR 则假设已知的时区将无限期地持续观察。

MAXIR 努力与 SQL 标准的典型用法兼容。然而，SQL 标准对日期和时间类型及其功能有一些奇怪的混合。两个明显的问题是：

1. 在现实世界中，时区除非与日期以及时间一起关联，否则几乎没有意义，因为偏移量可以因夏令时边界问题而在一年中变化。

2. 默认时区是指定为 UTC 的常数数值偏移量。因此，在跨 DST 边界进行日期/时间运算时，无法适应夏令时。

为了解决上述问题，MAXIR 建议在使用同时包含日期和时间的日期/时间类型的时候指定时区。

所有知道时区的日期和时间都以 UTC 内部存储。在显示给客户端之前，它们会被转换为 `TimeZone` 配置参数指定的时区的本地时间。

 

### 支持的时区格式

MAXIR 支持三种时区格式：

- **时区全称**

    基于 IANA 时区数据库，用于表示某个地理区域相对于协调世界时（UTC）的时间差异，例如 `America/New_York`、`Europe/Paris` 等。这些地理区域标识代表特定区域的时区，每个时区全称都对应一个相对于协调世界时（UTC）的时间差异，它以小时为单位，可以是正数、负数或零。正数表示 UTC 以东的时间，负数表示 UTC 以西的时间，零表示该时区与 UTC 时间一致。例如 `America/New_York` 时区的偏移量为 `-5` 小时，表示该时区在 UTC 以西，时间相比 UTC 晚 5 小时。

- **基于 ISO-8601 标准的时区偏移表示**

    时区格式为一个正号或负号后跟小时和分钟的偏移量来表示：`±HH[:MM]`。每个时区偏移都表示一个相对于 UTC 的时间差异，可以是正数、负数或零。正数表示时区在 UTC 以东，负数表示时区在 UTC 以西，零表示该时区与 UTC 时间一致。例如，`+02:00` 表示 UTC 以东的时区，时间比 UTC 早 2 小时；`-05:30` 表示比 UTC 以西的时区，时间比 UTC 晚 5 小时 30 分钟。

- **基于 POSIX 标准的时区偏移表示**

    时区格式为一个正号或负号后跟小时和分钟的偏移量来表示：`±HH[:MM]`。每个时区偏移都表示一个相对于 UTC 的时间差异，可以是正数、负数或零。其中正数表示时区在 UTC 以西，负数表示时区在 UTC 以东（偏移方向与 ISO-8601 标准的时区相反）。例如，`+02:00` 表示 UTC 以西的时区，时间比 UTC 晚 2 小时；`-05:30` 表示比 UTC 以东的时区，时间比 UTC 早 5 小时 30 分钟。


 

### 时区偏移说明

在时区偏移在不同的使用场景下所遵循的标准不同。如下为在各种场景下的时区偏移说明：

<br/>

**场景 1**：时间 Literal

时区偏移遵循的标准：ISO-8601

说明：当时间 Literal 中出现时区偏移时，将遵循 ISO-8601 标准处理该时区偏移。

示例：

```sql
SELECT timestamptz '2024-01-15 12:00:00+06';


      timestamptz
------------------------
 2024-01-15 06:00:00+00
(1 row)

SELECT timestamptz '2024-01-15 12:00:00+06:00';


      timestamptz
------------------------
 2024-01-15 06:00:00+00
(1 row)
```
>说明 <br/>
>此示例中，会话时区设置为 `UTC`。

<br/>

**场景 2**：输出的时间结果

时区偏移遵循的标准：ISO-8601

说明：当时区偏移出现在时间输出中时，其所代表的含义遵循 ISO-8601 标准。

示例：

```sql
SELECT timestamptz '2024-01-15 12:00:00+00';

      timestamptz
------------------------
 2024-01-15 20:00:00+08
(1 row)
```

>说明 <br/>
>此示例中，会话时区设置为 `Asia/Shanghai`。

<br/>

**场景 3**：字符串转换为时间类型

时区偏移遵循的标准：ISO-8601

说明：当表示时间的字符串中出现时区偏移时，将遵循 ISO-8601 标准处理该时区偏移

样例：

```sql
SELECT CAST('2024-01-15 12:00:00+06' AS timestamptz);

      timestamptz
------------------------
 2024-01-15 06:00:00+00
(1 row)

SELECT CAST('2024-01-15 12:00:00+06:00' AS timestamptz);

      timestamptz
------------------------
 2024-01-15 06:00:00+00
(1 row)
```

>说明 <br/>
>此示例中，会话时区设置为 `UTC`。

<br/>

**场景 4**：时间格式化函数

在该场景下，存在两种情况：

1. 字符串格式转换为时间

    时区偏移遵循的标准：ISO-8601

    说明：当时区偏移出现在时间格式化函数的源字符串中时，将遵循 ISO-8601 标准处理该时区偏移

    示例：

    ```sql
    SELECT to_timestamp('2024-01-15 12:00:00-08', 'YYYY-MM-DD HH24:MI:SSTZH');

        to_timestamp
    ------------------------
    2024-01-15 20:00:00+00
    (1 row)

    SELECT to_timestamp('2024-01-15 12:00:00-08:30', 'YYYY-MM-DD HH24:MI:SSTZH:TZM');

          to_timestamp
    ------------------------
     2024-01-15 20:30:00+00
    (1 row)
    ```

    >说明 <br/>
    >此示例中，会话时区设置为 `UTC`。
  

2. 时间格式转换为字符串

    时区偏移遵循的标准：请参考“场景 5：会话中的时区”中所遵循的标准。

    说明：在时间格式化为字符串的处理逻辑中，`'TZH'` 格式符输出时使用的是会话的时区偏移，具体遵循的标准参见“场景 5：会话中的时区”中的描述。
    
    示例：

    ```sql
    SELECT to_char(timestamptz '2024-01-15 12:00:00+10', 'YYYY-MM-DD HH24:MI:SS TZH:TZM');

          to_char
    ----------------------------
    2024-01-15 10:00:00+08:00
    (1 row)
    ```
    >说明 <br/>
    >此示例中，会话时区设置为`'+8'`。
   

<br/>

**场景 5**：会话中的时区

该场景分为两种情况：

1. 会话时区设置为 `±HH`

    时区偏移遵循的标准：ISO-8601

    说明：当会话的时区设置为 `'±HH'` 格式时，遵循 ISO-8601 标准处理该时区偏移

    示例：

    ```sql
    SET time zone '+07';

    SELECT timestamp with time zone '2024-02-25 10:00:00+00';

          timestamptz
    ------------------------
     2024-02-25 17:00:00+07
    (1 row)


    SET time zone '-07';
    
    SELECT timestamp with time zone '2024-02-25 10:00:00+00';

          timestamptz
    ------------------------
     2024-02-25 03:00:00-07
    (1 row)
    ```
    >说明 <br/>
    >此示例中，会话时区设置为 `'+07'`。
   



2. 会话时区设置为 `±HH:MM`

    时区偏移遵循的标准：POSIX

    说明：当会话的时区设置为 `'±HH:MM'` 格式时，遵循 POSIX 标准处理该时区偏移

    示例：

    ```sql
    SET time zone '+07:00';

    SELECT timestamp with time zone '2024-02-25 10:00:00+00';

          timestamptz
    ------------------------
     2024-02-25 03:00:00-07
    (1 row)


    SET time zone '-07:00';
    
    SELECT timestamp with time zone '2024-02-25 10:00:00+00';

          timestamptz
    ------------------------
     2024-02-25 17:00:00+07
    (1 row)    
    ```
    >说明 <br/>
    >此示例中，会话时区设置为 `'+07:00'` 。


**场景 6**：`AT TIME ZONE` 命令中的时区

时区偏移遵循的标准：POSIX

说明：当 `AT TIME ZONE` 命令中的时区设置为 offset 格式（±HH/±HH:MM）时，遵循 POSIX 标准处理该时区偏移

示例：

```sql
SET time zone 'UTC';

SELECT timestamptz '2024-01-10 12:00:00+00' at time zone '+08' ;


      timezone
---------------------
 2024-01-10 04:00:00
(1 row)

SELECT timestamptz '2024-01-10 12:00:00+00' at time zone '+08:00' ;

      timezone
---------------------
 2024-01-10 04:00:00
(1 row)

SELECT timestamp '2024-01-10 12:00:00' at time zone '+08';

        timezone
------------------------
 2024-01-10 20:00:00+00
(1 row)

SELECT timestamp '2024-01-10 12:00:00' at time zone '+08:00';


        timezone
------------------------
 2024-01-10 20:00:00+00
(1 row)
```


>说明 <br/>
>此示例中，会话时区设置为 `UTC`。


---

## 间隔

`interval` 类型有一个额外的选项，那就是通过编写以下短语之一来限制存储的字段集：

```
YEAR
MONTH
DAY
HOUR
MINUTE
SECOND
MILLISECOND
MICROSECOND
```



以下是一个 `interval` 值的示例：

```sql
1 year 2 months 3 days 4 hours 5 minutes 6 seconds
```  
    

| 缩写 | 含义 |
| :- | :- |
| Y | 年 |
| M | 月（在日期部分） |
| W | 周 |
| D | 日 |
| H | 小时 |
| M | 分钟（在时间部分） |
| S | 秒 |

<br/>
