Doğum Tarihi ve getDate () esas alınarak yaş (yıl cinsinden) nasıl hesaplanır


171

İnsanları doğum tarihleriyle birlikte listeleyen bir masam var (şu anda nvarchar (25))

Bunu bir tarihe nasıl dönüştürebilirim ve sonra yaşlarını yıl olarak nasıl hesaplayabilirim?

Verilerim aşağıdaki gibi görünüyor

ID    Name   DOB
1     John   1992-01-09 00:00:00
2     Sally  1959-05-20 00:00:00

Görmek isterim:

ID    Name   AGE  DOB
1     John   17   1992-01-09 00:00:00
2     Sally  50   1959-05-20 00:00:00

16
Tarih değerlerini neden veritabanının yerel tarihini veya datetime türünü kullanmak yerine nvarchar (25) kullanarak dizeler olarak saklıyorsunuz?
Jesper

Soru, 2008 değil 2008 olarak etiketlendiğinden yerel 'Tarih' türü kullanılabilir değil, ancak kesinlikle bir datetime ve doğruluğa ihtiyacınız olmadığından SmallDateTime olarak tartışılabilir.
Andrew

Merhaba, tarihleri ​​varchar olarak tutmanın nedeni, bunu SQL olmayan bir sunucu şemasından içe aktarmam, bunları datetime (ve diğer tarih biçimleri) olarak içe aktarmada bazı sorunlar vardı ve varchar dönüştürüldü
Jimmy

7
@ James.Elsey, yani içe aktarma konusunda sorunlarınız oldu ve sonuç olarak tüm tarihler geçerli mi? varchar ile bir datetime veya smalldatetime kullanmadığınızdan asla emin olamazsınız, varchar ile içe aktarma işleminizin çalışmasını sağlayabilirsiniz, ancak satırda başka sorunlar yaşarsınız. Ayrıca, asla yaşı saklamam, her gün değişir, bir View
KM

@KM Evet, bu verileri tarih olarak içe aktarırken bir sorun vardı, o zaman tek geçerli çözüm nvarchar olarak içe aktarmaktı. Bu seçim her gece bir işin parçası olacak, bu yüzden yaşı depolamak sorun olmamalı
Jimmy

Yanıtlar:


256

Artık yıl / gün ve aşağıdaki yöntemle ilgili sorunlar var, aşağıdaki güncellemeye bakın:

bunu dene:

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

ÇIKTI:

AgeYearsDecimal                         AgeYearsIntRound AgeYearsIntTrunc
--------------------------------------- ---------------- ----------------
17.767054                               18               17

(1 row(s) affected)

UPDATE burada bazı daha doğru yöntemler:

INT YILINDA EN İYİ YÖNTEM

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

yukarıdakileri 10000değiştirebilir 10000.0ve ondalık sayıları alabilirsiniz, ancak aşağıdaki yöntem kadar doğru olmayacaktır.

DECIMAL'DA YILLAR İÇİN EN İYİ YÖNTEM

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

24
Bu da kesin bir çözüm değil. '1986-07-05 00:00:00' olarak kendi dolabımı alırsam ve bunu GETDATE()'2013-07-04 23:59:59' tarihinde yürütürsem (yerine başka bir değişken kullanırdım ) 27 yaşındayım, o sırada henüz değilim. Örnek kod: declare @startDate nvarchar(100) = '1986-07-05 00:00:00' declare @endDate nvarchar(100) = '2013-07-04 23:59:59' SELECT DATEDIFF(hour,@startDate,@endDate)/8766.0 AS AgeYearsDecimal ,CONVERT(int,ROUND(DATEDIFF(hour,@startDate,@endDate)/8766.0,0)) AS AgeYearsIntRound ,DATEDIFF(hour,@startDate,@endDate)/8766 AS AgeYearsIntTrunc
bartlaarhoven

