postgresql Postgres:是从现在到每一个生日的间隔日期

i7uaboj4  于 2023-06-05  发布在  PostgreSQL
关注(0)|答案(4)|浏览(174)

我希望能够返回用户谁有一个生日从现在到指定的时间间隔。

用户模型

  • name(string)
  • 生日(日期)
    我的时间间隔= 30天
    数据集
|---------------------|------------------|------------------|
|      id             |     name         |     birthday     |
|---------------------|------------------|------------------|
|          1          |        Tim       |   27/06/1994     |
|---------------------|------------------|------------------|

我的尝试

SELECT * FROM User where User.birthday BETWEEN NOW()::timestamp AND to_char(NOW() + interval '30 days','MM-DD')::timestamp;

返回

空的。Postgres假设省略年份实际上是指第1年。

我想要的

此查询用于返回其生日位于该时间间隔内的所有用户,而不考虑年份。

从答案中尝试(非常感谢@Mureinik)

SELECT *
FROM   user
WHERE  birthday BETWEEN TO_CHAR(NOW(), 'MM-DD') AND
TO_CHAR(NOW() + INTERVAL '30 days','MM-DD')

此答案的问题

  • 如果30天后是明年,这将行不通。
  • 如果是闰年,这个间隔是否不需要是31天?
gupuwyp2

gupuwyp21#

我根据当前的年份和用户的生日月份和日期生成了一个新的日期,然后看看它是否在未来30天内。

select *
from user
where date(date_part('year', current_date)||'-'||date_part('month', birthday)||'-'||date_part('day', birthday))
    between current_date and current_date + interval '30 days';

例如:

# select * from user;
 id | name  |  birthday
----+-------+------------
  1 | Tim   | 1994-06-27
  2 | Steve | 1982-06-23
  3 | Dave  | 1980-07-29
(3 rows)

# select *
from user
where date(date_part('year', current_date)||'-'||date_part('month', birthday)||'-'||date_part('day', birthday))
    between current_date and current_date + interval '30 days';
 id | name  |  birthday
----+-------+------------
  1 | Tim   | 1994-06-27
  2 | Steve | 1982-06-23
(2 rows)
6psbrbz9

6psbrbz92#

您可以将between的两个参数都转换为字符串并使用字典比较。由于格式是固定宽度的,因此应该可以:

SELECT *
FROM   user
WHERE  birthday BETWEEN TO_CHAR(NOW(), 'MM-DD') AND
                        TO_CHAR(NOW() + INTERVAL '30 days','MM-DD')
62lalag4

62lalag43#

这里,我在我的项目中实现了QueryDsl支持:

private static final DateTimeFormatter DTF_MM_dd = DateTimeFormatter.ofPattern("MM-dd");

protected BooleanExpression betweenLocalDatesIgnoringYear(DatePath<LocalDate> localDate, LocalDate from, LocalDate to) {
    if (from == null && to == null) {
        return Expressions.asBoolean(true).isTrue();
    }
    if (Objects.equals(from, to)) {
        return eqLocalDateIgnoringYear(localDate, from);
    }
    Set<String> MM_DDs = new HashSet<>();
    for (LocalDate date = (from != null ? from : LocalDate.now());
         date.isBefore(to != null ? to.plusDays(1) : from.plusMonths(1).plusDays(1));
         date = date.plusDays(1)) {

        MM_DDs.add(DTF_MM_dd.format(date));
    }
    if (MM_DDs.contains("02-28")) {
        MM_DDs.add("02-29");
    }
    if (MM_DDs.isEmpty()) {
        return Expressions.asBoolean(true).isTrue();
    }
    return localDateIgnoringYearIn(localDate, MM_DDs.stream().toArray(String[]::new));
}

protected BooleanExpression eqLocalDateIgnoringYear(DatePath<LocalDate> pathLocalDate, LocalDate localDate) {
    if (localDate == null) {
        return Expressions.asBoolean(true).isTrue();
    }
    return localDateIgnoringYearIn(pathLocalDate, DTF_MM_dd.format(localDate));
}

private BooleanExpression localDateIgnoringYearIn(DatePath<LocalDate> pathLocalDate, String... values) {
    return Expressions.stringTemplate("FUNCTION('to_char', {0},'MM-DD')", pathLocalDate).in(values);
}
r8xiu3jd

r8xiu3jd4#

不是100%相同,但是如果你只需要计算到下一个周年纪念日的天数,并且你可以忽略闰年,你可以使用年份的日期(DOY)和模函数来做一些数学运算。例如

select (EXTRACT(DOY FROM birthday) - EXTRACT(DOY FROM NOW()) + 365)::integer % 365 from user;

这是通过将它们之间的差加365而使其为正数和未来值,然后删除任何多余的内容,以使用模来获得余数。

相关问题