ghickman
ghickman

Reputation: 6043

How to calculate next birthday given a date of birth?

Given this schema in a Postgres database:

CREATE TABLE person (
    id serial PRIMARY KEY,
    name text,
    birth_date date,
);

How would I query the table to get the date of each person's next birthday after today?

For example if Bob's birth_date is 2000-06-01 then his next birthday would be 2016-06-01.

Note: I'm not looking for the birth_date + a pre-defined interval but rather the next anniversary of a person's birth.

I've written the equivalent in Python:

def next_birthday(self):
    today = datetime.date.today()
    next_birthday = self.birth_date.replace(year=today.year)
    if next_birthday < today:
        next_birthday = next_birthday.replace(year=today.year + 1)
    return next_birthday

However I'd like to see if Postgres can do this in a more performant way.

Upvotes: 8

Views: 2727

Answers (3)

user330315
user330315

Reputation:

select birth_date,
       cast(birth_date + ((extract(year from age(birth_date)) + 1) * interval '1' year) as date) as next_birthday
from person
where name = 'Bob'

The expression (extract(year from age(birth_date)) + 1) * interval '1' year calculates the age at the next birthday in (complete) years. When adding that to the date of birth, this gives the next birthday.

The cast is necessary to get a real date back, because date + interval returns a timestamp (including a time).

If you remove the where condition, you'll get all "next" birthdays.

You can also get a list of the upcoming birthdays in e.g. the next 30 days using something like this:

select next_birthday,
       next_birthday - current_date as days_until_next
from (
  select birth_date,
         cast(birth_date + ((extract(year from age(birth_date)) + 1) * interval '1' year) as date) as next_birthday
  from person
) as upcoming
where upcoming.next_birthday <= current_date + 30
order by next_birthday;

Upvotes: 10

David Aman
David Aman

Reputation: 291

SELECT
    birth_date
    +
    cast(
        date_part('year', current_date)
        -
        date_part('year', birth_date)
        +
        CASE
            WHEN
                date_part('month', birth_date) <
                        date_part('month', current_date)
                OR (
                    date_part('month', birth_date) =
                            date_part('month', current_date)
                    AND
                    date_part('day', birth_date) <
                            date_part('day', current_date)
                )
            THEN 1
            ELSE 0
        END || ' year' as interval)
FROM person;

Upvotes: 0

somesingsomsing
somesingsomsing

Reputation: 3350

SELECT date birth_date + interval '1 year' as next_birthday from person;

Upvotes: -1

Related Questions