20
365,25 güne kadar çalışan yılda 8766 saat olduğu için bu doğru değildir. 365.25 gün ile hiçbir yıl olmadığından, bu kişinin doğum tarihi yakınında doğru olduğundan daha sık yanlış olacaktır. Bu yöntem hala daha doğru olacaktır.
Bacon Bits

1
İkinci @Bacon Bits yorumu - mevcut tarih bir kişinin doğum tarihine yakın olduğunda bu genellikle yanlış olur.
yanıp sönme

2
Sanırım metnin ilk bloğu bu cevabı kafa karıştırıcı yapıyor. Güncellenmiş yönteminizde artık yıllarla ilgili bir sorun yoksa, cevabınızın alt kısmına taşımak için (gerçekten tutmak istiyorsanız) öneririm.
ajbeaven

1
Bir EXACT hesaplaması istiyorsanız , DATEDIFF @ShailendraMishra'da bunu yapmayacaktır, çünkü günlere yakındır, vb. Örneğin, select datediff(year, '2000-01-05', '2018-01-04')olması gerektiği gibi değil 17 değerini döndürür. Yukarıdaki örneği "INT YILINDA EN İYİ YÖNTEM" başlığı altında kullandım ve mükemmel çalışıyor. Teşekkürler!
openwonk

132

Bunu oraya atmalıyım. Eğer varsa dönüştürmek bir sayıya 112 stili (yyyyaagg) kullanarak tarih böyle bir hesaplama kullanabilirsiniz ...

(yyyyMMdd - yyyyMMdd) / 10000 = tam yıllardaki fark

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

çıktı

20091015    19800420    290595  29

14
Artık yıl problemlerini nasıl çözdüğü neredeyse büyülü. 112'nin, tarihi yyyymmdd olarak biçimlendiren CONVERT işlevi için özel bir sayı olduğunu belirtmek gerekebilir. Baktığınızda muhtemelen herkes için açık değildir.
Derek Tomes

5
Sen bir dahisin!
ercan

Ekibim, yaşı bulmak için kullandığımız tarihle karşılaştırdığımız tarihle aynı gün olduğunda bir sorunla karşılaştı. Aynı gün (ve yaş tuhaf olacaksa) yaşın birer birer kapanacağını fark ettik. Bu mükemmel çalıştı!
The Sheek Geek

1
Bu doğru cevap - lütfen bu şekilde işaretleyin.
Snympi

4
SQL Server 2012+ ile aynı hesaplama yönteminin en basit / en kısa koducode: SELECT [Age] = (0+ FORMAT(@as_of,'yyyyMMdd') - FORMAT(@bday,'yyyyMMdd') ) /10000 --The 0+ part tells SQL to calc the char(8) as numbers
ukgav

44

Bu sorguyu yaklaşık 10 yıldır üretim kodumuzda kullandım:

SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age

6
Kötü değil, ama% 100 değil, 2007/10/16 2009/10/15
Andrew

4
Doh, bariz olanı kaçırıyoruz, gün ortasından sonra, getdate bir int döndürüyor, bu yüzden elbette yuvarlanacak. Cevabınızı kopyaladım ve çalıştırdım, böylece otomatik olarak kullanılan getdate, değişmez.
Andrew

2
Zarif ve basit. Teşekkürler!
William MB

9
İnsan yaşlarından bahsediyorsak, insanların yaş hesaplama biçimini hesaplamalısınız. Dünyanın ne kadar hızlı hareket ettiği ve takvim ile ilgili her şeyi ilgilendirmez. Her zaman doğum tarihi aynı ay ve gün geçtiğinde, 1. ederek artım yaş ortalaması insanlarda ne aynalar onlar "yaş" derken, çünkü şu en doğrusudur Bu araçlar:DATEDIFF(yy, @BirthDate, GETDATE()) - CASE WHEN (MONTH(@BirthDate) >= MONTH(GETDATE())) AND DAY(@BirthDate) > DAY(GETDATE()) THEN 1 ELSE 0 END
Bacon Uçları

