↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1
历史版本。 PostgreSQL 12 已结束支持。 2024-11-21. 请参阅 当前版本手册.

9.8. 数据类型格式化函数 #

PostgreSQL 格式化函数提供一套强大的工具用于把各种数据类型(日期/时间、整数、浮点数、数值)转换成格式化的字符串以及反过来从格式化的字符串转换成指定的数据类型。表 9.24 列出了这些函数。这些函数都遵循一个公共的调用规范:第一个参数是待格式化的值,而第二个是一个定义输出或输入格式的模板。

表 9.24. 格式化函数

函数返回类型描述示例
to_char(timestamp, text)text将时间戳转换为字符串to_char(current_timestamp, 'HH12:MI:SS')
to_char(interval, text)text将时间间隔转换为字符串to_char(interval '15h 2m 12s', 'HH24:MI:SS')
to_char(int, text)text将整数转换为字符串to_char(125, '999')
to_char(double precision, text)text将 real/double precision 转换为字符串to_char(125.8::real, '999D9')
to_char(numeric, text)text将 numeric 转换为字符串to_char(-125.8, '999D99S')
to_date(text, text)date将字符串转换为日期to_date('05 Dec 2000', 'DD Mon YYYY')
to_number(text, text)numeric将字符串转换为 numericto_number('12,454.8-', '99G999D9S')
to_timestamp(text, text)timestamp with time zone将字符串转换为时间戳to_timestamp('05 Dec 2000', 'DD Mon YYYY')

注意

还有一个接受单个参数的 to_timestamp 函数;参见表 9.31。

提示

to_timestamp 和 to_date 存在的目的是为了处理无法通过简单类型转换直接处理的输入格式。对于大部分标准的日期/时间格式,只需把源字符串类型转换为所需的数据类型即可,并且简单很多。类似地,对于标准的数字表示形式,to_number 也是没有必要的。

在一个 to_char 输出模板串中,一些特定的模式可以被识别并且被替换成基于给定值的被恰当地格式化的数据。任何不属于模板模式的文本都简单地照字面拷贝。同样,在一个输入模板串里(对其他函数),模板模式标识由输入数据串提供的值。如果在模板字符串中有不是模板模式的字符,输入数据字符串中的对应字符会被简单地跳过(不管它们是否等于模板字符串字符)。

表 9.25 展示了可以用于格式化日期和时间值的模板模式。

表 9.25. 用于日期/时间格式化的模板模式

模式描述
HH一天中的小时(01-12)
HH12一天中的小时(01-12)
HH24一天中的小时(00-23)
MI分钟(00-59)
SS秒(00-59)
MS毫秒(000-999)
US微秒(000000-999999)
SSSS自午夜起的秒数(0-86399)
AM, am, PM 或 pm上午/下午标记(不带句点)
A.M., a.m., P.M. 或 p.m.上午/下午标记(带句点)
Y,YYY带逗号的年(4 位或者更多位)
YYYY年(4 位或者更多位)
YYY年的最后 3 位数字
YY年的最后 2 位数字
Y年的最后 1 位数字
IYYYISO 8601 周编号方式的年(4 位或更多位)
IYYISO 8601 周编号方式的年的最后 3 位数字
IYISO 8601 周编号方式的年的最后 2 位数字
IISO 8601 周编号方式的年的最后 1 位数字
BC, bc, AD 或 ad纪元指示器(不带句号)
B.C., b.c., A.D. 或 a.d.纪元指示器(带句号)
MONTH大写的月份全称(空格补齐到 9 字符)
Month首字母大写的月份全称(空格补齐到 9 字符)
month小写的月份全称(空格补齐到 9 字符)
MON简写的大写形式的月名(英文 3 字符,本地化长度可变)
Mon简写的首字母大写形式的月名(英文 3 字符,本地化长度可变)
mon简写的小写形式的月名(英文 3 字符,本地化长度可变)
MM月份编号(01-12)
DAY大写的星期全称(空格补齐到 9 字符)
Day首字母大写的星期全称(空格补齐到 9 字符)
day小写的星期全称(空格补齐到 9 字符)
DY大写的星期简称(英语 3 字符,本地化长度可变)
Dy首字母大写的星期简称(英语 3 字符,本地化长度可变)
dy小写的星期简称(英语 3 字符,本地化长度可变)
DDD一年中的第几天(001-366)
IDDDISO 8601 周编号年中的第几天(001-371;一年的第 1 天是第一个 ISO 周的星期一)
DD月内日序数(01-31)
D星期几,周日 (1) 到周六 (7)
IDISO 8601 星期几,周一 (1) 到周日 (7)
W月内周序数(1-5)(第一周从该月第一天开始)
WW一年中的第几周(1-53)(第一周从该年第一天开始)
IWISO 8601 周编号年中的第几周(01-53;该年的第一个星期四位于第 1 周)
CC世纪(2 位数)(21 世纪开始于 2001-01-01)
J儒略日(从本地午夜的公元前 4714 年 11 月 24 日开始的整数日数;参见第 B.7 节)
Q季度
RM以大写罗马数字表示的月份(I-XII;I= 一月)
rm以小写罗马数字表示的月份(i-xii;i= 一月)
TZ大写形式的时区缩写(仅在 to_char 中支持)
tz小写形式的时区缩写(仅在 to_char 中支持)
TZH时区的小时
TZM时区的分钟
OF相对于 UTC 的时区偏移(仅在 to_char 中支持)

