# 数据类型格式化函数

数据类型格式化函数用于将各种数据类型转换为格式化字符串 (Formatted String)，同时也能将格式化字符串转换回特定的数据类型。MAXIR 中的数据类型格式化函数都遵循一个通用的调用约定：第一个参数是需要格式化的值，第二个参数是一个模板，定义了输出或输入的格式。

Extreme DPS 提供了多个日期/时间格式化函数，如下表所示：

| 函数 | 返回类型 | 说明 | 
| :- | :- | :- |
| `TO_CHAR(date, text)` | `text` | 将日期转换为字符串。 | `TO_CHAR(date '2023-02-05', 'YYYY-FMMM-FMDD')` <br/> → `2023-2-5` |
| `TO_CHAR(timestamp with time zone, text)` | `text` | 将带时区的时间戳转换为指定格式的字符串。 | `TO_CHAR(timestamp with time zone '2023-02-15 12:34:56.123456+00', 'YYYY MM DD HH24:MI:SS.US OF TZ TZH TZM')` <br/> → `2023 02 15 20:34:56.123456 +08 CST +08 00` |
| `TO_CHAR(timestamp, text)` | `text` | 将时间戳转换为指定格式的字符串。 | `TO_CHAR(timestamp '2023-02-15 12:34:56.123456', 'YYYY MM DD HH24:MI:SS.US' )` <br/> → `2023 02 15 12:34:56.123456` |
| `TO_DATE(text, text)` | `date` | 将字符串转换为指定格式的日期。 | `TO_DATE('2023 NOV 28', 'YYYY MON DD')` <br/> → `2023-11-28` |
| `TO_TIMESTAMP(text, text)` | `timestamp with time zone` | 将字符串转换为指定格式的时间戳。 | `TO_TIMESTAMP('05 Dec 2000', 'DD Mon YYYY')` <br/> → `2000-12-05 00:00:00-05` |


<br/>

---
## 日期/时间格式化支持的模板模式

下表描述了日期/时间格式化支持的模版模式 (Template Pattern)，以及各函数对每一个模版模式支持情况。

| 模式 | 描述 | `TO_CHAR` | `TO_DATE` | `TO_TIMESTAMP` |
| :- | :- | :- | :- | :- |
| `HH` | 小时数，取值范围为 01 到 12。 | ✅ | N/A | ✅ |
| `HH12` | 小时数，取值范围为 01 到 12。 | ❌ | N/A |  ✅  |
| `HH24` | 小时数，取值范围为 00 到 23。 |  ✅  | N/A |  ✅  |
| `MI` | 分钟数，取值范围为 00 到 59。 |  ✅  | N/A |  ✅  |
| `SS` | 秒数，取值范围为 00 到 59。 |  ✅  | N/A |  ✅  |
| `MS` | 毫秒数，取值范围为 000 到 999。 |  ✅  | N/A |  ✅  |
| `US` | 微秒数，取值范围为 000000 到 999999。 |  ✅  | N/A |  ✅  |
| `AM` 、`am`、`PM` 或 `pm` | 上午（`AM`、`am`）或者下午（`PM`、`pm`）标志。|  仅支持大写格式 | N/A |  ✅  |
| `YYYY` | 年份（由 4 个或更多数字构成）。 |  ✅  |  ✅  |  ✅  |
| `YY` | 年份的后两位数字。|  ✅  |  ✅  |  ✅  |
| `IYYY` | ISO 8601 周编号年份（由 4 个或更多数字构成）。|  ✅  | ❌ | ❌ |
| `BC`、`bc`、`AD` 或 `ad` | 纪元标志，`BC`/`bc` 表示公元前，`AD`/`ad` 表示公元后。 | 仅支持大写格式 |  ✅  |  ✅  |
| `MONTH`、`Month` 或 `month` | 月份全称（使用空格填充至 9 个字符）。 |  ✅  |  ✅  |  ✅  |
| `MON`、`Mon` 或 `mon` | 月份缩写（英文中为 3 个字符，缩略长度在不同语言中可能有所不同）。 |  ✅  |  ✅  |  ✅  |
| `MM` | 一年中的第几个月，取值范围为 01 到 12。 |  ✅  |  ✅  |  ✅  |
| `DAY` 、 `Day` 或 `day` | 日期全称（使用空格填充至 9 个字符）。|  ✅  |  ✅  |  ✅  |
| `DY` 、 `Dy` 或 `dy` | 日期缩写（英文中为 3 个字符，缩略长度在不同语言中可能有所不同）。|  ✅  |  ✅  |  ✅  |
| `DDD` | 一年中的第几天，取值范围为 001 到 366。 |  ✅  |  ✅  |  ✅  |
| `IDDD` | ISO 8601 周编号年的年内日，取值范围为 001 到 371（一年的第一天是第一个 ISO 周的星期一）。 |  ✅  | ❌ | ❌ |
| `DD` | 一个月中的第几天，取值范围为 01 到 31。 |  ✅  |  ✅  |  ✅  |
| `D` | 一个星期中的第几天，取值范围为 1（周日）到 7（周六）。 |  ✅  |  ✅  |  ✅  |
| `ID` | 符合 ISO 8601 编码的一个星期中的第几天，取值范围为 1（周一）到 7（周日）。 |  ✅  | ❌ | ❌ |
| `W` | 一个月中的第几周，取之范围为 1 到 5（从当月第一天开始计算第一周）。|  ✅  |  ✅  |  ✅  |
| `WW` | 一年中的第几周，取之范围为 1 到 53（从当年第一天开始计算第一周）。|  ✅  |  ✅  |  ✅  |
| `IW` | 符合 ISO 8601 编码的一年中的第几周，取之范围为 01 到 53（从当年的第一个周四开始计算第一周）。|  ✅  | ❌ | ❌ |
| `Q` | 季度。 |  ✅  |  ✅  |  ✅  |
| `TZ` | 时区缩写。|  ✅  | ❌ | N/A |
| `TZH` | 相对于 UTC 的时区偏差小时数。 |  ✅  | N/A |  ✅  |
| `TZM` | 时区设置中，除小时偏差外的额外分钟偏差。 |  ✅  | N/A |  ✅  |
| `OF` | 相对于 UTC 的时区偏差。 |  ✅  | ❌ | N/A |