5
Üzgünüz, bu sözdizimi yanlış. CASE WHEN (MONTH(@date) > MONTH(GETDATE())) OR (MONTH(@date) = MONTH(GETDATE()) AND DAY(@date) > DAY(GETDATE())) THEN 1 ELSE 0 END
Bacon Bits

31

Yukarıdaki çözümlerin birçoğu yanlış DateDiff (yy, @ Dob, @PassedDate) her iki tarihin ayını ve gününü dikkate almayacaktır. Ayrıca dart parçalarını almak ve karşılaştırmak sadece uygun şekilde sipariş edilirse işe yarar.

AŞAĞIDAKİ KOD ÇALIŞIR VE ÇOK BASİT:

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

Neden 100 ile çarpıyorsunuz? Kod kütüphanemizde var olan veritabanında çoğaltmaya çalıştığım için bu benim için çalışıyor - ama işlevinizi açıklayamadım. Bu aptalca bir soru olabilir :)
Jen

6
Teşekkürler! Tam burada kod bekliyordum. Bu, (çirkin) dize dönüşümleri olmadan bu iş parçacığında tam olarak doğru kod! @Jen DoB'nin ayını ve gününü alır (25 Eylül gibi) ve bir tamsayı değerine 0925(veya 925) dönüştürür. Geçerli tarihle aynı işlemi yapar (16 Aralık gibi 1216) ve sonra DoB tamsayı değerinin zaten geçilip geçmediğini kontrol eder. Bu tamsayıyı oluşturmak için ay 100 ile çarpılmalıdır.
bartlaarhoven

Teşekkürler @bartlaarhoven :)
Jen

Ben sadece bu dize dönüşümleri önlemek, ancak bunun yerine döküm çok şey bahsetmek istiyorum. Testlerim dotjoe'un cevabından çok daha hızlı olmadığını ve kodun daha ayrıntılı olduğunu gösteriyor.
StriplingWarrior

kabul edilen cevabın çok daha basit bir INT cevabı vardır:(CONVERT(int,CONVERT(char(8),@Now,112))-CONVERT(char(8),@Dob,112))/10000
KM.

19

Tarihli komutun nasıl yuvarlandığını düşünmeniz gerekir.

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>

Buradan uyarladım .

28 Şubat'ın artık olmayan yıllar için bir sıçramanın doğum günü olarak değerlendirileceğini unutmayın; örneğin 29 Şubat 2020'de doğan bir kişi, 01 Şubat 2021 yerine 28 Şubat 2021'de 1 yaşında olarak kabul edilecektir.


@Andrew - Düzeltildi - Oyuncu değişikliklerinden birini kaçırdım
Ed Harper

1
Basitleştirilmiş sürümSELECT DATEDIFF(year, DOB, getdate()) + CASE WHEN (DATEADD(year,DATEDIFF(year, DOB, getdate()) , DOB) > getdate()) THEN - 1 ELSE 0 END)
Peter

Doğru yaklaşım budur; Hack'lerin neden bu kadar çok oy verildiğini anlamıyorum.
Salman A

8

DÜZENLEME: BU CEVAP YANLIŞ. Sonunda başka bir düzenleme ile , kullanmak isteyen herkese bir uyarı olarak burada bırakıyorum dayofyear.


Benim gibi, kesirli günlere veya risk yuvarlama / artık yıl hatalarına bölmek istemiyorsanız, https://stackoverflow.com/a/1572257/489865 adresindeki bir yayında @Bacon Bits yorumunu alkışlıyorum :

İnsan yaşlarından bahsediyorsak, insanların yaş hesaplama yöntemini hesaplamalısınız. Dünyanın ne kadar hızlı hareket ettiği ve takvim ile ilgili her şeyi ilgilendirmez. Aynı ay ve gün doğum tarihi olarak her geçtiğinde, yaşı 1 arttırırsınız. Bu, aşağıdakilerin en doğru olduğu anlamına gelir;