修饰符可以被应用于模板模式来修改它们的行为。例如,FMMonth 就是带着 FM 修饰符的 Month 模式。表 9.26 展示了可用于日期/时间格式化的修饰符模式。

表 9.26. 用于日期/时间格式化的模板模式修饰符

修饰符描述示例
FM 前缀填充模式(抑制前导零和填充的空格)FMMonth
TH 后缀大写形式的序数后缀DDTH,例如,12TH
th 后缀小写形式的序数后缀DDth,例如,12th
FX 前缀固定格式全局选项(见使用须知)FX Month DD Day
TM 前缀翻译模式(根据 lc_time 输出本地化的星期名和月份名)TMMonth
SP 后缀拼写模式(未实现)DDSP

日期/时间格式化的使用注意事项:

  • FM 抑制了在模式输出中添加前导零和尾随空格的行为,这些前导零和尾随空格本来会被添加以使输出成为固定宽度。在 PostgreSQL 中,FM 仅修改下一个格式说明,而在 Oracle 中 FM 影响所有后续格式说明,并且重复的 FM 修饰符切换填充模式的开启和关闭。

  • TM 不包含尾随空格。to_timestamp 和 to_date 会忽略 TM 修饰符。

  • to_timestamp 和 to_date 跳过输入字符串开头和日期时间值周围的多个空格,除非使用 FX 选项。例如,to_timestamp(' 2000    JUN', 'YYYY MON') 和 to_timestamp('2000 - JUN', 'YYYY-MON') 是有效的,但是 to_timestamp('2000    JUN', 'FXYYYY MON') 会返回错误,因为 to_timestamp 只接受单个空格。FX 必须作为模板中的第一项指定。

  • 在 to_timestamp 和 to_date 的模板字符串中,分隔符(空格或非字母/非数字字符)匹配输入字符串中的任何单个分隔符,或被跳过,除非使用 FX 选项。例如,to_timestamp('2000JUN', 'YYYY///MON') 和 to_timestamp('2000/JUN', 'YYYY MON') 可以工作,但 to_timestamp('2000//JUN', 'YYYY/MON') 会返回错误,因为输入字符串中的分隔符数量超过了模板中的分隔符数量。

    如果指定了 FX,模板字符串中的分隔符将精确匹配输入字符串中的一个字符。但请注意,输入字符串的字符不一定与模板字符串中的分隔符相同。例如,to_timestamp('2000/JUN', 'FXYYYY MON') 可以工作,但 to_timestamp('2000/JUN', 'FXYYYY  MON') 会返回错误,因为模板字符串中的第二个空格会消耗输入字符串中的字母 J。

  • 一个 TZH 模板模式可以匹配有符号数。没有 FX 选项,负号可能会有歧义,并且可能被解释为分隔符。此歧义解决如下:如果模板字符串中 TZH 之前的分隔符数量少于输入字符串中负号之前的分隔符数量,则负号被解释为 TZH 的一部分。否则,负号被视为值之间的分隔符。例如,to_timestamp('2000 -10', 'YYYY TZH') 匹配 -10 到 TZH,但 to_timestamp('2000 -10', 'YYYY  TZH') 匹配 10 到 TZH。

  • 普通文本可以出现在 to_char 模板中,并会按字面输出。可以用双引号括起子串,使其即使包含模式关键字也强制按字面文本解释。例如,在'"Hello Year "YYYY' 中,YYYY 会被年份数据替换,但 Year 中单独的 Y 不会被替换。在 to_date、to_number 和 to_timestamp 中,字面文本和双引号字符串会跳过与该字符串所含字符数相同数量的输入字符;例如,"XX" 跳过两个输入字符(无论它们是否为 XX)。

    提示

    在 PostgreSQL 12 之前,可以使用非字母或非数字字符跳过输入字符串中的任意文本。例如,to_timestamp('2000y6m1d', 'yyyy-MM-DD') 曾经有效。现在,您只能使用字母字符来实现这一目的。例如,to_timestamp('2000y6m1d', 'yyyytMMtDDt') 和 to_timestamp('2000y6m1d', 'yyyy"y"MM"m"DD"d"') 跳过了 y,m 和 d。

  • 如果您想在输出中使用双引号,必须在其前面加上反斜杠,例如'\"YYYY Month\"'。反斜杠在双引号之外不起特殊作用。在双引号字符串内部,反斜杠会使下一个字符被按字面解释,无论是什么(但除非下一个字符是双引号或另一个反斜杠,否则没有特殊效果)。

  • 在 to_timestamp 和 to_date 中,如果年份格式规范少于四位数字,例如 YYY,并且提供的年份少于四位数字,年份将被调整为最接近 2020 年的年份,例如 95 变为 1995 年。

  • 在 to_timestamp 和 to_date 中,负年份被视为 BC 纪元。如果同时写入负年份和显式的 BC 字段,则再次得到 AD。年份零被视为公元前 1 年。

  • 在 to_timestamp 和 to_date 中,YYYY 转换在处理超过 4 位数字的年份时有限制。您必须在 YYYY 后使用一些非数字字符或模板,否则年份总是被解释为 4 位数字。例如(使用年份 20000):to_date('200001130', 'YYYYMMDD') 将被解释为 4 位年份;而应该在年份后使用非数字分隔符,如 to_date('20000-1130', 'YYYY-MMDD') 或 to_date('20000Nov30', 'YYYYMonDD')。

  • 在 to_timestamp 和 to_date 中,如果存在 YYY、YYYY 或 Y,YYY 字段,则会接受但忽略 CC(世纪)字段。如果 CC 与 YY 或 Y 一起使用,则结果将计算为指定世纪中的那一年。如果指定了世纪但未指定年份,则假定为该世纪的第一年。

  • 在 to_timestamp 和 to_date 中,星期几的名称或数字(DAY,D,以及相关字段类型)是被接受的,但在计算结果时会被忽略。同样适用于季度(Q)字段。

  • 在 to_timestamp 和 to_date 中,ISO 8601 周编号日期(与公历日期不同)可以通过两种方式之一指定:

    • 年份、周编号和星期几:例如 to_date('2006-42-4', 'IYYY-IW-ID') 返回日期 2006-10-19。如果省略星期几,则假定为 1(星期一)。

    • 年份和年内日序数:例如 to_date('2006-291', 'IYYY-IDDD') 也返回 2006-10-19。

    尝试使用 ISO 8601 周编号字段和公历日期字段的混合输入日期是荒谬的,并将导致错误。在 ISO 8601 周编号年的背景下,“月份”或“月内日序数”的概念没有意义。在公历年的背景下,ISO 周没有意义。

    小心

    虽然 to_date 会拒绝混合使用公历和 ISO 周编号日期字段,但 to_char 不会,因为输出格式规范如 YYYY-MM-DD (IYYY-IDDD) 可能很有用。但要避免编写类似 IYYY-MM-DD 的内容;那会在年初附近产生令人惊讶的结果。(有关更多信息,请参见第 9.9.1 节。)

  • 在 to_timestamp 函数中,毫秒(MS)或微秒(US)字段被用作小数点后的秒数位。例如 to_timestamp('12.3', 'SS.MS') 不是 3 毫秒,而是 300,因为转换将其视为 12 + 0.3 秒。因此,对于格式 SS.MS,输入值 12.3、12.30 和 12.300 指定相同数量的毫秒。要获得三毫秒,必须写成 12.003,转换将其视为 12 + 0.003 = 12.003 秒。

    这是一个更复杂的示例:to_timestamp('15:12:02.020.001230', 'HH24:MI:SS.MS.US') 为 15 小时 12 分钟,秒数为 2 秒 + 20 毫秒 + 1230 微秒 = 2.021230 秒。

  • to_char(..., 'ID') 的星期几编号与 extract(isodow from ...) 函数匹配,但 to_char(..., 'D') 的星期几编号与 extract(dow from ...) 的不一致。

  • to_char(interval) 格式化 HH 和 HH12,如在 12 小时制时钟上显示,例如零小时和 36 小时都输出为 12,而 HH24 输出完整的小时值,在 interval 值中可以超过 23。