<br/>

---
## 模版模式支持的修饰符

下表描述了在日期/时间格式化模版模式中支持的修饰符 (Pattern Modifier)。其中，`TO_CHAR` 支持下述所有修饰符，`TO_DATE` 仅支持 FX 前缀。

| 修饰符 | 描述 | 样例 |
| :- | :- | :- |
| FM 前缀 | 一种填充模式，指定在表示数据或日期时，省略前导 0 和填充的空格。 | `TO_CHAR(date '2023-02-05', 'YYYY-FMMM-FMDD')` → `2023-2-5` |
| TH 后缀 | 给序数词添加的后缀（大写），表示顺序。 | `TO_CHAR(date '2023-02-05', 'YYYY MMTH DDTH')` → `2023 02ND 05TH` |
| th 后缀 | 给序数词添加的后缀（小写），表示顺序。 | `TO_CHAR(date '2023-02-05', 'YYYY MMth DDth')` → `2023 02nd 05th` |
| FX 前缀 | 固定格式全局选项，详细说明，请见 [使用说明](#使用说明)。 | `FX Month DD Day` |

<br/>




### 使用说明

- FM 前缀用于消除其他情况下会被添加到模式输出中的前导零和空格，以使输出具有固定宽度。

- `TO_DATE` 会跳过输入字符串开始处和日期时间值周围的多个空格，除非使用了 `FX` 选项。例如，`TO_DATE('   2023      DEC', 'FXYYYY MON')` 有效，但是 `TO_DATE('   2023      DEC', 'FXYYYY MON')` 会返回错误，因为 `TO_DATE` 预期只有一个空格。`FX` 必须被指定为模板中的第一项。

- 在 `TO_DATE` 的模板字符串中的分隔符（空格或非字母/非数字字符）会匹配输入字符串中的任何单个分隔符或被跳过，除非使用了 `FX` 选项。例如，`TO_DATE('2023DEC', 'YYYY!#@#$%^*MON')` 有效，但是 `TO_DATE('2023!!!DEC', 'YYYY!MON')` 会返回错误，因为输入字符串中的分隔符数量超过了模板中的分隔符数量。如果指定了 `FX`，模板字符串中的分隔符将精确匹配输入字符串中的字符。但请注意，输入字符串中的字符不需要与模板字符串中的分隔符相同。例如，`TO_DATE('2023/DEC', 'FXYYYY MON')` 有效，但是 `TO_DATE('2023/DEC', 'FXYYYY  MON')` 会返回错误，因为模板字符串中的第二个空格消耗了输入字符串中的字母 D。

- 普通文本可以在 `TO_CHAR` 模板中使用，并将按原样输出。你可以将子字符串放在双引号中，即使它包含模板模式，也会被强制解释为字面文本。例如，在 `'"Hello YY "YYYY'` 中，`YYYY` 将会替换为年份，但 `"Year YY"` 中的 `YY` 不会。在 `TO_DATE` 中，字面文本和双引号字符串会导致跳过字符串中包含的字符数量；例如 `"XX"` 会跳过两个输入字符（无论这两个字符是否为 `XX`）。

- 如果您想在输出中有双引号，您必须在前面加上反斜杠，例如 `TO_CHAR(date '2023-12-23', '\"YYYY Month\"') -> "2023 December "`。反斜杠在双引号字符串外没有特殊含义。在双引号字符串内，反斜杠会使下一个字符被字面解释（没有特殊效果，除非下一个字符是双引号或另一个反斜杠）。

- 在 `TO_DATE` 中，如果年份格式规范少于四位数字，例如 `YYY`，且提供的年份少于 4 位数字，年份将调整为最接近 2020 年的年份，例如 `95` 会被调整为 `1995`。

- 如果年份输入为 0，则会被视为公元前 1 年。

- 在 `TO_DATE` 中，`YYYY` 转换在处理超过 4 位数字的年份时有限制。您必须在 `YYYY` 之后使用某些非数字字符或模板，否则年份始终将会被解释为 4 位数字。例如（以 `20000` 年为例）：`TO_DATE('200000915', 'YYYYMMDD')` 将被解释为 4 位数年份；相反，应使用年份后的非数字分隔符，如 `TO_DATE('20000-0915', 'YYYY-MMDD')` 或 `TO_DATE('20000Sep15', 'YYYYMonDD')`。