Daha sonra şunları sunar:

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

Burada ay ve günü karşılaştırmayı içeren birkaç öneri var (ve bazıları yanlış anlıyor, ORburada doğru şekilde izin vermiyor !). Ama hiç kimse teklif etmedi dayofyear, bu çok basit ve çok daha kısa görünüyor. Teklif ediyorum:

DATEDIFF(year, @date, GETDATE()) -
CASE WHEN DATEPART(dayofyear, @date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END

[Not: Hiçbir yerde SQL BOL / MSDN hiçbir yerde DATEPART(dayofyear, ...)gerçekte belgelenmiş olduğunu! 1--366 aralığında bir sayı olduğunu anlıyorum; En önemlisi, yok değil uyarınca bölgeye göre değişiklik DATEPART(weekday, ...)& SET DATEFIRST.]


DÜZENLEME: Neden dayofyearyanlış giderse : doğum / tarih olmayan bir artık yıl Şubat sonradır başlarsanız akım / bitiş tarihi artık yıl olduğunda kullanıcı olarak @AeroX örneğin, yaş bir gün erken artırılır, yorum yaptığını '2015-05-26', '2016-05-25'bir verir 1 yaşındayken, 0 olması gerekir dayofyear. Farklı yıllarda karşılaştırmak açıkça tehlikelidir. Sonuçta MONTH()ve kullanmak DAY()gereklidir.


Bu oylanmalı ve hatta cevap olarak işaretlenmelidir. Kısa, zarif ve mantıksal olarak doğrudur.
z00l

1
Şubat ayından sonra doğan herkes için Yaşları, her bir artık yılda bir gün erken DayOfYearyöntemi kullanılarak artırılır .
AeroX

4
@AeroX Bu kusuru tespit ettiğiniz için teşekkür ederiz. Çözümümü kullanabilecek veya kullanmış olabilecek bir uyarı olarak bırakmaya karar verdim dayofyear, ancak bunun neden yanlış gittiğini göstermek için açıkça düzenledim. Umarım bu uygundur.
JonBrave

5

Her zaman doğru yaşı veren basit bir cevap olmadığından, işte karşımıza çıkan şey.

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 

Bu, doğum tarihi ile mevcut tarih arasındaki yıl farkını alır. Sonra doğum tarihi henüz geçmediyse bir yıl çıkarır.

Her zaman doğru - artık yıllar veya doğum tarihine ne kadar yakın olursa olsun.

En iyisi - işlevsiz.


3
SELECT ID,
Name,
DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE,
DOB
FROM MyTable

1
Getdate'i ikinci argüman olarak istemezsiniz, aksi takdirde negatif sayı sonuçları ve tarihli turlar alırsınız, bu yüzden dateiff (yy, '20081231', getdate ()) 1 yaşını bildirir, ancak yalnızca 10 aylık olurlar .
Andrew

1
Bu hesaplama, bu yıl henüz doğum gününü henüz yaşamamış insanlar için yanlış hesaplamalar veriyor.

3

Ne dersin:

DECLARE @DOB datetime
SET @DOB='19851125'   
SELECT Datepart(yy,convert(date,GETDATE())-@DOB)-1900

Bu, tüm yuvarlama, kesme ve ofsetleme sorunlarından kaçınmaz mı?


Hesaplamanız doğru değil. Örneğin: '1986-07-05 00:00:00'DOB ve '2013-07-04 23:59:59'şimdiki zaman için alırsanız başarısız olur .
drinovc

@ub_coding Başka bir soru sorup cevaplıyor veya soruyor musunuz?
Aaron C

this: DECLARE @DOB datetime SET @ DOB = '19760229' SEÇ Datepart (yy, dönüştürmek (datetime, '19770228') - @ DOB) -1900 = 1 ana sorun fev 29 .
Leonardo Marques de Souza

3

Bunun burada yayınlananlara benzer olduğuna inanıyorum .... ancak bu çözüm 02/29/1976 - 03/01/2011 artık yıl örnekleri için çalıştı ve aynı zamanda ilk yıl için de çalıştı .. 07/04 gibi / 2011 - 07/03/2012 arasında, artık yıl çözümüyle ilgili olarak yayınlanan son başvuru, ilk yıl kullanım davasında işe yaramadı.

SELECT FLOOR(DATEDIFF(DAY, @date1 , @date2) / 365.25)

Burada bulundu .


3

Sadece aşağıdaki cevabın uygun olup olmadığını kontrol edin.

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        
 )