表 9.27 展示了可以用于格式化数值的模板模式。

表 9.27. 用于数值格式化的模板模式

模式描述
9数位(非有效位可以被省略)
0数位(即便是非有效位也不会被省略)
.(句点)小数点
,(逗号)分组(千)分隔符
PR尖括号内的负值
S紧贴数值的正负号(使用区域设置)
L货币符号(使用区域设置)
D小数点(使用区域设置)
G分组分隔符(使用区域设置)
MI在指定位置的负号(如果数字 < 0)
PL在指定位置的正号(如果数字 > 0)
SG在指定位置的正/负号
RN罗马数字(输入在 1 和 3999 之间)
TH 或 th序数后缀
V移动指定位数(参阅注解)
EEEE科学记数的指数

数值格式化的使用注意事项:

  • 0 指定一个数字位置,即使它包含前导/尾随零,也将始终打印出来。9 也指定一个数字位置,但如果它是一个前导零,则将被替换为一个空格,而如果它是一个尾随零并且指定了填充模式,则将被删除。(对于 to_number(),这两个模式字符是等效的。)

  • 如果格式指定的小数位数少于被格式化数值的小数位数,to_char() 会将该数值舍入到指定的小数位数。

  • 模式字符 S、L、D 和 G 表示当前区域设置定义的正负号、货币符号、小数点和千位分隔符字符(参见 lc_monetary 和 lc_numeric)。模式字符句点和逗号表示这些确切字符,具有小数点和千位分隔符的含义,不受区域设置影响。

  • 如果 to_char() 的模式中没有明确指定正负号的位置,就会为正负号保留一列,并使其紧贴数值(紧靠数值左侧)。如果 S 紧邻若干个 9 的左侧,它同样会紧贴数值。

  • 使用 SG、PL 或 MI 格式化的正负号不紧贴数值;例如,to_char(-12, 'MI9999') 会产生'-  12',但 to_char(-12, 'S9999') 会产生'  -12'。(Oracle 实现不允许在 9 之前使用 MI,而是要求 9 在 MI 之前。)

  • TH 不会转换小于零的值,也不会转换小数。

  • PL,SG 和 TH 是 PostgreSQL 的扩展。

  • 在 to_number 函数中,如果使用非数据模板模式,如 L 或 TH,则会跳过相应数量的输入字符,无论它们是否与模板模式匹配,除非它们是数据字符(即数字、正负号、小数点或逗号)。例如,TH 会跳过两个非数据字符。

  • V 与 to_char 一起,将输入值乘以 10^n,其中 n 是跟在 V 后面的数字位数。V 与 to_number 一起以类似的方式进行除法。to_char 和 to_number 不支持与小数点结合使用的 V(例如,不允许使用 99.9V99)。

  • EEEE(科学计数法)不能与任何其他格式模式或修饰符结合使用,除了数字和小数点模式之外,必须位于格式字符串的末尾(例如,9.99EEEE 是一个有效模式)。

