9.8. Функции форматирования данных
Функции форматирования в PostgreSQL предоставляют богатый набор инструментов для преобразования самых разных типов данных (дата/время, целое, числа с плавающей и фиксированной точкой) в форматированные строки и обратно. Все они перечислены в Таблице 9.23. Все эти функции следует одному соглашению: в первом аргументе передаётся значение, которое нужно отформатировать, а во втором — шаблон, определяющий формат ввода или вывода.
Таблица 9.23. Функции форматирования
Примечание
Также имеется функция to_timestamp с одним аргументом; см. Таблицу 9.30.
Шаблон вывода to_char может содержать ряд кодов, которые распознаются при форматировании и заменяются соответствующими данными. Любой текст, который не является кодом, копируется в результат в неизменном виде. Подобным образом, в строке шаблона ввода (для других функций) коды шаблона определяют, какие значения содержит передаваемая текстовая строка.
Все коды форматирования даты и времени перечислены в Таблице 9.24.
Таблица 9.24. Коды форматирования даты/времени
| Код | Описание |
|---|---|
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 | последняя цифра года |
IYYY | недельный год по ISO 8601 (4 или более цифр) |
IYY | последние 3 цифры недельного года по ISO 8601 |
IY | последние 2 цифры недельного года по ISO 8601 |
I | последняя цифра недельного года по ISO 8601 |
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) |
IDDD | номер дня в году по ISO 8601 (001-371; 1 день — понедельник первой недели по ISO) |
DD | день месяца (01-31) |
D | номер дня недели, считая с воскресенья (1) до субботы (7) |
ID | номер дня недели по ISO 8601, считая с понедельника (1) до воскресенья (7) |
W | неделя месяца (1-5) (первая неделя начинается в первое число месяца) |
WW | номер недели в году (1-53) (первая неделя начинается в первый день года) |
IW | номер недели в году по ISO 8601 (01-53; первый четверг года относится к неделе 1) |
CC | век (2 цифры) (двадцать первый век начался 2001-01-01) |
J | юлианская дата (целое число дней от 24 ноября 4714 г. до н. э. 00:00 по местному времени; см. Раздел B.7) |
Q | квартал (игнорируется функциями to_date и to_timestamp) |
RM | номер месяца римскими цифрами в верхнем регистре (I-XII; I=январь) |
rm | номер месяца римскими цифрами в нижнем регистре (i-xii; i=январь) |
TZ | сокращённое название часового пояса в верхнем регистре (поддерживается только в to_char) |
tz | сокращённое название часового пояса в нижнем регистре (поддерживается только в to_char) |
OF | смещение часового пояса от UTC (поддерживается только в to_char) |
К любым кодам форматирования можно добавить модификаторы, изменяющие их поведение. Например, шаблон форматирования FMMonth включает код Month с модификатором FM. Модификаторы, предназначенные для форматирования даты/времени, перечислены в Таблице 9.25.
Таблица 9.25. Модификаторы кодов для форматирования даты/времени
| Модификатор | Описание | Пример |
|---|---|---|
Приставка FM | режим заполнения (подавляет ведущие нули и дополнение пробелами) | FMMonth |
Окончание TH | окончание порядкового числительного в верхнем регистре | DDTH, например 12TH |
Окончание th | окончание порядкового числительного в нижнем регистре | DDth, например 12th |
Приставка FX | глобальный параметр фиксированного формата (см. замечания) | FX Month DD Day |
Приставка TM | режим перевода (выводятся локализованные названия дней и месяцев, исходя из lc_time) | TMMonth |
Окончание SP | режим числа прописью (не реализован) | DDSP |
Замечания по использованию форматов даты/времени:
FMподавляет дополняющие пробелы и нули справа, которые в противном случае будут добавлены, чтобы результат имел фиксированную ширину. В PostgreSQL модификаторFMдействует только на следующий код, тогда как в OracleFMеё действие распространяется на все последующие коды, пока не будет отключено последующим модификаторомFM.TMне затрагивает замыкающие пробелы. Функцииto_timestampиto_dateигнорируют указаниеTM.to_timestampиto_dateпропускают повторяющиеся пробелы во входной строке, если только не используется параметрFX. Например,to_timestamp('2000 JUN', 'YYYY MON')будет работать, ноto_timestamp('2000 JUN', 'FXYYYY MON')вернёт ошибку, так какto_timestampв данном случае ожидает только один разделяющий пробел. ПриставкаFXдолжна быть первой в шаблоне.to_timestampиto_dateпредназначены для обработки входных форматов, для которых недостаточно простого приведения. Эти функции интерпретируют вводимые данные с послаблениями, проверяя только грубые ошибки. Хотя они выдают корректные данные, результат может отличаться от ожидаемого. В частности, входные аргументы этих функций не ограничиваются обычными диапазонами, так чтоto_date('20096040','YYYYMMDD')выдаёт2014-01-17, а не ошибку. С приведением такого не происходит.Шаблоны для функций
to_charмогут содержать обычный текст; он будет выведен в неизменном виде. Чтобы вывести текст принудительно, например, если в нём оказываются поддерживаемые коды, его можно заключить в кавычки. Например, в строке'"Hello Year "YYYY', кодYYYYбудет заменён номером года, а букваYв словеYearостанется неизменной. В функцияхto_date,to_numberиto_timestampпри обработке подстроки в кавычках просто пропускаются символы входной строки по числу символов в подстроке, например для"XX"будут пропущены два символа.Если вы хотите получить в результате кавычки, перед ними нужно добавить обратную косую черту, например так:
'\"YYYY Month\"'.Если формат года определяется менее, чем 4 цифрами, например, как
YYY, и в переданном значении года тоже меньше 4 цифр, год пересчитывается в максимально близкий к году 2020, т. е.95воспринимается как 1995.Функции
to_timestampиto_dateвоспринимают отрицательные значения годов как относящиеся к годам до н. э. Если же указать отрицательное значение и добавить явный признакBC(до н. э.), год будет относиться к н. э. Нулевое значение года воспринимается как 1 год до н. э.В функциях
to_timestampиto_dateс преобразованиемYYYYсвязано ограничение, когда обрабатываемый год записывается более чем 4 цифрами. ПослеYYYYнеобходимо будет добавить нецифровой символ или соответствующий код, иначе год всегда будет восприниматься как 4 цифры. Например, вto_date('200001131', 'YYYYMMDD')(с годом 20000) год будет интерпретирован как состоящий из 4 цифр; чтобы исправить ситуацию, нужно добавить нецифровой разделитель после года, как вto_date('20000-1131', 'YYYY-MMDD'), или код как вto_date('20000Nov31', 'YYYYMonDD').В преобразованиях из строки в тип
timestampилиdate, полеCC(век) игнорируется, если шаблон включает поляYYY,YYYYилиY,YYY. КогдаCCиспользуется сYYилиY, год вычисляется как год данного столетия. Если присутствует только код столетия, без года, подразумевается первый год этого века.Даты по недельному календарю ISO 8601 (отличающиеся от григорианских) можно передать функциям
to_timestampиto_dateодним из двух способов:Год, номер недели и дня недели: например,
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.)При преобразовании из текстовой строки в
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 seconds.Нумерация дней недели в
to_char(..., 'ID')соответствует функцииextract(isodow from ...), но нумерацияto_char(..., 'D')не соответствует нумерации, принятой вextract(dow from ...).Функция
to_char(interval)обрабатывает форматыHHиHH12в рамках 12 часов, то есть 0 и 36 часов будут выводиться как12, тогда какHH24выводит значение полностью и для интервалов выводимое значение может превышать 23.
Коды форматирования числовых значений перечислены в Таблице 9.26.
Таблица 9.26. Коды форматирования чисел
| Код | Описание |
|---|---|
9 | позиция цифры (может отсутствовать, если цифра незначащая) |
0 | позиция цифры (присутствует всегда, даже если цифра незначащая) |
. (точка) | десятичная точка |
, (запятая) | разделитель групп (тысяч) |
PR | отрицательное значение в угловых скобках |
S | знак, добавляемый к числу (с учётом локали) |
L | символ денежной единицы (с учётом локали) |
D | разделитель целой и дробной части числа (с учётом локали) |
G | разделитель групп (с учётом локали) |
MI | знак минус в заданной позиции (если число < 0) |
PL | знак плюс в заданной позиции (если число > 0) |
SG | знак плюс или минус в заданной позиции |
RN | число римскими цифрами (в диапазоне от 1 до 3999) |
TH или th | окончание порядкового числительного |
V | сдвиг на заданное количество цифр (см. замечания) |
EEEE | экспоненциальная запись числа |
Замечания по использованию форматов чисел:
0обозначает позицию цифры, которая будет выводиться всегда, даже если это незначащий ноль слева или справа.9также обозначает позицию цифры, но если это незначащий ноль слева, он заменяется пробелом, а если справа и задан режим заполнения, он удаляется. (Для функцииto_number()эти два символа равнозначны.)Символы шаблона
S,L,DиGпредставляют знак, символ денежной единицы, десятичную точку и разделитель тысяч, как их определяет текущая локаль (см. lc_monetary и lc_numeric). Символы точка и запятая представляют те же символы, обозначающие десятичную точку и разделитель тысяч, но не зависят от локали.Если в шаблоне
to_char()отсутствует явное указание положения знака, для него резервируется одна позиция рядом с числом (слева от него). Если левее нескольких9помещёнS, знак также будет приписан слева к числу.Знак числа, полученный кодами
SG,PLилиMI, не присоединяется к числу; например,to_char(-12, 'MI9999')выдаёт'- 12', тогда какto_char(-12, 'S9999')—' -12'. (В OracleMIне может идти перед9, наоборот9нужно указать передMI.)THне преобразует значения меньше 0 и не поддерживает дробные числа.PL,SGиTH— расширения PostgreSQL.Vcto_charумножает вводимое значение на10^, гдеnn— число цифр, следующих заV.Vсto_numberподобным образом делит значение. Функцииto_charиto_numberне поддерживаютVс дробными числами (например,99.9V99не допускается).Код
EEEE(научная запись) не может сочетаться с любыми другими вариантами форматирования или модификаторами, за исключением цифр и десятичной точки, и должен располагаться в конце строки шаблона (например,9.99EEEE— допустимый шаблон).
Для изменения поведения кодов к ним могут быть применены определённые модификаторы. Например, FM99.99 обрабатывается как код 99.99 с модификатором FM. Все модификаторы для форматирования чисел перечислены в Таблице 9.27.
Таблица 9.27. Модификаторы шаблонов для форматирования чисел
| Модификатор | Описание | Пример |
|---|---|---|
Приставка FM | режим заполнения (подавляет завершающие нули и дополнение пробелами) | FM99.99 |
Окончание TH | окончание порядкового числительного в верхнем регистре | 999TH |
Окончание th | окончание порядкового числительного в нижнем регистре | 999th |
В Таблице 9.28 приведены некоторые примеры использования функции to_char.
Таблица 9.28. Примеры 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' |