2
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
)

kaynak: http://beginsql.wordpress.com/2012/04/26/how-to-calculate-age-in-sql-server/


Bunu SQL Server 2012+ ile yapmanın daha kısa bir yolu aşağıdaki gibidir ve 112'ye dönüştürmeyi önler ve zemin gerekli değildir:code: SELECT [Age] = (0+ FORMAT(@ToDate,'yyyyMMdd') - FORMAT(@DOB,'yyyyMMdd') ) /10000
ukgav

2

Bunu çok düşünerek araştırdım ve 3 çözümüm var.

  • yaşı doğru hesapla
  • kısa (çoğunlukla)
  • (çoğunlukla) çok anlaşılır.

İşte test değerleri:

DECLARE @NOW DATETIME = '2013-07-04 23:59:59' 
DECLARE @DOB DATETIME = '1986-07-05' 

Çözüm 1: Bu yaklaşımı bir js kütüphanesinde buldum. O benim favorim.

DATEDIFF(YY, @DOB, @NOW) - 
  CASE WHEN DATEADD(YY, DATEDIFF(YY, @DOB, @NOW), @DOB) > @NOW THEN 1 ELSE 0 END

Aslında DOB'a yıllar içinde fark katıyor ve eğer mevcut tarihten daha büyükse bir yıl çıkarıyor. Basit değil mi? Tek şey, yıllardaki farkın burada tekrarlanması.

Ancak satır içi kullanmanız gerekmiyorsa şöyle yazabilirsiniz:

DECLARE @AGE INT = DATEDIFF(YY, @DOB, @NOW)
IF DATEADD(YY, @AGE, @DOB) > @NOW
SET @AGE = @AGE - 1

2.Çözüm: Orijinal olarak @ bacon-bits'ten kopyaladım. Anlaması en kolay ama biraz uzun.

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

Temelde biz insanlar gibi yaşı hesaplıyoruz.


Çözüm 3: Arkadaşım bunu yeniden düzenledi:

DATEDIFF(YY, @DOB, @NOW) - 
  CEILING(0.5 * SIGN((MONTH(@DOB) - MONTH(@NOW)) * 50 + DAY(@DOB) - DAY(@NOW)))

