Цикл выставления счетов, получать дату каждый месяц (нет такого 30 февраля)

#postgresql

#postgresql

Вопрос:

У меня есть столбец с именем, anchor который является timestamp . У меня есть строка со значением 30 января 2020 года. Я хочу сравнить это с 29 февраля 2020 года, и это должно дать мне 1 месяц. Даже если это не 30 дней, но у февраля больше нет дней после 29. Я пытаюсь выставлять счета каждый месяц.

Вот моя sql-скрипка —http://sqlfiddle.com /#!17/6906d/2

 create table subscription (
  id serial,
  anchor timestamp
);

insert into subscription (anchor) values 
('2020-01-30T00:00:00.0Z'),
('2019-01-30T00:00:00.0Z');

select id,
       anchor,
       AGE('2020-02-29T00:00:00.0Z', anchor) as "monthsToFeb29-2020",
       AGE('2019-02-28T00:00:00.0Z', anchor) as "monthsToFeb28-2019"
from subscription;
  

Возможно ли получить возраст так, как я говорю?

Мои ожидаемые результаты:

  • Для возраста с 30 января 2020 года по 29 февраля 2020 года я ожидаю 1,0 месяца
  • Для возраста с 30 января 2020 года по 28 февраля 2019 года я ожидаю -11,0 месяца
  • Для возраста с 30 января 2019 года по 29 февраля 2020 года я ожидаю 13,0 месяца
  • Для возраста с 30 января 2019 года по 28 февраля 2019 года я ожидаю 1,0 месяца

(вот как библиотека momentjs делает это для тех парней из node / js):

 const moment = require('moment');
moment('Jan 30 2019', 'MMM DD YYYY').diff(moment('Feb 29 2020', 'MMM DD YYYY'), 'months', true) === -13.0
moment('Jan 30 2019', 'MMM DD YYYY').diff(moment('Feb 28 2019', 'MMM DD YYYY'), 'months', true) === -1.0
  

Комментарии:

1. For age from jan 30 2020 to feb 2 2020 i expect 1.0 month здесь разница составляет 3 дня, но вы ожидаете 1 месяц? можете ли вы объяснить логику требования? Что я понял, если день больше, чем дата привязки, то вы считаете его месяцем

2. Упс @AkhileshMishra я это исправил, я имею в виду 28-е / 29-е.

Ответ №1:

Как насчет:

 select round(('2/29/2020'::date - '1/30/2020'::date) / 30.0);
 round 
-------
     1

select round(('02/28/2019'::date - '1/30/2020'::date ) / 30.0);
 round 
-------
   -11

select round(('2/29/2020'::date - '1/30/2019'::date) / 30.0);
 round 
-------
    13

select round(('2/28/2019'::date - '01/30/2019'::date) / 30.0);
 round 
-------
     1


  

Вычитание даты дает вам целочисленное значение дней, затем вы делите на 30-дневный месяц и округляете до ближайшего целого числа. Вы могли бы поместить это в функцию и использовать это.

Комментарии:

1. Спасибо, Адриан! Это очень приятно, спасибо! Я не думаю, что это идеально соответствует moment.diff но я думаю, что это определенно основа, спасибо за это! Принято!

2. Ну, moment.diff() выполняет специальную обработку в течение нескольких месяцев / лет разницы . Не уверен, что я согласен с этим, но это то, что есть.

3. Спасибо, что поделились этим! Я не знал об этом. Я попытаюсь имитировать это в postgres. Поскольку это дает мне правильное количество выставленных счетов. Например, если я различаю 30 января 2020 года и 29 февраля 2020 года, это дает мне 1. Это означает, что я должен был выставить счет пользователю дважды при запуске разница.