日期/时间类型 ================== PostgreSQL支持SQL中所有的日期和时间类型,如\ `表 `__\ 所示。这些数据类型上可用的操作如\ `节 `__\ 所述。日期根据公历来计算,即使对于该历法被引入之前的年份也一样(见\ `节 `__\ )。 .. container:: table :name: DATATYPE-DATETIME-TABLE **表 日期/时间类型** .. container:: table-contents +----------+----------+----------+----------+----------+--------+ | 名字 | 存储尺寸 | 描述 | 最小值 | 最大值 | 解析度 | +==========+==========+==========+==========+==========+========+ | \ t\ | 8字节 | 包括日期 | 4713 BC | 294276 | 1微秒 | | imestamp | | 和时间( | | AD | | | [ (p ) | | 无时区) | | | | | ] [ | | | | | | | without | | | | | | | time | | | | | | | zone ] | | | | | | +----------+----------+----------+----------+----------+--------+ | \ t\ | 8字节 | 包括日 | 4713 BC | 294276 | 1微秒 | | imestamp | | 期和时间 | | AD | | | [ (p ) | | ,有时区 | | | | | ] with | | | | | | | time | | | | | | | zone | | | | | | +----------+----------+----------+----------+----------+--------+ | \ date | 4字节 | 日期(没 | 4713 BC | 5874897 | 1日 | | | | 有一天中 | | AD | | | | | 的时间) | | | | +----------+----------+----------+----------+----------+--------+ | \ time | 8字节 | 一天中 | 00:00:00 | 24:00:00 | 1微秒 | | [ ( p ) | | 的时间( | | | | | ] [ | | 无日期) | | | | | without | | | | | | | time | | | | | | | zone ] | | | | | | +----------+----------+----------+----------+----------+--------+ | \ time | 12字节 | 仅仅是一 | 00:00 | 24:00 | 1微秒 | | [ ( p ) | | 天中的时 | :00+1459 | :00-1459 | | | ] with | | 间(没有 | | | | | time | | 日期), | | | | | zone | | 带有时区 | | | | +----------+----------+----------+----------+----------+--------+ | \ int\ | 16字节 | 时间间隔 | -178 | 178 | 1微秒 | | erval [ | | | 000000年 | 000000年 | | | fields\ | | | | | | | ] [\ | | | | | | | (\ | | | | | | | p )\ | | | | | | | ]\ | | | | | | +----------+----------+----------+----------+----------+--------+ .. note:: .. rubric:: 注意 :name: 注意 :class: title SQL要求只写\ ``timestamp``\ 等效于\ ``timestamp without time zone``\ ,并且PostgreSQL鼓励这种行为。\ ``timestamptz``\ 被接受为\ ``timestamp with time zone``\ 的一种简写,这是一种PostgreSQL的扩展。 ``time``\ 、\ ``timestamp``\ 和\ ``interval``\ 接受一个可选的精度值 ``p`` \ ,这个精度值声明在秒域中小数点之后保留的位数。缺省情况下,在精度上没有明确的边界。\ ``p``\ 允许的范围是从 0 到 6。 ``interval``\ 类型有一个附加选项,它可以通过写下面之一的短语来限制存储的fields的集合: .. code:: literallayout YEAR MONTH DAY HOUR MINUTE SECOND YEAR TO MONTH DAY TO HOUR DAY TO MINUTE DAY TO SECOND HOUR TO MINUTE HOUR TO SECOND MINUTE TO SECOND 注意如果\ ``fields``\ 和\ ``p`` 被指定,\ ``fields``\ 必须包括\ ``SECOND``\ ,因为精度只应用于秒。 类型\ ``time with time zone``\ 是 SQL 标准定义的,但是该定义显示出了一些会影响可用性的性质。在大多数情况下, ``date``\ 、\ ``time``\ 、\ ``timestamp without time zone``\ 和\ ``timestamp with time zone``\ 的组合就应该能提供任何应用所需的全范围的日期/时间功能。   日期/时间输入 ---------------------------- 日期和时间的输入可以接受几乎任何合理的格式,包括 ISO 8601、SQL-兼容的、传统POSTGRES的和其他的形式。 对于一些格式,日期输入里的日、月和年的顺序会让人混淆, 并且支持指定所预期的这些域的顺序。把\ `DateStyle `__\ 参数设置为\ ``MDY``\ ,就是选择“月-日-年”的解释,设置为\ ``DMY``\ 就是 “日-月-年”,而\ ``YMD``\ 是 “年-月-日”。 PostgreSQL在处理日期/时间输入上比SQL标准要求的更灵活。 参阅\ `附录 B `__\ 获取关于日期/时间输入的准确的分析规则和可识别文本域,包括月份、星期几和时区。 请记住任何日期或者时间的文字输入需要由单引号包围,就象一个文本字符串一样。参考\ `节 `__\ 获取更多信息。SQL要求下面的语法 .. code:: synopsis type [ (p) ] 'value' 其中\ ``p`` 是一个可选的精度声明,它给出了在秒域中的小数位数目。精度可以被指定给\ ``time``\ 、\ ``timestamp``\ 和\ ``interval``\ 类型,并且可以取从0到6的值。这允许前文所述的值。如果在一个常数声明中没有指定任何精度,它将默认取文字值的精度(但不能超过6位)。  日期 ++++++++++++++ `表 `__\ 显示了\ ``date``\ 类型可能的输入方式。 .. container:: table :name: DATATYPE-DATETIME-DATE-TABLE **表 日期输入** .. container:: table-contents +------------------+--------------------------------------------------+ | 例子 | 描述 | +==================+==================================================+ | 1999-01-08 | ISO 8601; 任何模式下的1月8日 (推荐格式) | +------------------+--------------------------------------------------+ | January 8, 1999 | 在任何\ ``datestyle``\ 输入模式下都无歧义 | +------------------+--------------------------------------------------+ | 1/8/1999 | `` | | | MDY``\ 模式中的1月8日;\ ``DMY``\ 模式中的8月1日 | +------------------+--------------------------------------------------+ | 1/18/1999 | ``MDY``\ 模式中的1月18日;在其他模式中被拒绝 | +------------------+--------------------------------------------------+ | 01/02/03 | ``MDY``\ 模式中的2003年1月2日; | | | ``DMY``\ 模式中的2003年2月1日; | | | ``YMD``\ 模式中的2001年2月3日 | +------------------+--------------------------------------------------+ | 1999-Jan-08 | 任何模式下的1月8日 | +------------------+--------------------------------------------------+ | Jan-08-1999 | 任何模式下的1月8日 | +------------------+--------------------------------------------------+ | 08-Jan-1999 | 任何模式下的1月8日 | +------------------+--------------------------------------------------+ | 99-Jan-08 | ``YMD``\ 模式中的1月8日,否则错误 | +------------------+--------------------------------------------------+ | 08-Jan-99 | 1月8日,除了在\ ``YMD``\ 模式中错误 | +------------------+--------------------------------------------------+ | Jan-08-99 | 1月8日,除了在\ ``YMD``\ 模式中错误 | +------------------+--------------------------------------------------+ | 19990108 | ISO 8601; 任何模式中的1999年1月8日 | +------------------+--------------------------------------------------+ | 990108 | ISO 8601; 任何模式中的1999年1月8日 | +------------------+--------------------------------------------------+ | 1999.008 | 年和一年中的日子 | +------------------+--------------------------------------------------+ | J2451187 | 儒略日期 | +------------------+--------------------------------------------------+ | January 8, 99 BC | 公元前99年 | +------------------+--------------------------------------------------+  时间 ++++++++++++++ 当日时间类型是\ ``time [ (p``) ] without time zone和\ ``time [ (p``) ] with time zone。 只写\ ``time``\ 等效于\ ``time without time zone``\ 。 这些类型的有效输入由当日时间后面跟着可选的时区组成(参阅\ `表 `__\ 和\ `表 `__\ )。 如果在\ ``time without time zone``\ 的输入中指定了时区,那么它会被无声地忽略。你也可以指定一个日期但是它会被忽略,除非你使用了一个涉及到夏令时规则的时区,例如\ ``America/New_York``\ 。在这种情况下,为了判断是应用了标准时间还是夏令时时间,要求指定该日期。适当的时区偏移被记录在\ ``time with time zone``\ 值中。 .. container:: table :name: DATATYPE-DATETIME-TIME-TABLE **表 时间输入** .. container:: table-contents +----------------------------------+----------------------------------+ | 例子 | 描述 | +==================================+==================================+ | ``04:05:06.789`` | ISO 8601 | +----------------------------------+----------------------------------+ | ``04:05:06`` | ISO 8601 | +----------------------------------+----------------------------------+ | ``04:05`` | ISO 8601 | +----------------------------------+----------------------------------+ | ``040506`` | ISO 8601 | +----------------------------------+----------------------------------+ | ``04:05 AM`` | 和04:05一样,AM并不影响值 | +----------------------------------+----------------------------------+ | ``04:05 PM`` | 和16:05一样,输入的小时必须为 <= | | | 12 | +----------------------------------+----------------------------------+ | ``04:05:06.789-8`` | ISO 8601 | +----------------------------------+----------------------------------+ | ``04:05:06-08:00`` | ISO 8601 | +----------------------------------+----------------------------------+ | ``04:05-08:00`` | ISO 8601 | +----------------------------------+----------------------------------+ | ``040506-08`` | ISO 8601 | +----------------------------------+----------------------------------+ | ``04:05:06 PST`` | 缩写指定的时区 | +----------------------------------+----------------------------------+ | ``2003-0 | 全名指定的时区 | | 4-12 04:05:06 America/New_York`` | | +----------------------------------+----------------------------------+ .. container:: table :name: DATATYPE-TIMEZONE-TABLE **表 时区输入** .. container:: table-contents ==================== ====================== 例子 描述 ==================== ====================== ``PST`` 缩写(太平洋标准时间) ``America/New_York`` 完整时区名 ``PST8PDT`` POSIX风格的时区声明 ``-8:00`` PST的ISO-8601偏移 ``-800`` PST的ISO-8601偏移 ``-8`` PST的ISO-8601偏移 ``zulu`` UTC的军方缩写 ``z`` ``zulu``\ 的短形式 ==================== ====================== 参考\ `节 `__\ 可以了解如何指定时区。  时间戳 ++++++++++++++ 时间戳类型的有效输入由一个日期和时间的串接组成,后面跟着一个可选的时区,一个可选的\ ``AD``\ 或者\ ``BC``\ (另外,\ ``AD``/``BC``\ 可以出现在时区前面,但这个顺序并非最佳)。 因此: .. code:: programlisting 1999-01-08 04:05:06 和: .. code:: programlisting 1999-01-08 04:05:06 -8:00 都是有效的值,它遵循ISO 8601 标准。另外,使用广泛的格式: .. code:: programlisting January 8 04:05:06 1999 PST 也被支持。 SQL标准通过“+”或者“-”符号的存在以及时间后面的时区偏移来区分\ ``timestamp without time zone``\ 和\ ``timestamp with time zone``\ 文字。因此,根据标准, .. code:: programlisting TIMESTAMP '2004-10-19 10:23:54' 是一个\ ``timestamp without time zone``\ , 而 .. code:: programlisting TIMESTAMP '2004-10-19 10:23:54+02' 是一个\ ``timestamp with time zone``\ 。PostgreSQL从来不会在确定文字串的类型之前检查其内容,因此会把上面两个都看做是 ``timestamp without time zone``\ 。因此要保证把上面的文字当作\ ``timestamp with time zone``\ 看待, 就要给它正确的显式类型: .. code:: programlisting TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02' 如果一个文字已被确定是\ ``timestamp without time zone``\ ,PostgreSQL将不声不响忽略任何其中指出的时区。 即,结果值是从输入值的日期/时间域衍生出来的,并且没有就时区进行调整。 对于\ ``timestamp with time zone``\ ,内部存储的值总是 UTC (全球统一时间,以前也叫格林威治时间GMT)。如果一个输入值有明确的时区声明, 那么它将用该时区合适的偏移量转换成 UTC。如果在输入串里没有时区声明, 那么它就被假设是在系统的\ `TimeZone `__\ 参数里的那个时区,然后使用这个 ``timezone``\ 时区的偏移转换成 UTC。 如果一个\ ``timestamp with time zone``\ 值被输出,那么它总是从 UTC 转换成当前的\ ``timezone``\ 时区,并且显示为该时区的本地时间。要看其它时区的时间,要么修改\ ``timezone``\ ,要么使用\ ``AT TIME ZONE``\ 构造(参阅\ `节 `__\ )。 在\ ``timestamp without time zone``\ 和\ ``timestamp with time zone``\ 之间的转换通常假设\ ``timestamp without time zone``\ 值应该以\ ``timezone``\ 本地时间的形式接受或者写出。为该转换指定一个不同的可以用\ ``AT TIME ZONE``\ 。  特殊值 ++++++++++++++ 为了方便,PostgreSQL支持一些特殊日期/时间输入值,如\ `表 `__\ 所示。这些值中\ ``infinity``\ 和\ ``-infinity``\ 被在系统内部以特殊方式表示并且将被原封不动地显示。但是其他的仅仅只是概念上的速写,当被读到的时候会被转换为正常的日期/时间值(特殊地,\ ``now``\ 及相关串在被读到时立刻被转换到一个指定的时间值)。在作为常量在SQL命令中使用时,所有这些值需要被包括在单引号内。 .. container:: table :name: DATATYPE-DATETIME-SPECIAL-TABLE **表 特殊日期/时间输入** .. container:: table-contents +---------------+-------------------------+-------------------------+ | 输入串 | 合法类型 | 描述 | +===============+=========================+=========================+ | ``epoch`` | ``date``, ``timestamp`` | 1970-01-01 | | | | 00:00 | | | | :00+00(Unix系统时间0) | +---------------+-------------------------+-------------------------+ | ``infinity`` | ``date``, ``timestamp`` | 比任何其他时间戳都晚 | +---------------+-------------------------+-------------------------+ | ``-infinity`` | ``date``, ``timestamp`` | 比任何其他时间戳都早 | +---------------+-------------------------+-------------------------+ | ``now`` | ``date``, ``time``, | 当前事务的开始时间 | | | ``timestamp`` | | +---------------+-------------------------+-------------------------+ | ``today`` | ``date``, ``timestamp`` | 今日午夜 (``00:00``) | +---------------+-------------------------+-------------------------+ | ``tomorrow`` | ``date``, ``timestamp`` | 明日午夜 (``00:00``) | +---------------+-------------------------+-------------------------+ | ``yesterday`` | ``date``, ``timestamp`` | 昨日午夜 (``00:00``) | +---------------+-------------------------+-------------------------+ | ``allballs`` | ``time`` | 00:00:00.00 UTC | +---------------+-------------------------+-------------------------+ 下列SQL-兼容的函数可以被用来为相应的数据类型获得当前时间值: ``CURRENT_DATE``\ 、\ ``CURRENT_TIME``\ 、 ``CURRENT_TIMESTAMP``\ 、\ ``LOCALTIME``\ 、 ``LOCALTIMESTAMP``\ 。后四种接受一个可选的亚秒精度声明(参见\ `节 `__\ )。注意这些是SQL函数并且在数据输入串中\ *不*\ 被识别。  日期/时间输出 -------------- 时间/日期类型的输出格式可以设成四种风格之一: ISO 8601、SQL(Ingres)、传统的POSTGRES(Unix的date格式)或 German 。缺省是ISO格式(ISO标准要求使用 ISO 8601 格式。ISO输出格式的名字是历史偶然)。\ `表 `__\ 显示了每种输出风格的例子。\ ``date``\ 和\ ``time``\ 类型的 输出通常只有日期或时间部分和例子中一致。不过,POSTGRES风格输出的是ISO格式的只有日期的值。 .. container:: table :name: DATATYPE-DATETIME-OUTPUT-TABLE **表 日期/时间输出风格** .. container:: table-contents ============ ================= ================================ 风格声明 描述 例子 ============ ================= ================================ ``ISO`` ISO 8601, SQL标准 ``1997-12-17 07:37:16-08`` ``SQL`` 传统风格 ``12/17/1997 07:37:16.00 PST`` ``Postgres`` 原始风格 ``Wed Dec 17 07:37:16 1997 PST`` ``German`` 地区风格 ``17.12.1997 07:37:16.00 PST`` ============ ================= ================================ .. note:: .. rubric:: 注意 :name: 注意-1 :class: title ISO 8601指定使用大写字母\ ``T``\ 来分隔日期和时间。PostgreSQL在输入上接受这种格式,但是在输出时它采用一个空格而不是\ ``T``\ ,如上所示。和一些其他数据库系统一样,这是为了可读性以及与RFC 3339的一致性。 SQL和POSTGRES风格中,如果DMY域顺序被指定,“日”将出现在“月”之前,否则“月”出现在“日”之前(有关该设置如何影响输入值的解释,请参考\ `节 `__\ )。\ `表 `__\ 给出了例子。 .. container:: table :name: DATATYPE-DATETIME-OUTPUT2-TABLE **表 日期顺序习惯** .. container:: table-contents +---------------------+----------------------+----------------------+ | ``datestyle``\ 设置 | 输入顺序 | 例子输出 | +=====================+======================+======================+ | ``SQL, DMY`` | ``日`` | ``17/12/19 | | | / ``月`` / ``年`` | 97 15:37:16.00 CET`` | +---------------------+----------------------+----------------------+ | ``SQL, MDY`` | ``月`` | ``12/17/19 | | | / ``日`` / ``年`` | 97 07:37:16.00 PST`` | +---------------------+----------------------+----------------------+ | ``Postgres, DMY`` | ``日`` | ``Wed 17 Dec | | | / ``月`` / ``年`` | 07:37:16 1997 PST`` | +---------------------+----------------------+----------------------+ 日期/时间风格可以由用户使用\ ``SET datestyle``\ 命令选取,在\ ``postgresql.conf``\ 配置文件里的参数\ `DateStyle `__\ 设置或者在服务器或客户端的\ ``PGDATESTYLE``\ 环境变量里设置。 格式化函数\ ``to_char``\ (见\ `节 `__\ )也可以作为一个更灵活的方式来格式化日期/时间输出。   时区 -------------- 时区和时区习惯不仅仅受地球几何形状的影响,还受到政治决定的影响。 到了19世纪,全球的时区变得稍微标准化了些,但是还是易于遭受随意的修改,部分是因为夏时制规 则。PostgreSQL使用广泛使用的 IANA (Olson) 时区数据库来得到有关历史时区规则的信息。对于未来的时间,我们假设关于一个给定时区的最新已知 规则将会一直持续到无穷远的未来。 PostgreSQL努力在典型使用中与SQL标准的定义相兼容。但SQL标准在日期和时间类型和功能上有一些奇怪的混淆。两个显而易见的问题是: .. container:: itemizedlist - 尽管\ ``date``\ 类型与时区没有联系,而\ ``time``\ 类型却可以有。 然而,现实世界的时区只有在与时间和日期都关联时才有意义, 因为偏移(时差)可能因为实行类似夏时制这样的制度而在一年里有所变化。 - 缺省的时区会指定一个到UTC的数字常量偏移(时差)。因此,当跨DST边界做日期/时间算术时, 我们根本不可能适应于夏时制时间。 为了克服这些困难,我们建议在使用时区的时候,使用那些同时包含日期和时间的日期/时间类型。我们\ *不*\ 建议使用类型 ``time with time zone`` (尽管PostgreSQL出于遗留应用以及与SQL标准兼容性的考虑支持这个类型)。 PostgreSQL假设你用于任何类型的本地时区都只包含日期或时间。 在系统内部,所有时区相关的日期和时间都用UTC存储。它们在被显示给客户端之前会被转换成由\ `TimeZone `__\ 配置参数指定的本地时间。 PostgreSQL允许你使用三种不同形式指定时区: .. container:: itemizedlist - 一个完整的时区名字,例如\ ``America/New_York``\ 。能被识别的时区名字被列在\ ``pg_timezone_names``\ 视图中(参见\ `节 `__\ )。PostgreSQL用广泛使用的 IANA 时区数据来实现该目的,因此相同的时区名字也可以在其他软件中被识别。 - 一个时区缩写,例如\ ``PST``\ 。这样一种声明仅仅定义了到UTC的一个特定偏移,而不像完整时区名那样指出整套夏令时转换日期规则。能被识别的缩写被列在\ ``pg_timezone_abbrevs``\ 视图中(参见\ `节 `__\ )。你不能将配置参数\ `TimeZone `__\ 或\ `log_timezone `__\ 设置成一个时区缩写,但是你可以在日期/时间输入值和\ ``AT TIME ZONE``\ 操作符中使用时区缩写。 - 除了时区名和缩写,PostgreSQL将接受POSIX-风格的 时区声明,形式为\ *``STD``\ ``offset``*\ 或 *``STD``\ ``offset``\ ``DST``*\ , 其中\ *``STD``*\ 是一个区域缩写、\ *``offset``*\ 是从UTC西 起的以小时计的数字偏移量、\ *``DST``*\ 是一个可选的夏令时区域缩 写(被假定为给定偏移量提前一小时)。例如,如果\ ``EST5EDT``\ 还不是一 个被识别的区域名,它可以被接受并且可能和美国东海岸时间的功效相同。在这种语法中, 一个时区缩写可以是一个字母的字符串或者由尖括号(\ ``<>``\ )包围 的任意字符串。当一个夏令时区域缩写出现时,会假定根据 IANA 时区数据库的 ``posixrules``\ 条目中使用的同一个夏令时转换规则使用它。 在一个标准的PostgreSQL安装中, ``posixrules``\ 和\ ``US/Eastern``\ 相同, 因此POSIX-风格的时区声明遵循美国的夏令时规则。如果需要,你可以通过替换 ``posixrules``\ 文件来调整这种行为。 简而言之,在缩写和全称之间是有不同的:缩写表示从UTC开始的一个特定偏移量, 而很多全称表示一个本地夏令时规则并且因此具有两种可能的UTC偏移量。例如, ``2014-06-04 12:00 America/New_York``\ 表示纽约本地时间的中午, 这个特殊的日期是东部夏令时间(UTC-4)。因此\ ``2014-06-04 12:00 EDT`` 指定的是同一个时间点。但是\ ``2014-06-04 12:00 EST``\ 指定东部标准时间的 中午(UTC-5),不管在那个日期夏令时是否生效。 更要命的是,某些行政区已经使用相同的时区缩写在不同的时间表示不同的 UTC 偏移量。例如, 在莫斯科\ ``MSK``\ 在某些年份表示 UTC+3 而在另一些年份表示 UTC+4。 PostgreSQL 会根据在指定的日期它们到底表示什么(或者最近表示什么) 来解释这种缩写。但是,正如上面的\ ``EST``\ 例子所示,这并不是必须和那一天的本地 标准时间相同。 你应该注意到POSIX-风格的时区特性可能导致伪造的输入被接受,因为它没有对区域缩写合理性的检查。例如\ ``SET TIMEZONE TO FOOBAR0``\ 将会正常工作,让系统实际使用一个相当奇怪的UTC缩写。另一个需要记住的问题是在POSIX时区名中,正值的偏移量被用于格林威治\ *以西*\ 的位置。在其他情况下,PostgreSQL将遵循 ISO-8601 惯例,认为正值的时区偏移量是格林威治\ *以东*\ 。 在所有情况下,时区名及其缩写都是大小写不敏感的(这是对PostgreSQL 2之前版本的一个修改,在这些版本中某些环境下时区名是大小写敏感的而在另外一些环境中却是大小写不敏感的)。 时区名和缩写都不是硬写在服务器中的,它们是从存储在安装目录下的\ ``.../share/timezone/``\ 和\ ``.../share/timezonesets/``\ 子目录中获取的(参见\ `节 `__\ )。 `TimeZone `__\ 配置参数可以在文件\ ``postgresql.conf``\ 中被设置,或者使用\ `章 `__\ 中描述的任何一种标准方法设置。同时也有一些特殊的方法来设置它: .. container:: itemizedlist - SQL命令\ ``SET TIME ZONE``\ 为会话设置时区。它是\ ``SET TIMEZONE TO``\ 的另一种拼写,它更加符合SQL的语法。 - libpq客户端使用\ ``PGTZ``\ 环境变量来通过连接发送一个\ ``SET TIME ZONE``\ 命令给服务器。  间隔输入 -------------- ``interval``\ 值可以使用下列语法书写: .. code:: synopsis [@] quantity unit [quantity unit...] [direction] 其中\ ``quantity``\ 是一个数字(很可能是有符号的); ``unit``\ 是\ ``毫秒``\ 、 ``millisecond``\ 、\ ``second``\ 、 ``minute``\ 、\ ``hour``\ 、\ ``day``\ 、 ``week``\ 、\ ``month``\ 、\ ``year``\ 、 ``decade``\ 、\ ``century``\ 、\ ``millennium`` 或者缩写或者这些单位的复数; ``direction``\ 可以是\ ``ago``\ 或者为空。At符号(\ ``@``\ )是一个可选的噪声。不同单位的数量通过合适的符号计数被隐式地添加。\ ``ago``\ 对所有域求反。如果\ `IntervalStyle `__\ 被设置为\ ``postgres_verbose``\ ,该语法也被用于间隔输出。 日、小时、分钟和秒的数量可以不适用显式的单位标记指定。例如,\ ``'1 12:59:10'``\ 被读作\ ``'1 day 12 hours 59 min 10 sec'``\ 。同样,一个年和月的组合可以使用一个横线指定,例如\ ``'200-10'``\ 被读作\ ``'200年10个月'``\ (这些较短的形式事实上是SQL标准唯一许可的形式,并且在\ ``IntervalStyle``\ 被设置为\ ``sql_standard``\ 时用于输出)。 间隔值也可以被写成 ISO 8601 时间间隔,使用该标准4.4.3.2小节的“带标志符的格式”或者4.4.3.3小节的“替代格式”。带标志符的格式看起来像这样: .. code:: synopsis P quantity unit [ quantity unit ...] [ T [ quantity unit ...]] 该串必须以一个\ ``P``\ 开始,并且可以包括一个引入当日时间单位的\ ``T``\ 。可用的单位缩写在\ `表 `__\ 中给出。单位可以被忽略,并且可以以任何顺序指定,但是小于一天的单位必须出现在\ ``T``\ 之后。特别地,\ ``M``\ 的含义取决于它出现在\ ``T``\ 之前还是之后。 .. container:: table :name: DATATYPE-INTERVAL-ISO8601-UNITS **表 ISO 8601 间隔单位缩写** .. container:: table-contents ==== ==================== 缩写 含义 ==== ==================== Y 年 M 月(在日期部分中) W 周 D 日 H 小时 M 分钟 (在时间部分中) S 秒 ==== ==================== 如果使用替代格式: .. code:: synopsis P [ years-months-days ] [ T hours:minutes:seconds ] 串必须以\ ``P``\ 开始,并且一个\ ``T``\ 分隔间隔的日期和时间部分。其值按照类似于 ISO 8601日期的数字给出。 在用一个\ *``域``*\ 声明书写一个间隔常量时,或者为一个用\ *``域``*\ 声明定义的间隔列赋予一个串时,对于为标记的量的解释依赖于\ *``域``*\ 。例如\ ``INTERVAL '1' YEAR``\ 被解读成1年,而\ ``INTERVAL '1'``\ 表示1秒。同样,\ *``域``*\ 声明允许的最后一个有效域“右边”的域值会被无声地丢弃掉。例如书写\ ``INTERVAL '1 day 2:03:04' HOUR TO MINUTE``\ 将会导致丢弃秒域,而不是日域。 根据SQL标准,一个间隔值的所有域都必须由相同的符号,这样一个领头的负号将会应用到所有域;例如在间隔文字\ ``'-1 2:03:04'``\ 中的负号会被应用于日、小时、分钟和秒部分。PostgreSQL允许域具有不同的符号,并且在习惯上认为以文本表示的每个域具有独立的符号,因此在这个例子中小时、分钟和秒部分被认为是正值。如果\ ``IntervalStyle``\ 被设置为\ ``sql_standard``\ ,则一个领头的符号将被认为是应用于所有域(但是仅当没有额外符号出现)。否则将使用传统的PostgreSQL解释。为了避免混淆,我们推荐在任何域为负值时为每一个域都附加一个显式的符号。 在冗长的输入格式中,以及在更紧凑输入格式的某些域中,域值可以有分数部分;例如\ ``'1.5 week'``\ 或\ ``'01:02:03.45'``\ 。这样的输入被转换为合适的月数、日数和秒数用于存储。当这样会导致月和日中的分数时,分数被加到低序域中,使用的转换因子是1月=30日和1日=24小时。例如,\ ``'1.5 month'``\ 会变成1月和15日。只有秒总是在输出时被显示为分数。 `表 `__\ 展示了一些有效\ ``interval``\ 输入的例子。 .. container:: table :name: DATATYPE-INTERVAL-INPUT-EXAMPLES **表 间隔输入** .. container:: table-contents +----------------------------------+----------------------------------+ | 例子 | 描述 | +==================================+==================================+ | 1-2 | SQL标准格式:1年2个月 | +----------------------------------+----------------------------------+ | 3 4:05:06 | SQL标准格式:3日4小时5分钟6秒 | +----------------------------------+----------------------------------+ | 1 year 2 months 3 days 4 hours 5 | 传统Postgres | | minutes 6 seconds | 格式:1年2个月3日4小时5分钟6秒钟 | +----------------------------------+----------------------------------+ | P1Y2M3DT4H5M6S | “带标志符的”ISO 8601 | | | 格式:含义同上 | +----------------------------------+----------------------------------+ | P0001-02-03T04:05:06 | ISO 8601 的“替代格式”:含义同上 | +----------------------------------+----------------------------------+ 在内部,\ ``interval``\ 值被存储为months、days以及seconds。之所以这样做是因为一个月中的天数是变化的,并且在涉及到夏令时调整时一天可以有23或者25个小时。months以及days域是整数,而seconds域可以存储分数。因为区间通常是从常量字符串或者\ ``timestamp``\ 减法创建而来,这种存储方法在大部分情况下都很好,但是也可能导致预料之外的结果: .. code:: programlisting SELECT EXTRACT(hours from '80 minutes'::interval); date_part ----------- 1 SELECT EXTRACT(days from '80 hours'::interval); date_part ----------- 0 函数\ ``justify_days``\ 和\ ``justify_hours``\ 可以用来调整溢出其正常范围之外的days和hours。  间隔输出 -------------- 间隔类型的输出格式可以被设置为四种风格之一:\ ``sql_standard``\ 、\ ``postgres``\ 、\ ``postgres_verbose``\ 或\ ``iso_8601``\ ,设置方法使用\ ``SET intervalstyle``\ 命令。默认值为\ ``postgres``\ 格式。\ `表 `__\ 展示了每种输出风格的例子。 如果间隔值符合SQL标准的限制(仅年-月或仅日-时间,没有正负值部分的混合),\ ``sql_standard``\ 风格为间隔文字串产生符合SQL标准规范的输出。否则输出将看起来像一个标准的年-月文字串跟着一个日-时间文字串,并且带有显式添加的符号以区分混合符号的间隔。 当\ `DateStyle `__\ 参数被设置为\ ``ISO``\ 时,\ ``postgres``\ 风格的输出匹配PostgreSQL 4版本以前的输出。 当\ ``DateStyle``\ 参数被设置为非\ ``ISO``\ 输出时,\ ``postgres_verbose``\ 风格的输出匹配PostgreSQL 4版本以前的输出。 ``iso_8601``\ 风格的输出匹配在ISO 8601标准的4.4.3.2小节中描述的“带标志符的格式”。 .. container:: table :name: INTERVAL-STYLE-OUTPUT-TABLE **表 间隔输出风格例子** .. container:: table-contents +----------------+----------------+----------------+----------------+ | 风格声明 | 年-月间隔 | 日-时间间隔 | 混合间隔 | +================+================+================+================+ | | 1-2 | 3 4:05:06 | -1-2 +3 | |``sql_standard``| | | -4:05:06 | +----------------+----------------+----------------+----------------+ | ``postgres`` | 1 year 2 mons | 3 days | -1 year -2 | | | | 04:05:06 | mons +3 days | | | | | -04:05:06 | +----------------+----------------+----------------+----------------+ | ``post | @ 1 year 2 | @ 3 days 4 | @ 1 year 2 | | gres_verbose`` | mons | hours 5 mins 6 | mons -3 days 4 | | | | secs | hours 5 mins 6 | | | | | secs ago | +----------------+----------------+----------------+----------------+ | ``iso_8601`` | P1Y2M | P3DT4H5M6S | P-1Y- | | | | | 2M3DT-4H-5M-6S | +----------------+----------------+----------------+----------------+