Bu en kısa olanıdır, ancak anlaşılması en zordur. 50sadece bir ağırlık olduğundan, gün farkı yalnızca aylar aynı olduğunda önemlidir. SIGNişlevi -1, 0 veya 1 değerine sahip olduğu değeri dönüştürmek içindir . SQL ile CEILING(0.5 *aynı Math.max(0, value)şey yoktur.


1
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

1
select floor((datediff(day,0,@today) - datediff(day,0,@birthdate)) / 365.2425) as age

Burada çok sayıda 365.25 cevap var. Artık yılların nasıl tanımlandığını unutmayın:

  • Her dört yılda bir
    • hariç her 100 yılda
      • 400 yılda bir hariç

Mükemmel cevap. Burada merak edenler için neden 365.2425'in kullanım için doğru değer olduğuna dair bir açıklama var: grc.nasa.gov/WWW/k-12/Numbers/Math/Mathematical_Thinking/…
vvvv4d

0

Buna ne dersin:

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

0

Bunu dene

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'

0

Bu çözümü deneyin:

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

0

Bu, doğum günü ve yuvarlama ile ilgili sorunları doğru bir şekilde çözecektir:

DECLARE @dob  datetime
SET @dob='1992-01-09 00:00:00'

SELECT DATEDIFF(YEAR, '0:0', getdate()-@dob)

2
Artık yılları doğru işlemez TARİHİ SEÇİN (YIL, '0: 0', dönüştür (tarih, '2014-02-28') -'2012-02-29 ') 2 verir, ancak yalnızca 1 olmalıdır
Peter Kerr

0

Ed Harper'ın çözümü bulduğum en basit çözüm, iki tarihin ay ve günü 1 veya daha az gün olduğunda asla yanlış yanıtı döndürmüyor. Negatif yaşlarla başa çıkmak için hafif bir değişiklik yaptım.

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

0

Doğru olarak işaretlenen cevap doğruluğa daha yakındır, ancak aşağıdaki senaryoda başarısız olur - Doğum Yılı Sıçan yıl ve gün Şubat ayından sonra

declare @ReportStartDate datetime = CONVERT(datetime, '1/1/2014'),
@DateofBirth datetime = CONVERT(datetime, '2/29/1948')

FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8766)


VEYA

FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8765.82) -- Divisor is more accurate than 8766

- Aşağıdaki çözüm bana daha doğru sonuçlar veriyor.

FLOOR(DATEDIFF(YEAR,@DateofBirth,@ReportStartDate) - (CASE WHEN DATEADD(YY,DATEDIFF(YEAR,@DateofBirth,@ReportStartDate),@DateofBirth) > @ReportStartDate THEN 1 ELSE 0 END ))

Artık yıl, tarih 29 şubat, vb. Göz önünde bulundurularak neredeyse tüm senaryolarda çalıştı.

Bu formülde boşluk varsa lütfen beni düzeltin.


Nihai formül bu yanıttaki gibi hemen hemen aynıdır stackoverflow.com/a/1572235/168747 . Ancak buradaki daha az okunabilir ve gereksiz içerir floor.
Marek

0
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

0

Doğum tarihi ve şimdiki tarih verilen yaşı nasıl hesaplayacağım.

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

0
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

-1: Her zaman yanlış olur , month(compare) > month(dob)AMA day(compare) < day(dob), ör select dbo.AgeAtDate('2000-01-14', '2016-02-12').
JonBrave

Haklısın, bu dava için teşekkür ederim, işlevi güncelledin
Vova

0
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

0

Artık yıl değil, matematik değil, sadece tarih işlevlerine sahip bir çözüm hakkında

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

0

BİRÇOK yöntem denedikten sonra, bu stil 112 dönüştürmek yerine modern MS SQL FORMAT işlevini kullanarak% 100 zaman çalışır. Ya işe yarayacaktı ama bu en az kod.

Herkes çalışmayan bir tarih kombinasyonu bulabilir mi? Bir tane olduğunu sanmıyorum :)

--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

-2

Burada böyle bir şey kullandık, ama sonra ortalama yaşı alıyoruz:

ROUND(avg(CONVERT(int,DATEDIFF(hour,DOB,GETDATE())/8766.0)),0) AS AverageAge

Dikkat, YUVARLAK içeriden ziyade dışında. Bu, AVG'nin daha doğru olmasını sağlar ve sadece bir kez YUVARIZ. Daha hızlı yapmak.


-2
select DATEDIFF(yy,@DATE,GETDATE()) -
case when DATEPART(mm,GETDATE())*100+DATEPART(dd,GETDATE())>=
DATEPART(mm,@DATE)*100+DATEPART(dd,@DATE) THEN 0
ELSE 1 END 

-2
SELECT CAST(DATEDIFF(dy, @DOB, GETDATE()+1)/365.25 AS int)

Oyları aşağı görüyorum ama bunun bozulduğunu kanıtlayan örnekler göremiyorum.
Alex
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.