Postgres:是从现在到每个生日间隔的日期
Postgres: Is Date between now and interval for EVERY birthday
我希望能够 return 生日从现在到指定时间间隔的用户。
用户模型
- 名称(字符串)
- 生日(日期)
我的时间间隔 = 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;
Returns
空的。 Postgres 假设省略年份我实际上是指第 1 年。
我想要的
此查询 return 所有生日在该区间内的用户,与年份无关。
尝试回答(非常感谢@Mureinik)
SELECT *
FROM user
WHERE birthday BETWEEN TO_CHAR(NOW(), 'MM-DD') AND
TO_CHAR(NOW() + INTERVAL '30 days','MM-DD')
这个答案有问题
- 如果从现在起 30 天是明年,这将不起作用。
- 如果年份是闰年,这个间隔不需要31天吗?
您可以将 between
的参数都转换为字符串并使用字典序比较。由于格式是固定宽度的,这应该没问题:
SELECT *
FROM user
WHERE birthday BETWEEN TO_CHAR(NOW(), 'MM-DD') AND
TO_CHAR(NOW() + INTERVAL '30 days','MM-DD')
我根据当前年份和用户的生日月份和日期生成了一个新日期,然后查看它是否在接下来的 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)
在这里,我在我的项目中实现了 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);
}
我希望能够 return 生日从现在到指定时间间隔的用户。
用户模型
- 名称(字符串)
- 生日(日期)
我的时间间隔 = 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;
Returns
空的。 Postgres 假设省略年份我实际上是指第 1 年。
我想要的
此查询 return 所有生日在该区间内的用户,与年份无关。
尝试回答(非常感谢@Mureinik)
SELECT *
FROM user
WHERE birthday BETWEEN TO_CHAR(NOW(), 'MM-DD') AND
TO_CHAR(NOW() + INTERVAL '30 days','MM-DD')
这个答案有问题
- 如果从现在起 30 天是明年,这将不起作用。
- 如果年份是闰年,这个间隔不需要31天吗?
您可以将 between
的参数都转换为字符串并使用字典序比较。由于格式是固定宽度的,这应该没问题:
SELECT *
FROM user
WHERE birthday BETWEEN TO_CHAR(NOW(), 'MM-DD') AND
TO_CHAR(NOW() + INTERVAL '30 days','MM-DD')
我根据当前年份和用户的生日月份和日期生成了一个新日期,然后查看它是否在接下来的 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)
在这里,我在我的项目中实现了 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);
}