Вернуть отметки времени Postgres в формате 'x days a go' - PullRequest
0 голосов
/ 18 апреля 2020

В наши дни в веб-приложениях довольно часто отображаются временные метки относительно временных интервалов, например, 5 days ago, 3 hours ago, 34 minutes ago или just now, если <несколько секунд. </p>

Я попытался найти в сети функцию postgres, которая конвертировала бы метки времени в этот формат, но на удивление я не смог найти ни одной. Кто-нибудь знает какие-нибудь хорошие функции, написанные для этого?

Ответы [ 3 ]

1 голос
/ 18 апреля 2020

Вычитание временной метки из временной метки дает interval, которая содержит именно ту информацию, которую вы хотите.

Например,

select timestamp '2020-04-18 21:30:15 - timestamp '2020-04-13 14:10:00')

return

0 years 0 mons 5 days 7 hours 20 mins 15.0 secs

Вы можете использовать to_char(), чтобы получить желаемый результат:

select to_char(timestamp '2020-04-18 21:30:15' - timestamp '2020-04-13 14:10:00', 'dd "days" ago, hh24 "hours" ago, mi "minutes" ago') 

Если вы хотите что-то более динамичное c вы можете использовать это:

with t(diff) as (
  select timestamp '2020-04-18 21:30:15' - timestamp '2020-04-13 14:10:00'
)
select concat_ws(' and ', 
                  nullif(extract(year from diff), 0)||' years',
                  nullif(extract(month from diff), 0)||' months',
                  nullif(extract(day from diff), 0)||' days',
                  nullif(extract(minute from diff), 0)||' minutes')||' ago')
from t

, который возвращает:

5 days and 20 minutes ago
0 голосов
/ 18 апреля 2020

К сожалению PostgreSQL не поддерживает DATEDIFF. В противном случае вы могли бы использовать это для захвата year(s), month(s), day(s), hour(s), minute(s) ago + just now, используя этот код:

-- SQL Server --

SELECT
  CASE WHEN (DATEDIFF(yy, now(), time_field)) > 1 THEN CONCAT((DATEDIFF(yy, now(), time_field), ' years ago'))
    WHEN (DATEDIFF(yy, now(), time_field)) = 1 THEN CONCAT((DATEDIFF(yy, now(), time_field), ' year ago'))
    WHEN (DATEDIFF(mm, now(), time_field)) > 1 THEN CONCAT((DATEDIFF(mm, now(), time_field), ' months ago'))
    WHEN (DATEDIFF(mm, now(), time_field)) = 1 THEN CONCAT((DATEDIFF(mm, now(), time_field), ' month ago'))
    WHEN (DATEDIFF(dd, now(), time_field)) > 1 THEN CONCAT((DATEDIFF(dd, now(), time_field), ' days ago'))
    WHEN (DATEDIFF(dd, now(), time_field)) = 1 THEN CONCAT((DATEDIFF(dd, now(), time_field), ' day ago'))
    WHEN (DATEDIFF(hh, now(), time_field)) > 1 THEN CONCAT((DATEDIFF(hh, now(), time_field), ' hours ago'))
    WHEN (DATEDIFF(hh, now(), time_field)) = 1 THEN CONCAT((DATEDIFF(hh, now(), time_field), ' hour ago'))
    WHEN (DATEDIFF(mi, now(), time_field)) > 1 THEN CONCAT((DATEDIFF(mi, now(), time_field), ' minutes ago'))
    WHEN (DATEDIFF(mi, now(), time_field)) = 1 THEN CONCAT((DATEDIFF(mi, now(), time_field), ' minute ago'))
    ELSE 'just now'
    END AS time_ago
FROM your_table

Однако, поскольку вы используете PostgreSQL, вам придется использовать некоторый код, который выглядит не так красиво или лаконично:

-- PostgreSQL --

SELECT
  CASE
-- year(s)
    WHEN (DATE_PART('year', now()) - DATE_PART('year', time_field)) > 1
      THEN CONCAT((DATE_PART('year', now()) - DATE_PART('year', time_field)), ' years ago')
    WHEN (DATE_PART('year', now()) - DATE_PART('year', time_field)) = 1
      THEN CONCAT((DATE_PART('year', now()) - DATE_PART('year', time_field)), ' year ago')      
-- month(s)
    WHEN (((DATE_PART('year', now()) - DATE_PART('year', time_field)) * 12) + (DATE_PART('month', now(), time_field))) > 1
      THEN CONCAT((((DATE_PART('year', now()) - DATE_PART('year', time_field)) * 12) + (DATE_PART('month', now(), time_field))) ' months ago')
    WHEN (((DATE_PART('year', now()) - DATE_PART('year', time_field)) * 12) + (DATE_PART('month', now(), time_field))) = 1
      THEN CONCAT((((DATE_PART('year', now()) - DATE_PART('year', time_field)) * 12) + (DATE_PART('month', now(), time_field))) ' month ago')
-- day(s)
    WHEN DATE_PART('day', now() - time_field) > 1
      THEN CONCAT(DATE_PART('day', now() - time_field), ' days ago')
    WHEN DATE_PART('day', now() - time_field) = 1
      THEN CONCAT(DATE_PART('day', now() - time_field), ' day ago')
-- hour(s)
    WHEN ((DATE_PART('day', now() - time_field) * 24) + (DATE_PART('hour', now() - time_field))) > 1
      THEN CONCAT((DATE_PART('day', now() - time_field) * 24) + (DATE_PART('hour', now() - time_field))), ' hours ago')
    WHEN ((DATE_PART('day', now() - time_field) * 24) + (DATE_PART('hour', now() - time_field))) = 1
      THEN CONCAT((DATE_PART('day', now() - time_field) * 24) + (DATE_PART('hour', now() - time_field))), ' hour ago')
-- minute(s)
    WHEN ((DATE_PART('day', now() - time_field) * 24) + ((DATE_PART('hour', now() - time_field)) * 60) + (DATE_PART('minute', now() - time_field))) > 1
      THEN CONCAT(((DATE_PART('day', now() - time_field) * 24) + ((DATE_PART('hour', now() - time_field)) * 60) + (DATE_PART('minute', now() - time_field))), ' minutes ago')
    WHEN ((DATE_PART('day', now() - time_field) * 24) + ((DATE_PART('hour', now() - time_field)) * 60) + (DATE_PART('minute', now() - time_field))) = 1
      THEN CONCAT(((DATE_PART('day', now() - time_field) * 24) + ((DATE_PART('hour', now() - time_field)) * 60) + (DATE_PART('minute', now() - time_field))), ' minute ago')
-- seconds        
ELSE 'just now'
    END AS time_ago
FROM your_table

Обратите внимание, что для дифференциации вам понадобятся повторяющиеся строки кода между 1 и >1 для каждой части времени. Например, вам понадобится 1 day ago вместо 1 days ago.

Вот некоторая справочная документация для вас:

Функции даты и времени и операторы

Выражение CASE

0 голосов
/ 18 апреля 2020

Это будет эффективно, если будет сделано на стороне клиента. Для этого сервер БД выполнит большую обработку в памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...