Согласно стандарту ECMA-404. The JSON Data Interchange Syntax в JSON нет типа для хранения даты и времени. В каком виде они будут закодированы в каждом конкретном JSON-файле определяет его автор. Я встречал два варианта:
- Целое число содержащее UNIX-время (UNIX-time или POSIX-time), которое используется в UNIX и других POSIX-совместимых операционных системах, и определяет количество секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года.
- Строка. Формат строки зависит от фантазии автора файла, но обычно используется стандарт ISO 8601, который представляет дату и время в универсальном формате, легко читаемом как людьми, так и машинами.
Начнем с PostgreSQL. У него строку достаточно преобразовать к типу данных TIMESTAMPTZ, который хранит дату и время в формате UTC:
Не совсем то, что мне надо. Хотелось, чтобы время было - час ночи. Поэтому для преобразования зададим часовой пояс UTC:select '1975-11-21T01:34:53.666Z'::TIMESTAMPTZ(3) 21.11.1975 3:34:53.666 +02:00 AD
select '1975-11-21T01:34:53.666Z'::TIMESTAMPTZ(3) AT TIME ZONE 'UTC' 21.11.1975 1:34:53.666000 AD
У MS SQL Server для преобразования подобной строки в дату тоже можно не задумываться. Просто "скармливаем" ее функции CAST:
В T-SQL есть еще своя функция для преобразования данных - CONVERT. Ее необязательный параметр целочисленный "style" указывает на способ преобразования строки. Для даты в формате ISO 8601 с часовым поясом Z используется стиль 127:select CAST('1975-11-21T01:34:53.666Z' as DATETIME) 21.11.1975 1:34:53.667
Вроде получилось, но в долях секунды вместо 666 мы видим 667. Решить эту проблему поможет использование типа DATETIME2, который по сравнению с DATETIME, для долей секунды имеет большую точность:select CONVERT(DATETIME, '1975-11-21T01:34:53.666Z', 127) 21.11.1975 1:34:53.667
Можно было привести к типу DATETIMEOFFSET, который по сравнению с DATETIME2, хранит еще и значение часового пояса:select CAST('1975-11-21T01:34:53.666Z' as DATETIME2(3)) 21.11.1975 1:34:53.666 select CONVERT(DATETIME2(3), '1975-11-21T01:34:53.666Z', 127) 21.11.1975 1:34:53.666
select CAST('1975-11-21T01:34:53.666Z' as DATETIMEOFFSET(3)) 21.11.1975 1:34:53.666 +00:00 select CONVERT(DATETIMEOFFSET(3), '1975-11-21T01:34:53.666Z', 127) 21.11.1975 1:34:53.666 +00:00
Признаюсь, с Oracle мне пришлось повозиться. Сочинение маски для конвертации строки заняло у меня значительное время, т.к. я никак не мог "победить" символ "Z". Уже думал перед конвертацией просто удалить "Z" из строки, но потом почитал документацию и нашел элемент формата "TZH". Его нельзя использовать для преобразования в тип данных DATE, но можно использовать для TIMESTAMP:
TIMESTAMP, отличается от DATE лишь тем, что время хранится с точностью до миллиардной доли секунды. Можно еще преобразовать в тип TIMESTAMP WITH TIME ZONE, который вместе со значением даты и времени дополнительно хранит информацию о часовом поясе:select TO_TIMESTAMP('1975-11-21T01:34:53.666Z', 'YYYY-MM-DD"T"HH24:MI:SS.FF3:TZH') from dual 1975-11-21 01:34:53.666000000
select TO_TIMESTAMP_TZ('1975-11-21T01:34:53.666Z', 'YYYY-MM-DD"T"HH24:MI:SS.FF3:TZH') from dual 21.11.1975 1:34:53 +00:00
Когда то давно были написаны 4 функции для вариантов даты в JSON обычном и полученном из 1с (в нем нет Z) --
ОтветитьУдалитьфункция перевода строки JSON даты в дату
FUNCTION FN_ISODATE_TO_DATE(pDS in varchar2) return DATE
is
begin
-- строка даты в формате '2020-07-08T15:30:42Z'
return to_date(pDS,'yyyy-mm-dd"T"hh24:mi:ss"Z"');
end FN_ISODATE_TO_DATE;
-- функция перевода строки JSON даты в дату без Z
FUNCTION FN_ISODATE_TO_DATE_WOZ(pDS in varchar2) return DATE
is
begin
-- строка даты в формате '2020-07-08T15:30:42Z'
return to_date(pDS,'yyyy-mm-dd"T"hh24:mi:ss');
end;
-- функция перевода даты в строку JSON даты
FUNCTION FN_DATE_TO_ISODATE(pD in date) return VARCHAR2
is
begin
-- строка даты в формате '2020-07-08T15:30:42Z'
return TO_CHAR(pD,'yyyy-mm-dd"T"hh24:mi:ss"Z"');
end FN_DATE_TO_ISODATE;
-- функция перевода даты в строку JSON даты без Z
FUNCTION FN_DATE_TO_ISODATE_WOZ(pD in date) return VARCHAR2
is
begin
-- строка даты в формате '2020-07-08T15:30:42Z'
return TO_CHAR(pD,'yyyy-mm-dd"T"hh24:mi:ss');
end;
Упс...Применимо к Oracle. Другие сервера не проверял.
ОтветитьУдалитьУ всех СУБД свой подход и свои головняки
Удалить