某些修饰符可以被应用到任何模板来改变其行为。例如,FM99.99 是带有 FM 修饰符的 99.99 模式。表 9.28 中展示了用于数值格式化的模式修饰符。

表 9.28. 用于数值格式化的模板模式修饰符

修饰符描述示例
FM 前缀填充模式(抑制尾随零和填充的空白)FM99.99
TH 后缀大写序数后缀999TH
th 后缀小写序数后缀999th

表 9.29 展示了一些使用 to_char 函数的示例。

表 9.29. to_char 示例

表达式结果
to_char(current_timestamp, 'Day, DD  HH12:MI:SS')'Tuesday  , 06  05:39:18'
to_char(current_timestamp, 'FMDay, FMDD  HH12:MI:SS')'Tuesday, 6  05:39:18'
to_char(-0.1, '99.99')'  -.10'
to_char(-0.1, 'FM9.99')'-.1'
to_char(-0.1, 'FM90.99')'-0.1'
to_char(0.1, '0.9')' 0.1'
to_char(12, '9990999.9')'    0012.0'
to_char(12, 'FM9990999.9')'0012.'
to_char(485, '999')' 485'
to_char(-485, '999')'-485'
to_char(485, '9 9 9')' 4 8 5'
to_char(1485, '9,999')' 1,485'
to_char(1485, '9G999')' 1 485'
to_char(148.5, '999.999')' 148.500'
to_char(148.5, 'FM999.999')'148.5'
to_char(148.5, 'FM999.990')'148.500'
to_char(148.5, '999D999')' 148,500'
to_char(3148.5, '9G999D999')' 3 148,500'
to_char(-485, '999S')'485-'
to_char(-485, '999MI')'485-'
to_char(485, '999MI')'485 '
to_char(485, 'FM999MI')'485'
to_char(485, 'PL999')'+485'
to_char(485, 'SG999')'+485'
to_char(-485, 'SG999')'-485'
to_char(-485, '9SG99')'4-85'
to_char(-485, '999PR')'<485>'
to_char(485, 'L999')'DM 485'
to_char(485, 'RN')'        CDLXXXV'
to_char(485, 'FMRN')'CDLXXXV'
to_char(5.2, 'FMRN')'V'
to_char(482, '999th')' 482nd'
to_char(485, '"Good number:"999')'Good number: 485'
to_char(485.8, '"Pre:"999" Post:" .999')'Pre: 485 Post: .800'
to_char(12, '99V999')' 12000'
to_char(12.4, '99V999')' 12400'
to_char(12.45, '99V9')' 125'
to_char(0.0004859, '9.99EEEE')' 4.86e-04'

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.