Related
I have a table listing people along with their date of birth (currently a nvarchar(25))
How can I convert that to a date, and then calculate their age in years?
My data looks as follows
ID Name DOB
1 John 1992-01-09 00:00:00
2 Sally 1959-05-20 00:00:00
I would like to see:
ID Name AGE DOB
1 John 17 1992-01-09 00:00:00
2 Sally 50 1959-05-20 00:00:00
There are issues with leap year/days and the following method, see the update below:
try this:
DECLARE #dob datetime
SET #dob='1992-01-09 00:00:00'
SELECT DATEDIFF(hour,#dob,GETDATE())/8766.0 AS AgeYearsDecimal
,CONVERT(int,ROUND(DATEDIFF(hour,#dob,GETDATE())/8766.0,0)) AS AgeYearsIntRound
,DATEDIFF(hour,#dob,GETDATE())/8766 AS AgeYearsIntTrunc
OUTPUT:
AgeYearsDecimal AgeYearsIntRound AgeYearsIntTrunc
--------------------------------------- ---------------- ----------------
17.767054 18 17
(1 row(s) affected)
UPDATE here are some more accurate methods:
BEST METHOD FOR YEARS IN INT
DECLARE #Now datetime, #Dob datetime
SELECT #Now='1990-05-05', #Dob='1980-05-05' --results in 10
--SELECT #Now='1990-05-04', #Dob='1980-05-05' --results in 9
--SELECT #Now='1989-05-06', #Dob='1980-05-05' --results in 9
--SELECT #Now='1990-05-06', #Dob='1980-05-05' --results in 10
--SELECT #Now='1990-12-06', #Dob='1980-05-05' --results in 10
--SELECT #Now='1991-05-04', #Dob='1980-05-05' --results in 10
SELECT
(CONVERT(int,CONVERT(char(8),#Now,112))-CONVERT(char(8),#Dob,112))/10000 AS AgeIntYears
you can change the above 10000 to 10000.0 and get decimals, but it will not be as accurate as the method below.
BEST METHOD FOR YEARS IN DECIMAL
DECLARE #Now datetime, #Dob datetime
SELECT #Now='1990-05-05', #Dob='1980-05-05' --results in 10.000000000000
--SELECT #Now='1990-05-04', #Dob='1980-05-05' --results in 9.997260273973
--SELECT #Now='1989-05-06', #Dob='1980-05-05' --results in 9.002739726027
--SELECT #Now='1990-05-06', #Dob='1980-05-05' --results in 10.002739726027
--SELECT #Now='1990-12-06', #Dob='1980-05-05' --results in 10.589041095890
--SELECT #Now='1991-05-04', #Dob='1980-05-05' --results in 10.997260273973
SELECT 1.0* DateDiff(yy,#Dob,#Now)
+CASE
WHEN #Now >= DATEFROMPARTS(DATEPART(yyyy,#Now),DATEPART(m,#Dob),DATEPART(d,#Dob)) THEN --birthday has happened for the #now year, so add some portion onto the year difference
( 1.0 --force automatic conversions from int to decimal
* DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,#Now),DATEPART(m,#Dob),DATEPART(d,#Dob)),#Now) --number of days difference between the #Now year birthday and the #Now day
/ DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,#Now),1,1),DATEFROMPARTS(DATEPART(yyyy,#Now)+1,1,1)) --number of days in the #Now year
)
ELSE --birthday has not been reached for the last year, so remove some portion of the year difference
-1 --remove this fractional difference onto the age
* ( -1.0 --force automatic conversions from int to decimal
* DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,#Now),DATEPART(m,#Dob),DATEPART(d,#Dob)),#Now) --number of days difference between the #Now year birthday and the #Now day
/ DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,#Now),1,1),DATEFROMPARTS(DATEPART(yyyy,#Now)+1,1,1)) --number of days in the #Now year
)
END AS AgeYearsDecimal
Gotta throw this one out there. If you convert the date using the 112 style (yyyymmdd) to a number you can use a calculation like this...
(yyyyMMdd - yyyyMMdd) / 10000 = difference in full years
declare #as_of datetime, #bday datetime;
select #as_of = '2009/10/15', #bday = '1980/4/20'
select
Convert(Char(8),#as_of,112),
Convert(Char(8),#bday,112),
0 + Convert(Char(8),#as_of,112) - Convert(Char(8),#bday,112),
(0 + Convert(Char(8),#as_of,112) - Convert(Char(8),#bday,112)) / 10000
output
20091015 19800420 290595 29
I have used this query in our production code for nearly 10 years:
SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age
You need to consider the way the datediff command rounds.
SELECT CASE WHEN dateadd(year, datediff (year, DOB, getdate()), DOB) > getdate()
THEN datediff(year, DOB, getdate()) - 1
ELSE datediff(year, DOB, getdate())
END as Age
FROM <table>
Which I adapted from here.
Note that it will consider 28th February as the birthday of a leapling for non-leap years e.g. a person born on 29 Feb 2020 will be considered 1 year old on 28 Feb 2021 instead of 01 Mar 2021.
So many of the above solutions are wrong DateDiff(yy,#Dob, #PassedDate) will not consider the month and day of both dates. Also taking the dart parts and comparing only works if they're properly ordered.
THE FOLLOWING CODE WORKS AND IS VERY SIMPLE:
create function [dbo].[AgeAtDate](
#DOB datetime,
#PassedDate datetime
)
returns int
with SCHEMABINDING
as
begin
declare #iMonthDayDob int
declare #iMonthDayPassedDate int
select #iMonthDayDob = CAST(datepart (mm,#DOB) * 100 + datepart (dd,#DOB) AS int)
select #iMonthDayPassedDate = CAST(datepart (mm,#PassedDate) * 100 + datepart (dd,#PassedDate) AS int)
return DateDiff(yy,#DOB, #PassedDate)
- CASE WHEN #iMonthDayDob <= #iMonthDayPassedDate
THEN 0
ELSE 1
END
End
EDIT: THIS ANSWER IS INCORRECT. I leave it in here as a warning to anyone tempted to use dayofyear, with a further edit at the end.
If, like me, you do not want to divide by fractional days or risk rounding/leap year errors, I applaud #Bacon Bits comment in a post above https://stackoverflow.com/a/1572257/489865 where he says:
If we're talking about human ages, you should calculate it the way
humans calculate age. It has nothing to do with how fast the earth
moves and everything to do with the calendar. Every time the same
month and day elapses as the date of birth, you increment age by 1.
This means the following is the most accurate because it mirrors what
humans mean when they say "age".
He then offers:
DATEDIFF(yy, #date, GETDATE()) -
CASE WHEN (MONTH(#date) > MONTH(GETDATE())) OR (MONTH(#date) = MONTH(GETDATE()) AND DAY(#date) > DAY(GETDATE()))
THEN 1 ELSE 0 END
There are several suggestions here involving comparing the month & day (and some get it wrong, failing to allow for the OR as correctly here!). But nobody has offered dayofyear, which seems so simple and much shorter. I offer:
DATEDIFF(year, #date, GETDATE()) -
CASE WHEN DATEPART(dayofyear, #date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END
[Note: Nowhere in SQL BOL/MSDN is what DATEPART(dayofyear, ...) returns actually documented! I understand it to be a number in the range 1--366; most importantly, it does not change by locale as per DATEPART(weekday, ...) & SET DATEFIRST.]
EDIT: Why dayofyear goes wrong: As user #AeroX has commented, if the birth/start date is after February in a non leap year, the age is incremented one day early when the current/end date is a leap year, e.g. '2015-05-26', '2016-05-25' gives an age of 1 when it should still be 0. Comparing the dayofyear in different years is clearly dangerous. So using MONTH() and DAY() is necessary after all.
I believe this is similar to other ones posted here.... but this solution worked for the leap year examples 02/29/1976 to 03/01/2011 and also worked for the case for the first year.. like 07/04/2011 to 07/03/2012 which the last one posted about leap year solution did not work for that first year use case.
SELECT FLOOR(DATEDIFF(DAY, #date1 , #date2) / 365.25)
Found here.
Since there isn't one simple answer that always gives the correct age, here's what I came up with.
SELECT DATEDIFF(YY, DateOfBirth, GETDATE()) -
CASE WHEN RIGHT(CONVERT(VARCHAR(6), GETDATE(), 12), 4) >=
RIGHT(CONVERT(VARCHAR(6), DateOfBirth, 12), 4)
THEN 0 ELSE 1 END AS AGE
This gets the year difference between the birth date and the current date. Then it subtracts a year if the birthdate hasn't passed yet.
Accurate all the time - regardless of leap years or how close to the birthdate.
Best of all - no function.
I've done a lot of thinking and searching about this and I have 3 solutions that
calculate age correctly
are short (mostly)
are (mostly) very understandable.
Here are testing values:
DECLARE #NOW DATETIME = '2013-07-04 23:59:59'
DECLARE #DOB DATETIME = '1986-07-05'
Solution 1: I found this approach in one js library. It's my favourite.
DATEDIFF(YY, #DOB, #NOW) -
CASE WHEN DATEADD(YY, DATEDIFF(YY, #DOB, #NOW), #DOB) > #NOW THEN 1 ELSE 0 END
It's actually adding difference in years to DOB and if it is bigger than current date then subtracts one year. Simple right? The only thing is that difference in years is duplicated here.
But if you don't need to use it inline you can write it like this:
DECLARE #AGE INT = DATEDIFF(YY, #DOB, #NOW)
IF DATEADD(YY, #AGE, #DOB) > #NOW
SET #AGE = #AGE - 1
Solution 2: This one I originally copied from #bacon-bits. It's the easiest to understand but a bit long.
DATEDIFF(YY, #DOB, #NOW) -
CASE WHEN MONTH(#DOB) > MONTH(#NOW)
OR MONTH(#DOB) = MONTH(#NOW) AND DAY(#DOB) > DAY(#NOW)
THEN 1 ELSE 0 END
It's basically calculating age as we humans do.
Solution 3: My friend refactored it into this:
DATEDIFF(YY, #DOB, #NOW) -
CEILING(0.5 * SIGN((MONTH(#DOB) - MONTH(#NOW)) * 50 + DAY(#DOB) - DAY(#NOW)))
This one is the shortest but it's most difficult to understand. 50 is just a weight so the day difference is only important when months are the same. SIGN function is for transforming whatever value it gets to -1, 0 or 1. CEILING(0.5 * is the same as Math.max(0, value) but there is no such thing in SQL.
What about:
DECLARE #DOB datetime
SET #DOB='19851125'
SELECT Datepart(yy,convert(date,GETDATE())-#DOB)-1900
Wouldn't that avoid all those rounding, truncating and ofsetting issues?
Just check whether the below answer is feasible.
DECLARE #BirthDate DATE = '09/06/1979'
SELECT
(
YEAR(GETDATE()) - YEAR(#BirthDate) -
CASE WHEN (MONTH(GETDATE()) * 100) + DATEPART(dd, GETDATE()) >
(MONTH(#BirthDate) * 100) + DATEPART(dd, #BirthDate)
THEN 1
ELSE 0
END
)
select floor((datediff(day,0,#today) - datediff(day,0,#birthdate)) / 365.2425) as age
There are a lot of 365.25 answers here. Remember how leap years are defined:
Every four years
except every 100 years
except every 400 years
There are many answers to this question, but I think this one is close to the truth.
The datediff(year,…,…) function, as we all know, only counts the boundaries crossed by the date part, in this case the year. As a result it ignores the rest of the year.
This will only give the age in completed years if the year were to start on the birthday. It probably doesn’t, but we can fake it by adjusting the asking date back by the same amount.
In pseudopseudo code, it’s something like this:
adjusted_today = today - month(dob) + 1 - day(dob) + 1
age = year(adjusted_today - dob)
The + 1 is to allow for the fact that the month and day numbers start from 1 and not 0.
The reason we subtract the month and the day separately rather than the day of the year is because February has the annoying tendency to change its length.
The calculation in SQL is:
datediff(year,dob,dateadd(month,-month(dob)+1,dateadd(day,-day(dob)+1,today)))
where dob and today are presumed to be the date of birth and the asking date.
You can test this as follows:
WITH dates AS (
SELECT
cast('2022-03-01' as date) AS today,
cast('1943-02-25' as date) AS dob
)
select
datediff(year,dob,dateadd(month,-month(dob)+1,dateadd(day,-day(dob)+1,today))) AS age
from dates;
which gives you George Harrison’s age in completed years.
This is much cleaner than fiddling about with quarter days which will generally give you misleading values on the edges.
If you have the luxury of creating a scalar function, you can use something like this:
DROP FUNCTION IF EXISTS age;
GO
CREATE FUNCTION age(#dob date, #today date) RETURNS INT AS
BEGIN
SET #today = dateadd(month,-month(#dob)+1,#today);
SET #today = dateadd(day,-day(#dob)+1,#today);
RETURN datediff(year,#dob,#today);
END;
GO
Remember, you need to call dbo.age() because, well, Microsoft.
DECLARE #DOB datetime
set #DOB ='11/25/1985'
select floor(
( cast(convert(varchar(8),getdate(),112) as int)-
cast(convert(varchar(8),#DOB,112) as int) ) / 10000
)
source: http://beginsql.wordpress.com/2012/04/26/how-to-calculate-age-in-sql-server/
Try This
DECLARE #date datetime, #tmpdate datetime, #years int, #months int, #days int
SELECT #date = '08/16/84'
SELECT #tmpdate = #date
SELECT #years = DATEDIFF(yy, #tmpdate, GETDATE()) - CASE WHEN (MONTH(#date) > MONTH(GETDATE())) OR (MONTH(#date) = MONTH(GETDATE()) AND DAY(#date) > DAY(GETDATE())) THEN 1 ELSE 0 END
SELECT #tmpdate = DATEADD(yy, #years, #tmpdate)
SELECT #months = DATEDIFF(m, #tmpdate, GETDATE()) - CASE WHEN DAY(#date) > DAY(GETDATE()) THEN 1 ELSE 0 END
SELECT #tmpdate = DATEADD(m, #months, #tmpdate)
SELECT #days = DATEDIFF(d, #tmpdate, GETDATE())
SELECT Convert(Varchar(Max),#years)+' Years '+ Convert(Varchar(max),#months) + ' Months '+Convert(Varchar(Max), #days)+'days'
After trying MANY methods, this works 100% of the time using the modern MS SQL FORMAT function instead of convert to style 112. Either would work but this is the least code.
Can anyone find a date combination which does not work? I don't think there is one :)
--Set parameters, or choose from table.column instead:
DECLARE #DOB DATE = '2000/02/29' -- If #DOB is a leap day...
,#ToDate DATE = '2018/03/01' --...there birthday in this calculation will be
--0+ part tells SQL to calc the char(8) as numbers:
SELECT [Age] = (0+ FORMAT(#ToDate,'yyyyMMdd') - FORMAT(#DOB,'yyyyMMdd') ) /10000
CASE WHEN datepart(MM, getdate()) < datepart(MM, BIRTHDATE) THEN ((datepart(YYYY, getdate()) - datepart(YYYY, BIRTH_DATE)) -1 )
ELSE
CASE WHEN datepart(MM, getdate()) = datepart(MM, BIRTHDATE)
THEN
CASE WHEN datepart(DD, getdate()) < datepart(DD, BIRTHDATE) THEN ((datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE)) -1 )
ELSE (datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE))
END
ELSE (datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE)) END
END
SELECT ID,
Name,
DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE,
DOB
FROM MyTable
How about this:
SET #Age = CAST(DATEDIFF(Year, #DOB, #Stamp) as int)
IF (CAST(DATEDIFF(DAY, DATEADD(Year, #Age, #DOB), #Stamp) as int) < 0)
SET #Age = #Age - 1
Try this solution:
declare #BirthDate datetime
declare #ToDate datetime
set #BirthDate = '1/3/1990'
set #ToDate = '1/2/2008'
select #BirthDate [Date of Birth], #ToDate [ToDate],(case when (DatePart(mm,#ToDate) < Datepart(mm,#BirthDate))
OR (DatePart(m,#ToDate) = Datepart(m,#BirthDate) AND DatePart(dd,#ToDate) < Datepart(dd,#BirthDate))
then (Datepart(yy, #ToDate) - Datepart(yy, #BirthDate) - 1)
else (Datepart(yy, #ToDate) - Datepart(yy, #BirthDate))end) Age
This will correctly handle the issues with the birthday and rounding:
DECLARE #dob datetime
SET #dob='1992-01-09 00:00:00'
SELECT DATEDIFF(YEAR, '0:0', getdate()-#dob)
Ed Harper's solution is the simplest I have found which never returns the wrong answer when the month and day of the two dates are 1 or less days apart. I made a slight modification to handle negative ages.
DECLARE #D1 AS DATETIME, #D2 AS DATETIME
SET #D2 = '2012-03-01 10:00:02'
SET #D1 = '2013-03-01 10:00:01'
SELECT
DATEDIFF(YEAR, #D1,#D2)
+
CASE
WHEN #D1<#D2 AND DATEADD(YEAR, DATEDIFF(YEAR,#D1, #D2), #D1) > #D2
THEN - 1
WHEN #D1>#D2 AND DATEADD(YEAR, DATEDIFF(YEAR,#D1, #D2), #D1) < #D2
THEN 1
ELSE 0
END AS AGE
The answer marked as correct is nearer to accuracy but, it fails in following scenario - where Year of birth is Leap year and day are after February month
declare #ReportStartDate datetime = CONVERT(datetime, '1/1/2014'),
#DateofBirth datetime = CONVERT(datetime, '2/29/1948')
FLOOR(DATEDIFF(HOUR,#DateofBirth,#ReportStartDate )/8766)
OR
FLOOR(DATEDIFF(HOUR,#DateofBirth,#ReportStartDate )/8765.82) -- Divisor is more accurate than 8766
-- Following solution is giving me more accurate results.
FLOOR(DATEDIFF(YEAR,#DateofBirth,#ReportStartDate) - (CASE WHEN DATEADD(YY,DATEDIFF(YEAR,#DateofBirth,#ReportStartDate),#DateofBirth) > #ReportStartDate THEN 1 ELSE 0 END ))
It worked in almost all scenarios, considering leap year, date as 29 feb, etc.
Please correct me if this formula have any loophole.
Declare #dob datetime
Declare #today datetime
Set #dob = '05/20/2000'
set #today = getdate()
select CASE
WHEN dateadd(year, datediff (year, #dob, #today), #dob) > #today
THEN datediff (year, #dob, #today) - 1
ELSE datediff (year, #dob, #today)
END as Age
Here is how i calculate age given a birth date and current date.
select case
when cast(getdate() as date) = cast(dateadd(year, (datediff(year, '1996-09-09', getdate())), '1996-09-09') as date)
then dateDiff(yyyy,'1996-09-09',dateadd(year, 0, getdate()))
else dateDiff(yyyy,'1996-09-09',dateadd(year, -1, getdate()))
end as MemberAge
go
CREATE function dbo.AgeAtDate(
#DOB datetime,
#CompareDate datetime
)
returns INT
as
begin
return CASE WHEN #DOB is null
THEN
null
ELSE
DateDiff(yy,#DOB, #CompareDate)
- CASE WHEN datepart(mm,#CompareDate) > datepart(mm,#DOB) OR (datepart(mm,#CompareDate) = datepart(mm,#DOB) AND datepart(dd,#CompareDate) >= datepart(dd,#DOB))
THEN 0
ELSE 1
END
END
End
GO
DECLARE #FromDate DATETIME = '1992-01-2623:59:59.000',
#ToDate DATETIME = '2016-08-10 00:00:00.000',
#Years INT, #Months INT, #Days INT, #tmpFromDate DATETIME
SET #Years = DATEDIFF(YEAR, #FromDate, #ToDate)
- (CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, #FromDate, #ToDate),
#FromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(YEAR, #Years , #FromDate)
SET #Months = DATEDIFF(MONTH, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(MONTH,DATEDIFF(MONTH, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SET #tmpFromDate = DATEADD(MONTH, #Months , #tmpFromDate)
SET #Days = DATEDIFF(DAY, #tmpFromDate, #ToDate)
- (CASE WHEN DATEADD(DAY, DATEDIFF(DAY, #tmpFromDate, #ToDate),
#tmpFromDate) > #ToDate THEN 1 ELSE 0 END)
SELECT #FromDate FromDate, #ToDate ToDate,
#Years Years, #Months Months, #Days Days
What about a solution with only date functions, not math, not worries about leap year
CREATE FUNCTION dbo.getAge(#dt datetime)
RETURNS int
AS
BEGIN
RETURN
DATEDIFF(yy, #dt, getdate())
- CASE
WHEN
MONTH(#dt) > MONTH(GETDATE()) OR
(MONTH(#dt) = MONTH(GETDATE()) AND DAY(#dt) > DAY(GETDATE()))
THEN 1
ELSE 0
END
END
declare #birthday as datetime
set #birthday = '2000-01-01'
declare #today as datetime
set #today = GetDate()
select
case when ( substring(convert(varchar, #today, 112), 5,4) >= substring(convert(varchar, #birthday, 112), 5,4) ) then
(datepart(year,#today) - datepart(year,#birthday))
else
(datepart(year,#today) - datepart(year,#birthday)) - 1
end
The following script checks the difference in years between now and the given date of birth; the second part checks whether the birthday is already past in the current year; if not, it subtracts it:
SELECT year(NOW()) - year(date_of_birth) - (CONCAT(year(NOW()), '-', month(date_of_birth), '-', day(date_of_birth)) > NOW()) AS Age
FROM tableName;
I want to get the 1st of the month following the date the person turns 70. How to achive this in SQL
i am calculating age using the formula
DECLARE #Date_of_birth DATETIME = '1915-10-02 00:00:00.000'
DECLARE #AGE INT
SELECT #AGE = FLOOR((CAST (GETDATE() AS INTEGER) - CAST(#Date_of_birth AS INTEGER)) / 365.25)
IF(#AGE > 70)
How to find the first of the month following the date ??
IF (#AGE >80)
You can use datediff to calculate their age, and then date add to find their 70th birthday. To find the first of the month afterwards, you can use the Month and Year functions.
create table #people (name varchar(30), birthdate date)
insert into #people
values ('Bob', '07/08/1976'), ('Tasha','05/30/1996'),('April','04/01/1971')
--This will give you everyone's age
select DATEDIFF(YY,birthdate,GETDATE()) as age
from #people
--This will give you the first month following the date that they turn 70
select Name, DATEADD(yy,70,birthdate) as [70thBday], convert(varchar,month(dateadd(m,1,DATEADD(yy,70,birthdate)))) + '/01/' + convert(varchar,YEAR(dateadd(m,1,DATEADD(yy,70,birthdate))))
from #people
declare #dob datetime = '1954-06-08'
declare #age int = 70
select DATEADD(m, DATEDIFF(m, -1, DATEADD(yy, #age, #dob)), 0)
you can use dateadd function like this
select dateadd(d,1 - datepart(d,dateadd(m,1,dateadd(yy,70",,#Date_of_birth)),dateadd(m,1,dateadd(yy,70",,#Date_of_birth)))
You can break down this query like this
declare #BD_70 date = dateadd(yy,70",,#Date_of_birth)
declare #Nxt_Month_70 = dateadd(m,1,#BD_70 date)
declare #First_Of_Month_70 = dateadd(d,1 - datepart(d,#Nxt_Month_70),#Nxt_Month_70)
Basically, you add 70 year, find next month and replace the day to the first of the month.
Here is how you would calculate age base on current date.
select case
when cast(getdate() as date) = cast(dateadd(year, (datediff(year, '1996-09-09', getdate())), '1996-09-09') as date)
then dateDiff(yyyy,'1996-09-09',dateadd(year, 0, getdate()))
else dateDiff(yyyy,'1996-09-09',dateadd(year, -1, getdate()))
end as MemberAge
go
This is how I calculate the age:
SELECT DATEDIFF(yy, [DateOfBirth], GETDATE()) + (CASE WHEN DATEPART(MONTH, GETDATE()) - DATEPART(MONTH, [DateOfBirth]) < 0 THEN -1 ELSE 0 END ) AS Age FROM [User]
You can try TIMESTAMPDIFF function.(Support MySQL, Apache Doris)
Example:
select TIMESTAMPDIFF(year,'1996-09-09',now()) as age;
Using the below as a basis how would i work out a person age in months i not to sure how to go about changing this so the months is cacualated instead of years
IF cast(datepart(m, GETDATE()) as int) > cast(datepart(m,#in_DOB) as int)
SET #age = cast(datediff(yyyy,#in_DOB,GETDATE()) as int)
else
IF cast(datepart(m,GETDATE()) as int) = cast(datepart(m,#in_DOB) as int)
IF datepart(d,GETDATE()) >= datepart(d,#in_DOB)
SET #age = cast(datediff(yyyy,#in_DOB,GETDATE()) as int)
ELSE
SET #age = cast(datediff(yyyy,#in_DOB,GETDATE()) as int) -1
ELSE
SET #age = cast(datediff(yyyy,#in_DOB,GETDATE()) as int) - 1
RETURN #age
Its my birthday today :) and I am SELECT DATEDIFF(MONTH, '13 Nov 1963', GetDate()) months old. Whoops, too many beers already.
Update
DECLARE #birthdate datetime
DECLARE #months INT
SELECT #birthdate = '13 Nov 1963'
SELECT #months = DATEDIFF(MONTH, #birthdate, GETDATE()) - CASE WHEN DAY(#birthdate) > DAY( GETDATE()) THEN 1 ELSE 0 END
SELECT #months
It's a bit of a mouthful, but we get the crude estimate just using DATEDIFF1 - and then we adjust it if it's wrong:
select #age = DATEDIFF(month,#in_DOB,CURRENT_TIMESTAMP) -
CASE WHEN DATEADD(month,DATEDIFF(month,#in_DOB,CURRENT_TIMESTAMP),#in_DOB)
> CURRENT_TIMESTAMP
THEN 1 ELSE 0 END
1 It's crude because DATEDIFF tells you the number of transitions that have occurred between two dates, rather than what some people might intuit. This means that the difference in months between 30th September and 1st October is 1, per this function.
So it can end up reporting a value 1 higher than the intuitive "difference in months" between two dates.
You need to always save UTC date in db. will save you a lot of trouble.
select DATEDIFF(second,#in_DOB,GETUTCDATE())/(30.5*24*60*60.0) --days 30.5 avg of 30 and 31
I need to determine the number of days in a month for a given date in SQL Server.
Is there a built-in function? If not, what should I use as the user-defined function?
In SQL Server 2012 you can use EOMONTH (Transact-SQL) to get the last day of the month and then you can use DAY (Transact-SQL) to get the number of days in the month.
DECLARE #ADate DATETIME
SET #ADate = GETDATE()
SELECT DAY(EOMONTH(#ADate)) AS DaysInMonth
You can use the following with the first day of the specified month:
datediff(day, #date, dateadd(month, 1, #date))
To make it work for every date:
datediff(day, dateadd(day, 1-day(#date), #date),
dateadd(month, 1, dateadd(day, 1-day(#date), #date)))
Most elegant solution: works for any #DATE
DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,#DATE),0)))
Throw it in a function or just use it inline. This answers the original question without all the extra junk in the other answers.
examples for dates from other answers:
SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'1/31/2009'),0))) Returns 31
SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'2404-feb-15'),0))) Returns 29
SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'2011-12-22'),0))) Returns 31
--Last Day of Previous Month
SELECT DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0)))
--Last Day of Current Month
SELECT DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0)))
--Last Day of Next Month
SELECT DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0)))
Personally though, I would make a UDF for it if there is not a built in function...
I would suggest:
SELECT DAY(EOMONTH(GETDATE()))
This code gets you the number of days in current month:
SELECT datediff(dd,getdate(),dateadd(mm,1,getdate())) as datas
Change getdate() to the date you need to count days for.
--- sql server below 2012---
select day( dateadd(day,-1,dateadd(month, 1, convert(date,'2019-03-01'))))
-- this for sql server 2012--
select day(EOMONTH(getdate()))
Solution 1: Find the number of days in whatever month we're currently in
DECLARE #dt datetime
SET #dt = getdate()
SELECT #dt AS [DateTime],
DAY(DATEADD(mm, DATEDIFF(mm, -1, #dt), -1)) AS [Days in Month]
Solution 2: Find the number of days in a given month-year combo
DECLARE #y int, #m int
SET #y = 2012
SET #m = 2
SELECT #y AS [Year],
#m AS [Month],
DATEDIFF(DAY,
DATEADD(DAY, 0, DATEADD(m, ((#y - 1900) * 12) + #m - 1, 0)),
DATEADD(DAY, 0, DATEADD(m, ((#y - 1900) * 12) + #m, 0))
) AS [Days in Month]
You do need to add a function, but it's a simple one. I use this:
CREATE FUNCTION [dbo].[ufn_GetDaysInMonth] ( #pDate DATETIME )
RETURNS INT
AS
BEGIN
SET #pDate = CONVERT(VARCHAR(10), #pDate, 101)
SET #pDate = #pDate - DAY(#pDate) + 1
RETURN DATEDIFF(DD, #pDate, DATEADD(MM, 1, #pDate))
END
GO
SELECT Datediff(day,
(Convert(DateTime,Convert(varchar(2),Month(getdate()))+'/01/'+Convert(varchar(4),Year(getdate())))),
(Convert(DateTime,Convert(varchar(2),Month(getdate())+1)+'/01/'+Convert(varchar(4),Year(getdate()))))) as [No.of Days in a Month]
select datediff(day,
dateadd(day, 0, dateadd(month, ((2013 - 1900) * 12) + 3 - 1, 0)),
dateadd(day, 0, dateadd(month, ((2013 - 1900) * 12) + 3, 0))
)
Nice Simple and does not require creating any functions Work Fine
You need to create a function, but it is for your own convenience. It works perfect and I never encountered any faulty computations using this function.
CREATE FUNCTION [dbo].[get_days](#date datetime)
RETURNS int
AS
BEGIN
SET #date = DATEADD(MONTH, 1, #date)
DECLARE #result int = (select DAY(DATEADD(DAY, -DAY(#date), #date)))
RETURN #result
END
How it works: subtracting the date's day number from the date itself gives you the last day of previous month. So, you need to add one month to the given date, subtract the day number and get the day component of the result.
select add_months(trunc(sysdate,'MM'),1) - trunc(sysdate,'MM') from dual;
I upvoted Mehrdad, but this works as well. :)
CREATE function dbo.IsLeapYear
(
#TestYear int
)
RETURNS bit
AS
BEGIN
declare #Result bit
set #Result =
cast(
case when ((#TestYear % 4 = 0) and (#testYear % 100 != 0)) or (#TestYear % 400 = 0)
then 1
else 0
end
as bit )
return #Result
END
GO
CREATE FUNCTION dbo.GetDaysInMonth
(
#TestDT datetime
)
RETURNS INT
AS
BEGIN
DECLARE #Result int
DECLARE #MonthNo int
Set #MonthNo = datepart(m,#TestDT)
Set #Result =
case #MonthNo
when 1 then 31
when 2 then
case
when dbo.IsLeapYear(datepart(yyyy,#TestDT)) = 0
then 28
else 29
end
when 3 then 31
when 4 then 30
when 5 then 31
when 6 then 30
when 7 then 31
when 8 then 31
when 9 then 30
when 10 then 31
when 11 then 30
when 12 then 31
end
RETURN #Result
END
GO
To Test
declare #testDT datetime;
set #testDT = '2404-feb-15';
select dbo.GetDaysInMonth(#testDT)
here's another one...
Select Day(DateAdd(day, -Day(DateAdd(month, 1, getdate())),
DateAdd(month, 1, getdate())))
I know this question is old but I thought I would share what I'm using.
DECLARE #date date = '2011-12-22'
/* FindFirstDayOfMonth - Find the first date of any month */
-- Replace the day part with -01
DECLARE #firstDayOfMonth date = CAST( CAST(YEAR(#date) AS varchar(4)) + '-' +
CAST(MONTH(#date) AS varchar(2)) + '-01' AS date)
SELECT #firstDayOfMonth
and
DECLARE #date date = '2011-12-22'
/* FindLastDayOfMonth - Find what is the last day of a month - Leap year is handled by DATEADD */
-- Get the first day of next month and remove a day from it using DATEADD
DECLARE #lastDayOfMonth date = CAST( DATEADD(dd, -1, DATEADD(mm, 1, FindFirstDayOfMonth(#date))) AS date)
SELECT #lastDayOfMonth
Those could be combine to create a single function to retrieve the number of days in a month if needed.
SELECT DAY(SUBDATE(ADDDATE(CONCAT(YEAR(NOW()), '-', MONTH(NOW()), '-1'), INTERVAL 1 MONTH), INTERVAL 1 DAY))
Nice 'n' Simple and does not require creating any functions
Mehrdad Afshari reply is most accurate one, apart from usual this answer is based on formal mathematical approach given by Curtis McEnroe in his blog https://cmcenroe.me/2014/12/05/days-in-month-formula.html
DECLARE #date DATE= '2015-02-01'
DECLARE #monthNumber TINYINT
DECLARE #dayCount TINYINT
SET #monthNumber = DATEPART(MONTH,#date )
SET #dayCount = 28 + (#monthNumber + floor(#monthNumber/8)) % 2 + 2 % #monthNumber + 2 * floor(1/#monthNumber)
SELECT #dayCount + CASE WHEN #dayCount = 28 AND DATEPART(YEAR,#date)%4 =0 THEN 1 ELSE 0 END -- leap year adjustment
To get the no. of days in a month we can directly use Day() available in SQL.
Follow the link posted at the end of my answer for SQL Server 2005 / 2008.
The following example and the result are from SQL 2012
alter function dbo.[daysinm]
(
#dates nvarchar(12)
)
returns int
as
begin
Declare #dates2 nvarchar(12)
Declare #days int
begin
select #dates2 = (select DAY(EOMONTH(convert(datetime,#dates,103))))
set #days = convert(int,#dates2)
end
return #days
end
--select dbo.daysinm('08/12/2016')
Result in SQL Server SSMS
(no column name)
1 31
Process:
When EOMONTH is used, whichever the date format we use it is converted into DateTime format of SQL-server. Then the date output of EOMONTH() will be 2016-12-31 having 2016 as Year, 12 as Month and 31 as Days.
This output when passed into Day() it gives you the total days count in the month.
If we want to get the instant result for checking we can directly run the below code,
select DAY(EOMONTH(convert(datetime,'08/12/2016',103)))
or
select DAY(EOMONTH(convert(datetime,getdate(),103)))
for reference to work in SQL Server 2005/2008/2012, please follow the following external link ...
Find No. of Days in a Month in SQL
DECLARE #date DATETIME = GETDATE(); --or '12/1/2018' (month/day/year)
SELECT DAY(EOMONTH ( #date )) AS 'This Month';
SELECT DAY(EOMONTH ( #date, 1 )) AS 'Next Month';
result:
This Month
31
Next Month
30
DECLARE #m int
SET #m = 2
SELECT
#m AS [Month],
DATEDIFF(DAY,
DATEADD(DAY, 0, DATEADD(m, +#m -1, 0)),
DATEADD(DAY, 0, DATEADD(m,+ #m, 0))
) AS [Days in Month]
RETURN day(dateadd(month, 12 * #year + #month - 22800, -1))
select day(dateadd(month, 12 * year(date) + month(date) - 22800, -1))
A cleaner way of implementing this is using the datefromparts function to construct the first day of the month, and calculate the days from there.
CREATE FUNCTION [dbo].[fn_DaysInMonth]
(
#year INT,
#month INT
)
RETURNS INT
AS
BEGIN
IF #month < 1 OR #month > 12 RETURN NULL;
IF #year < 1753 OR #year > 9998 RETURN NULL;
DECLARE #firstDay DATE = datefromparts(#year, #month, 1);
DECLARE #lastDay DATE = dateadd(month, 1, #firstDay);
RETURN datediff(day, #firstDay, #lastDay);
END
GO
Similarily, you can calculate the days in a year:
CREATE FUNCTION [dbo].[fn_DaysInYear]
(
#year INT
)
RETURNS INT
AS
BEGIN
IF #year < 1753 OR #year > 9998 RETURN NULL;
DECLARE #firstDay DATE = datefromparts(#year, 1, 1);
DECLARE #lastDay DATE = dateadd(year, 1, #firstDay);
RETURN datediff(day, #firstDay, #lastDay);
END
GO
use SQL Server EOMONTH Function nested with day to get last day of month
select Day(EOMONTH('2020-02-1')) -- Leap Year returns 29
select Day(EOMONTH('2021-02-1')) -- returns 28
select Day(EOMONTH('2021-03-1')) -- returns 31
For any date
select DateDiff(Day,#date,DateAdd(month,1,#date))
select first_day=dateadd(dd,-1*datepart(dd,getdate())+1,getdate()),
last_day=dateadd(dd,-1*datepart(dd,dateadd(mm,1,getdate())),dateadd(mm,1,getdate())),
no_of_days = 1+datediff(dd,dateadd(dd,-1*datepart(dd,getdate())+1,getdate()),dateadd(dd,-1*datepart(dd,dateadd(mm,1,getdate())),dateadd(mm,1,getdate())))
replace any date with getdate to get the no of months in that particular date
DECLARE #Month INT=2,
#Year INT=1989
DECLARE #date DateTime=null
SET #date=CAST(CAST(#Year AS nvarchar) + '-' + CAST(#Month AS nvarchar) + '-' + '1' AS DATETIME);
DECLARE #noofDays TINYINT
DECLARE #CountForDate TINYINT
SET #noofDays = DATEPART(MONTH,#date )
SET #CountForDate = 28 + (#noofDays + floor(#noofDays/8)) % 2 + 2 % #noofDays + 2 * floor(1/#noofDays)
SET #noofDays= #CountForDate + CASE WHEN #CountForDate = 28 AND DATEPART(YEAR,#date)%4 =0 THEN 1 ELSE 0 END
PRINT #noofDays
DECLARE #date nvarchar(20)
SET #date ='2012-02-09 00:00:00'
SELECT DATEDIFF(day,cast(replace(cast(YEAR(#date) as char)+'-'+cast(MONTH(#date) as char)+'-01',' ','')+' 00:00:00' as datetime),dateadd(month,1,cast(replace(cast(YEAR(#date) as char)+'-'+cast(MONTH(#date) as char)+'-01',' ','')+' 00:00:00' as datetime)))
simple query in SQLServer2012 :
select day(('20-05-1951 22:00:00'))
i tested for many dates and it return always a correct result
I'm trying to write a stored procedure to select employees who have birthdays that are upcoming.
SELECT * FROM Employees WHERE Birthday > #Today AND Birthday < #Today + #NumDays
This will not work because the birth year is part of Birthday, so if my birthday was '09-18-1983' that will not fall between '09-18-2008' and '09-25-2008'.
Is there a way to ignore the year portion of date fields and just compare month/days?
This will be run every monday morning to alert managers of birthdays upcoming, so it possibly will span new years.
Here is the working solution that I ended up creating, thanks Kogus.
SELECT * FROM Employees
WHERE Cast(DATEDIFF(dd, birthdt, getDate()) / 365.25 as int)
- Cast(DATEDIFF(dd, birthdt, futureDate) / 365.25 as int)
<> 0
Note: I've edited this to fix what I believe was a significant bug. The currently posted version works for me.
This should work after you modify the field and table names to correspond to your database.
SELECT
BRTHDATE AS BIRTHDAY
,FLOOR(DATEDIFF(dd,EMP.BRTHDATE,GETDATE()) / 365.25) AS AGE_NOW
,FLOOR(DATEDIFF(dd,EMP.BRTHDATE,GETDATE()+7) / 365.25) AS AGE_ONE_WEEK_FROM_NOW
FROM
"Database name".dbo.EMPLOYEES EMP
WHERE 1 = (FLOOR(DATEDIFF(dd,EMP.BRTHDATE,GETDATE()+7) / 365.25))
-
(FLOOR(DATEDIFF(dd,EMP.BRTHDATE,GETDATE()) / 365.25))
Basically, it gets the # of days from their birthday to now, and divides that by 365 (to avoid rounding issues that come up when you convert directly to years).
Then it gets the # of days from their birthday to a week from now, and divides that by 365 to get their age a week from now.
If their birthday is within a week, then the difference between those two values will be 1. So it returns all of those records.
In case someone is still looking for a solution in MySQL (slightly different commands), here's the query:
SELECT
name,birthday,
FLOOR(DATEDIFF(DATE(NOW()),birthday) / 365.25) AS age_now,
FLOOR(DATEDIFF(DATE_ADD(DATE(NOW()),INTERVAL 30 DAY),birthday) / 365.25) AS age_future
FROM user
WHERE 1 = (FLOOR(DATEDIFF(DATE_ADD(DATE(NOW()),INTERVAL 30 DAY),birthday) / 365.25)) - (FLOOR(DATEDIFF(DATE(NOW()),birthday) / 365.25))
ORDER BY MONTH(birthday),DAY(birthday)
Best use of datediff and dateadd. No rounding, no approximates, no 29th of february bug, nothing but date functions
ageOfThePerson = DATEDIFF(yyyy,dateOfBirth, GETDATE())
dateOfNextBirthday = DATEADD(yyyy,ageOfThePerson + 1, dateOfBirth)
daysBeforeBirthday = DATEDIFF(d,GETDATE(), dateofNextBirthday)
Thanks to #Gustavo Cardoso, new definition for the age of the person
ageOfThePerson = FLOOR(DATEDIFF(d,dateOfBirth, GETDATE())/365.25)
Liked the approach of #strelc, but his sql was a bit off. Here's an updated version that works well and is simple to use:
SELECT * FROM User
WHERE (DATEDIFF(dd, getdate(), DATEADD(yyyy,
DATEDIFF(yyyy, birthdate, getdate()) + 1, birthdate)) + 1) % 366 <= <number of days>
edit 10/2017: add single day to end
You could use the DAYOFYEAR function but be careful when you want to look for January birthdays in December. I think you'll be fine as long as the date range you're looking for doesn't span the New Year.
Sorry didn't see the requirement to neutralize the year.
select * from Employees
where DATEADD (year, DatePart(year, getdate()) - DatePart(year, Birthday), Birthday)
between convert(datetime, getdate(), 101)
and convert(datetime, DateAdd(day, 5, getdate()), 101)
This should work.
My guess is using "365.25" soon or later would be fail.
So I test the working solution using "365.25"
And It don't return the same numbers of rows for every case.
Here an example:
http://sqlfiddle.com/#!3/94c3ce/7
test with year 2016 and 2116 and you will see the difference. I only can post one link but change de /7 by /8 to see both queries. (/10 and /11 for the first answer)
So, I suggest this another query, where the point is determinate next birthday from a starting date and then compare if it is in my range of interest.
SELECT * FROM Employees
WHERE
CASE WHEN (DATEADD(yyyy,DATEDIFF(yyyy, birthdt, #fromDate),birthdt) < #fromDate )
THEN DATEADD(yyyy,DATEDIFF(yyyy, birthdt, #fromDate)+1,birthdt)
ELSE DATEADD(yyyy,DATEDIFF(yyyy, birthdt, #fromDate),birthdt) END
BETWEEN #fromDate AND #toDate
This is solution for MS SQL Server:
It returns employees with birthdays in 30 days.
SELECT * FROM rojstni_dnevi
WHERE (DATEDIFF (dd,
getdate(),
DATEADD ( yyyy,
DATEDIFF(yyyy, rDan, getdate()),
rDan)
nex )
+365) % 365 < 30
I found the solution for this. This may save someone's precious time.
select EmployeeID,DOB,dates.date from emp_tb_eob_employeepersonal
cross join dbo.GetDays(Getdate(),Getdate()+7) as dates where weekofmonthnumber>0
and month(dates.date)=month(DOB) and day(dates.date)=day(DOB)
GO
/****** Object: UserDefinedFunction [dbo].[GetDays] Script Date: 11/30/2011 13:19:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--SELECT [dbo].[GetDays] ('02/01/2011','02/28/2011')
ALTER FUNCTION [dbo].[GetDays](#startDate datetime, #endDate datetime)
RETURNS #retValue TABLE
(Days int ,Date datetime, WeekOfMonthNumber int, WeekOfMonthDescription varchar(10), DayName varchar(10))
AS
BEGIN
DECLARE #nextDay int
DECLARE #nextDate datetime
DECLARE #WeekOfMonthNum int
DECLARE #WeekOfMonthDes varchar(10)
DECLARE #DayName varchar(10)
SELECT #nextDate = #startDate, #WeekOfMonthNum = DATEDIFF(week, DATEADD(MONTH, DATEDIFF(MONTH,0,#startDate),0),#startDate) + 1,
#WeekOfMonthDes = CASE #WeekOfMonthNum
WHEN '1' THEN 'First'
WHEN '2' THEN 'Second'
WHEN '3' THEN 'Third'
WHEN '4' THEN 'Fourth'
WHEN '5' THEN 'Fifth'
WHEN '6' THEN 'Sixth'
END,
#DayName
= DATENAME(weekday, #startDate)
SET #nextDay=1
WHILE #nextDate <= #endDate
BEGIN
INSERT INTO #retValue values (#nextDay,#nextDate, #WeekOfMonthNum, #WeekOfMonthDes, #DayName)
SELECT #nextDay=#nextDay + 1
SELECT #nextDate = DATEADD(day,1,#nextDate),
#WeekOfMonthNum
= DATEDIFF(week, DATEADD(MONTH, DATEDIFF(MONTH,0, #nextDate),0), #nextDate) + 1,
#WeekOfMonthDes
= CASE #WeekOfMonthNum
WHEN '1' THEN 'First'
WHEN '2' THEN 'Second'
WHEN '3' THEN 'Third'
WHEN '4' THEN 'Fourth'
WHEN '5' THEN 'Fifth'
WHEN '6' THEN 'Sixth'
END,
#DayName
= DATENAME(weekday, #nextDate)
CONTINUE
END
WHILE(#nextDay <=31)
BEGIN
INSERT INTO #retValue values (#nextDay,#nextDate, 0, '', '')
SELECT #nextDay=#nextDay + 1
END
RETURN
END
Make a cross join with the dates and check for the comparison of month and dates.
In less than a month:
SELECT * FROM people WHERE MOD( DATEDIFF( CURDATE( ) , `date_birth`) /30, 12 ) <1 and (((month(`date_birth`)) = (month(curdate())) and (day(`date_birth`)) > (day (curdate() ))) or ((month(`date_birth`)) > (month(curdate())) and (day(`date_birth`)) < (day (curdate() ))))
You could use DATE_FORMAT to extract the day and month parts of the birthday dates.
EDIT: sorry i didn't see that he wasn't using MySQL.
Assuming this is T-SQL, use DATEPART to compare the month and date separately.
http://msdn.microsoft.com/en-us/library/ms174420.aspx
Alternatively, subtract January 1st of the current year from everyone's birthday, and then compare using the year 1900 (or whatever your epoch year is).
Most of these solutions are close, but you have to remember a few extra scenarios. When working with birthdays and a sliding scale, you must be able to handle the transition into the next month.
For example Stephens example works great for birthdays up until the last 4 days of the month. Then you have a logic fault as the valid dates if today was the 29th would be :29, 30, AND then 1, 2, 3 of the NEXT month, so you have to condition for that as well.
An alternative would be to parse the date from the birthday field, and sub in the current year, then do a standard range comparison.
Another thought: Add their age in whole years to their birthday (or one more if their Birthday hasn't happened yet and then compare as you do above. Use DATEPART and DATEADD to do this.
http://msdn.microsoft.com/en-us/library/ms186819.aspx
The edge case of a range spanning the year would have to have special code.
Bonus tip: consider using BETWEEN...AND instead of repeating the Birthday operand.
This should work...
DECLARE #endDate DATETIME
DECLARE #today DATETIME
SELECT #endDate = getDate()+6, #today = getDate()
SELECT * FROM Employees
WHERE
(DATEPART (month, birthday) >= DATEPART (month, #today)
AND DATEPART (day, birthday) >= DATEPART (day, #today))
AND
(DATEPART (month, birthday) < DATEPART (month, #endDate)
AND DATEPART (day, birthday) < DATEPART (day, #endDate))
I faced the same problem with my college project a few years ago. I responded (in a rather weasel way) by splitting the year and the date(MM:DD) in two separate columns. And before that, my project mate was simply getting all the dates and programatically going through them. We changed that because it was too inefficient - not that my solution was any more elegant either. Also, its probably not possible to do in a database that has been in use for a while by multiple apps.
Give this a try:
SELECT * FROM Employees
WHERE DATEADD(yyyy, DATEPART(yyyy, #Today)-DATEPART(yyyy, Birthday), Birthday) > #Today
AND DATEADD(yyyy, DATEPART(yyyy, #Today)-DATEPART(yyyy, Birthday), Birthday) < DATEADD(dd, #NumDays, #Today)
Nuts! A good solution between when I started thinking about this and when I came back to answer. :)
I came up with:
select (365 + datediff(d,getdate(),cast(cast(datepart(yy,getdate()) as varchar(4)) + '-' + cast(datepart(m,birthdt) as varchar(2)) + '-' + cast(datepart(d,birthdt) as varchar(2)) as datetime))) % 365
from employees
where (365 + datediff(d,getdate(),cast(cast(datepart(yy,getdate()) as varchar(4)) + '-' + cast(datepart(m,birthdt) as varchar(2)) + '-' + cast(datepart(d,birthdt) as varchar(2)) as datetime))) % 365 < #NumDays
You don't need to cast getdate() as a datetime, right?
This is a combination of a couple of the answers that was tested. This will find the next brithday after a certain date and the age they will be. Also the numdays will limit the range you are looking 7 days = week etc.
SELECT DISTINCT FLOOR(DATEDIFF(dd,Birthday, #BeginDate) / 365.25) + 1 age,
DATEADD(yyyy, FLOOR(DATEDIFF(dd,Birthday, #BeginDate) / 365.25) + 1, Birthday) nextbirthday, birthday
FROM table
WHERE DATEADD(yyyy, FLOOR(DATEDIFF(dd,Birthday, #BeginDate) / 365.25) + 1, Birthday) > #BeginDate
AND DATEADD(yyyy, FLOOR(DATEDIFF(dd,Birthday, #BeginDate) / 365.25) + 1, Birthday) < DATEADD(dd, #NumDays, #BeginDate)
order by nextbirthday
The best way to achieve the same is
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SELECT Member.* from vwMember AS Member
WHERE (DATEADD(YEAR, (DATEPART(YEAR, #StartDate) -
DATEPART(YEAR, Member.dBirthDay)), Member.dBirthDay)
BETWEEN #StartDate AND #EndDate)
Upcoming Birthday for the Employee - Sqlserver
DECLARE #sam TABLE
(
EmployeeIDs int,
dob datetime
)
INSERT INTO #sam (dob, EmployeeIDs)
SELECT DOBirth, EmployeeID FROM Employee
SELECT *
FROM
(
SELECT *, bd_this_year = DATEADD(YEAR, DATEPART(YEAR, GETDATE()) - DATEPART(YEAR, dob), dob)
FROM #sam s
) d
WHERE d.bd_this_year > DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0)
AND d.bd_this_year <= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 3)
I used this for MySQL, probably not the most efficient way to query but simple enough to implement.
select * from `schema`.`table` where date_format(birthday,'%m%d') >= date_format(now(),'%m%d') and date_format(birthday,'%m%d') < date_format(DATE_ADD(NOW(), INTERVAL 5 DAY),'%m%d');
i believe this ticket has been closed ages ago but for the benefit of getting the correct sql query please have a look.
SELECT Employee_Name, DATE_OF_BIRTH
FROM Hr_table
WHERE
/**
fetching the original birth_date and replacing the birth year to the current but have to deduct 7 days to adjust jan 1-7 birthdate.
**/
datediff(d,getdate(),DATEADD(year,datediff(year,DATEADD(d,-7,hr.DATE_OF_BIRTH),getdate()),hr.date_of_birth)) between 0 and 7
-- current date looks ahead to 7 days for upcoming modified year birth date.
order by
-- sort by no of days before the birthday
datediff(d,getdate(),DATEADD(year,datediff(year,DATEADD(d,-7,hr.DATE_OF_BIRTH),getdate()),hr.date_of_birth))
Better and easy solution:
select * from users with(nolock)
where date_of_birth is not null
and
(
DATEDIFF(dd,
DATEADD(yy, -(YEAR(GETDATE())-1900),GETDATE()), --Today
DATEADD(yy, -(YEAR(date_of_birth)-1901),date_of_birth)
) % 365
) = 30
I hope this helps u in some way....
select Employeename,DOB
from Employeemaster
where day(Dob)>day(getdate()) and month(DOB)>=month(getDate())
This solution also takes care for birthdays in the next year and the ordering:
(dob = day of birth; bty = birthday this year; nbd = next birthday)
with rs (bty) as (
SELECT DATEADD(Year, DATEPART(Year, GETDATE()) - DATEPART(Year, dob), dob) as bty FROM Employees
),
rs2 (nbd) as (
select case when bty < getdate() then DATEADD(yyyy, 1, bty) else bty end as nbd from rs
)
select nbd, DATEDIFF(d, getdate(), nbd) as diff from rs2 where DATEDIFF(d, getdate(), nbd) < 14 order by diff
This version, which avoids comparison of the dates, could be faster:
with rs (dob, bty) as (
SELECT dob, DATEADD(Year, DATEPART(Year, GETDATE()) - DATEPART(Year, DOB), DOB) as bty FROM employee
),
rs2 (dob, nbd) as (
select dob, DATEADD(yyyy, FLOOR(ABS((-1*(SIGN(DATEDIFF(d, getdate(), bty))))+0.1)), bty) as nbd from rs
),
rs3 (dob, diff) as (
select dob, datediff(d, getdate(), nbd) as diff from rs2
)
select dob, diff from rs3 where diff < 14 order by diff
If the range covers the 29 of February in the next year, then use:
with rs (dob, ydiff) as (
select dob, DATEPART(Year, GETDATE()) - DATEPART(Year, DOB) as ydiff from Employee
),
rs2 (dob, bty, ydiff) as (
select dob, DATEADD(Year, ydiff, dob) as bty, ydiff from rs
),
rs3 (dob, nbd) as (
select dob, DATEADD(yyyy, FLOOR(ABS((-1*(SIGN(DATEDIFF(d, getdate(), bty))))+0.1)) + ydiff, dob) as nbd from rs2
),
rs4 (dob, ddiff, nbd) as (
select dob, datediff(d, getdate(), nbd) as diff, nbd from rs3
)
select dob, nbd, ddiff from rs4 where ddiff < 68 order by ddiff
You can also use DATEPART:
-- To find out Today's Birthday
DECLARE #today DATETIME
SELECT #today = getdate()
SELECT *
FROM SMIS_Registration
WHERE (DATEPART (month, DOB) >= DATEPART (month, #today)
AND DATEPART (day, DOB) = DATEPART (day, #today))
Below query will return all next birthday of employee, it is shortest query.
SELECT
Employee.DOB,
DATEADD(
mm,
(
(
(
(
DATEPART(yyyy, getdate())-DATEPART(yyyy, Employee.DOB )
)
+
(
1-
(
((DATEPART(mm, Employee.DOB)*100)+DATEPART(dd, Employee.DOB))
/
((DATEPART(mm, getdate())*100) + DATEPART(dd, getdate()))
)
)
)
*12
)
),
Employee.DOB
) NextDOB
FROM
Employee
ORDER BY
NextDOB ;
Above query will cover all next month excluding current date.
Solution for SQLite3:
SELECT
*,
strftime('%j', birthday) - strftime('%j', 'now') AS days_remaining
FROM
person
WHERE :n_days >= CASE
WHEN days_remaining >= 0 THEN days_remaining
ELSE days_remaining + strftime('%j', strftime('%Y-12-31', 'now'))
END
;
The solutions dividing by 325.25 to get the age, or bringing the birthdate to the current year etc. didn't work for me.
What this does is computes the delta of the two daysOfTheYear (1-366). If the birthday didn't happen yet this year, you automatically get the correct number of remaining days, which you can compare to.
If the birthday already happened, remaining_days will be negative, and you can get the correct number of remaining days by still adding the total amount of days in the current year. This also correctly handles leap years, since in that case the extra day will be added as well (By using dayOfYear(Dec 31.))
select BirthDate,Name from Employees
order by Case
WHEN convert(nvarchar(5),BirthDate,101) > convert(nvarchar(5),GETDATE(),101) then 2
WHEN convert(nvarchar(5),BirthDate,101) < convert(nvarchar(5),GETDATE(),101) then 3
WHEN convert(nvarchar(5),BirthDate,101) = convert(nvarchar(5),GETDATE(),101) then 1 else 4 end ,convert(nvarchar(2),BirthDate,101),convert(nvarchar(2),BirthDate,105)