Cara menghitung usia (dalam tahun) berdasarkan Tanggal Kelahiran dan getDate ()


171

Saya memiliki tabel yang mencantumkan orang beserta tanggal lahirnya (saat ini nvarchar (25))

Bagaimana saya bisa mengonversi itu menjadi tanggal, dan kemudian menghitung usia mereka dalam tahun?

Data saya terlihat sebagai berikut

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

Saya ingin melihat:

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

16
Mengapa Anda menyimpan nilai tanggal sebagai string menggunakan nvarchar (25) alih-alih menggunakan tanggal asli database atau tipe datetime?
Jesper

Pertanyaan ini ditandai tahun 2005 bukan 2008 sehingga tipe 'Tanggal' asli tidak tersedia, tetapi jelas merupakan datetime, dan itu bisa diperdebatkan SmallDateTime karena Anda tidak perlu keakuratannya.
Andrew

Hai, alasan untuk menjaga tanggal sebagai varchar adalah karena saya mengimpor ini dari skema server non-SQL, ada beberapa masalah mengimpornya sebagai datetime (dan format tanggal lainnya) dan varchar dikonversi ok
Jimmy

7
@ James.Elsey, jadi Anda mengalami masalah saat mengimpor dan hasilnya semua tanggal valid? tidak pernah bisa yakin kecuali Anda menggunakan datetime atau smalldatetime, dengan varchar, Anda mungkin mendapatkan impor Anda untuk bekerja, tetapi memiliki masalah lain di telepon. Juga, saya tidak pernah menyimpan usia, itu berubah setiap hari, menggunakan View
KM.

@ KM Ya ada masalah saat mengimpor data sebagai tanggal, satu-satunya solusi saat itu adalah mengimpornya sebagai nvarchars. Pilih ini akan menjadi bagian dari pekerjaan malam sehingga menyimpan usia seharusnya tidak menjadi masalah
Jimmy

Jawaban:


256

Ada masalah dengan tahun kabisat / hari dan metode berikut, lihat pembaruan di bawah ini:

coba ini:

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

KELUARAN:

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

(1 row(s) affected)

UPDATE di sini adalah beberapa metode yang lebih akurat:

METODE TERBAIK UNTUK TAHUN DI 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

Anda dapat mengubah di atas 10000ke 10000.0dan mendapatkan desimal, tetapi itu tidak akan seakurat metode di bawah ini.

METODE TERBAIK UNTUK TAHUN DI DESIMAL

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
Ini juga bukan solusi yang tepat. Jika saya mengambil @dob saya sendiri menjadi '1986-07-05 00:00:00' dan saya akan menjalankan ini (gunakan variabel lain sebagai ganti GETDATE()) pada '2013-07-04 23:59:59' katanya, saya Sedang 27, sementara pada saat itu, saya belum. Kode contoh: 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
Ini tidak akurat karena mengasumsikan 8766 jam per tahun, yang bekerja hingga 365,25 hari. Karena tidak ada tahun dengan 365,25 hari, ini akan menjadi salah di dekat tanggal lahir seseorang lebih sering daripada yang benar. Metode ini masih akan lebih akurat.
Bacon Bits

1
Komentar @Bacon Bits kedua - ini sering salah ketika tanggal saat ini mendekati tanggal lahir seseorang
Flash

2
Saya pikir blok teks pertama membuat jawaban ini membingungkan. Jika metode Anda yang diperbarui tidak memiliki masalah dengan tahun kabisat, saya sarankan (jika Anda benar-benar ingin menyimpannya sama sekali) untuk memindahkannya ke bagian bawah jawaban Anda.
ajbeaven

1
Jika Anda menginginkan perhitungan TEPAT , maka DATEDIFF tidak akan melakukannya @ShailendraMishra, karena ini mendekati hari, dll. Misalnya, select datediff(year, '2000-01-05', '2018-01-04')mengembalikan 18, bukan 17 sebagaimana mestinya. Saya menggunakan contoh di atas di bawah judul "METODE TERBAIK UNTUK TAHUN DALAM INT" dan itu berfungsi dengan baik. Terima kasih!
openwonk

132

Harus membuang yang ini di luar sana. Jika Anda mengonversi tanggal menggunakan gaya 112 (yyyymmdd) ke angka, Anda dapat menggunakan perhitungan seperti ini ...

(yyyyMMdd - yyyyMMdd) / 10000 = perbedaan dalam tahun penuh

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

keluaran

20091015    19800420    290595  29

14
Ini hampir ajaib dalam cara memecahkan semua masalah tahun kabisat. Mungkin perlu dicatat bahwa 112 adalah angka khusus untuk fungsi CONVERT yang memformat tanggal sebagai yyyymmdd. Mungkin tidak jelas bagi semua orang ketika Anda melihatnya.
Derek Tomes

5
Anda jenius!
ercan

Tim saya mengalami masalah ketika tanggal yang kami gunakan untuk menemukan usia adalah hari yang sama dengan tanggal kami membandingkannya. Kami memperhatikan bahwa ketika mereka pada hari yang sama (dan jika usia akan menjadi aneh) usia akan dimatikan satu per satu. Ini bekerja dengan sempurna!
The Sheek Geek

1
Ini adalah jawaban yang benar - harap tandai sebagai itu.
Snympi

4
Kode paling sederhana / terpendek untuk metode perhitungan yang sama persis ini di SQL Server 2012+ adalahcode: 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

Saya telah menggunakan kueri ini dalam kode produksi kami selama hampir 10 tahun:

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

6
Ini tidak buruk, tetapi tidak 100%, 2007/10/16 akan melaporkan usia 2 tahun pada 2009/10/15
Andrew

4
Doh, kita kehilangan yang jelas, setelah tengah hari, getdate mengembalikan sebuah int jadi akan mengumpulkan tentu saja. Saya salin menempelkan jawaban Anda dan menjalankannya, sehingga secara otomatis menggunakan getdate, bukan literal.
Andrew

2
Elegan dan sederhana. Terima kasih!
William MB

9
Jika kita berbicara tentang usia manusia, Anda harus menghitungnya dengan cara manusia menghitung usia. Ini tidak ada hubungannya dengan seberapa cepat bumi bergerak dan segala sesuatu yang berkaitan dengan kalender. Setiap kali bulan dan hari yang sama berlalu sebagai tanggal lahir, Anda menambah usia dengan 1. Ini berarti yang berikut ini adalah yang paling akurat karena mencerminkan apa yang manusia maksudkan ketika mereka mengatakan "usia":DATEDIFF(yy, @BirthDate, GETDATE()) - CASE WHEN (MONTH(@BirthDate) >= MONTH(GETDATE())) AND DAY(@BirthDate) > DAY(GETDATE()) THEN 1 ELSE 0 END
Bacon Bits

5
Maaf, sintaks itu salah. CASE WHEN (MONTH(@date) > MONTH(GETDATE())) OR (MONTH(@date) = MONTH(GETDATE()) AND DAY(@date) > DAY(GETDATE())) THEN 1 ELSE 0 END
Bacon Bits

31

Begitu banyak solusi di atas yang salah DateDiff (yy, @ Dob, @PassedDate) tidak akan mempertimbangkan bulan dan hari dari kedua tanggal. Juga mengambil bagian panah dan membandingkan hanya berfungsi jika mereka dipesan dengan benar.

KODE BERIKUT INI BEKERJA DAN SANGAT SEDERHANA:

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

Mengapa Anda mengalikan dengan 100? Ini berfungsi untuk saya karena saya mencoba mereplikasi dalam database apa yang ada di perpustakaan kode kami - tetapi saya tidak bisa menjelaskan fungsi Anda. Ini mungkin pertanyaan bodoh :)
Jen

6
Terima kasih! Tepatnya kode yang kuharapkan di sini. Ini adalah satu - satunya kode yang benar-benar tepat di utas ini tanpa transformasi string (jelek)! @ Jen Membutuhkan bulan dan hari DoB (seperti 25 September) dan mengubahnya menjadi nilai integer 0925(atau 925). Itu melakukan hal yang sama dengan tanggal saat ini (seperti 16 Desember menjadi 1216) dan kemudian memeriksa apakah nilai integer DoB telah berlalu. Untuk membuat bilangan bulat ini, bulan harus dikalikan dengan 100.
bartlaarhoven

Terima kasih @ Bartlaarhoven :)
Jen

Saya hanya akan menyebutkan bahwa sementara ini menghindari transformasi string, ia melakukan banyak casting. Pengujian saya menunjukkan itu tidak jauh lebih cepat daripada jawaban dotjoe , dan kodenya lebih verbose.
StriplingWarrior

jawaban yang diterima memiliki jawaban INT yang lebih sederhana:(CONVERT(int,CONVERT(char(8),@Now,112))-CONVERT(char(8),@Dob,112))/10000
KM.

19

Anda perlu mempertimbangkan cara putaran perintah Dateiff.

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>

Yang saya adaptasi dari sini .

Perhatikan bahwa itu akan mempertimbangkan 28 Februari sebagai hari ulang tahun lompatan untuk tahun-tahun non-lompatan misalnya orang yang lahir pada tanggal 29 Februari 2020 akan dianggap berusia 1 tahun pada tanggal 28 Februari 2021 alih-alih 01 Mar 2021.


@Andrew - Dikoreksi - Saya merindukan salah satu pengganti
Ed Harper

1
Versi sederhanaSELECT DATEDIFF(year, DOB, getdate()) + CASE WHEN (DATEADD(year,DATEDIFF(year, DOB, getdate()) , DOB) > getdate()) THEN - 1 ELSE 0 END)
Peter

Ini adalah pendekatan yang benar; Saya tidak mengerti mengapa peretasan ter-upgrade terlalu banyak.
Salman A

8

EDIT: JAWABAN INI TIDAK BENAR. Saya meninggalkannya di sini sebagai peringatan bagi siapa saja yang tergoda untuk menggunakannya dayofyear, dengan pengeditan lebih lanjut di bagian akhir.


Jika, seperti saya, Anda tidak ingin membaginya dengan hari pecahan atau risiko pembulatan / tahun kabisat, saya memuji komentar @Bacon Bits dalam pos di atas https://stackoverflow.com/a/1572257/489865 di mana ia berkata:

Jika kita berbicara tentang usia manusia, Anda harus menghitungnya dengan cara manusia menghitung usia. Ini tidak ada hubungannya dengan seberapa cepat bumi bergerak dan segala sesuatu yang berkaitan dengan kalender. Setiap kali bulan dan hari yang sama berlalu sebagai tanggal lahir, Anda menambah usia dengan 1. Ini berarti yang berikut ini adalah yang paling akurat karena mencerminkan apa yang manusia maksudkan ketika mereka mengatakan "usia".

Dia kemudian menawarkan:

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

Ada beberapa saran di sini yang melibatkan membandingkan bulan & hari (dan ada yang salah, gagal mengizinkannya dengan ORbenar di sini!). Tapi tidak ada yang menawarkan dayofyear, yang tampak sangat sederhana dan jauh lebih pendek. Saya menawarkan:

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

[Catatan: Tidak ada dalam SQL BOL / MSDN yang DATEPART(dayofyear, ...)mengembalikan benar-benar didokumentasikan! Saya memahaminya sebagai angka dalam kisaran 1--366; yang paling penting, itu tidak berubah menurut lokal sesuai DATEPART(weekday, ...)& SET DATEFIRST.]


EDIT: Mengapa dayofyearsalah : Sebagai pengguna @AeroX telah berkomentar, jika tanggal lahir / mulai adalah setelah Februari di tahun bukan kabisat, usia bertambah satu hari lebih awal ketika tanggal saat ini / akhir adalah tahun kabisat, misalnya '2015-05-26', '2016-05-25'memberikan usia 1 ketika masih harus 0. Membandingkan dayofyeardi tahun yang berbeda jelas berbahaya. Jadi menggunakan MONTH()dan DAY()diperlukan setelah semua.


Ini harus dipilih atau bahkan ditandai sebagai jawabannya. Itu pendek, elegan dan secara logis benar.
z00l

1
Untuk semua orang yang lahir setelah Februari Umur mereka bertambah satu hari lebih awal pada setiap tahun kabisat menggunakan DayOfYearmetode ini.
AeroX

4
@ AeroX Terima kasih telah melihat kekurangan ini. Saya memutuskan untuk meninggalkan solusi sebagai peringatan bagi siapa saja yang mungkin atau telah menggunakan dayofyear, tetapi diedit dengan jelas untuk menunjukkan mengapa itu salah. Saya harap itu cocok.
JonBrave

5

Karena tidak ada satu jawaban sederhana yang selalu memberikan usia yang benar, inilah yang saya temukan.

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 

Ini mendapatkan perbedaan tahun antara tanggal lahir dan tanggal saat ini. Maka dikurangi satu tahun jika tanggal lahir belum berlalu.

Akurat setiap saat - terlepas dari tahun kabisat atau seberapa dekat dengan tanggal lahir.

Terbaik dari semuanya - tidak ada fungsi.


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

1
Anda ingin getdate sebagai argumen kedua, bukan argumen pertama jika tidak, Anda mendapatkan hasil angka negatif, dan putaran tanggaliff, jadi pilih Dateiff (yy, '20081231', getdate ()) akan melaporkan usia 1, tetapi mereka hanya akan berusia 10 bulan .
Andrew

1
Perhitungan ini memberikan perhitungan yang salah untuk orang yang belum berulang tahun tahun ini.

3

Bagaimana dengan:

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

Bukankah itu akan menghindari semua masalah pembulatan, pemangkasan, dan ofsetting?


Perhitungan Anda tidak akurat. Misalnya: gagal jika Anda mengambil '1986-07-05 00:00:00'untuk DOB dan '2013-07-04 23:59:59'untuk waktu saat ini.
drinovc

@ub_coding Apakah Anda menawarkan dan menjawab atau mengajukan pertanyaan lain?
Aaron C

ini: DECLARE @DOB datetime SET @ DOB = '19760229' SELECT Datepart (yy, convert (datetime, '19770228') - @ DOB) -1900 = 1 masalah utama adalah celah 29 untuk sebagian besar solusi, itu menjelaskan pemotongan pembulatan dll .
Leonardo Marques de Souza

3

Saya percaya ini mirip dengan yang lain diposting di sini .... tetapi solusi ini bekerja untuk contoh tahun kabisat 02/29/1976 hingga 03/01/2011 dan juga bekerja untuk kasus ini untuk tahun pertama .. seperti 07/04 / 2011 hingga 07/03/2012 yang terakhir diposting tentang solusi tahun kabisat tidak berfungsi untuk kasus penggunaan tahun pertama.

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

Ditemukan di sini .


3

Periksa apakah jawaban di bawah ini layak.

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
)

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


Cara yang lebih singkat untuk melakukan ini di SQL Server 2012+ adalah sebagai berikut, dan menghindari konversi ke 112 dan lantai tidak diperlukan:code: SELECT [Age] = (0+ FORMAT(@ToDate,'yyyyMMdd') - FORMAT(@DOB,'yyyyMMdd') ) /10000
ukgav

2

Saya telah melakukan banyak pemikiran dan mencari tentang ini dan saya punya 3 solusi itu

  • hitung usia dengan benar
  • pendek (kebanyakan)
  • (kebanyakan) sangat dimengerti.

Berikut adalah nilai-nilai pengujian:

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

Solusi 1: Saya menemukan pendekatan ini di satu perpustakaan js. Itu favorit saya.

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

Ini sebenarnya menambah perbedaan tahun ke DOB dan jika lebih besar dari tanggal saat ini maka kurangi satu tahun. Sederhana bukan? Satu-satunya hal adalah perbedaan dalam tahun digandakan di sini.

Tetapi jika Anda tidak perlu menggunakannya sebaris, Anda dapat menulisnya seperti ini:

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

Solusi 2: Yang ini saya awalnya salin dari @ bacon-bits. Ini yang paling mudah dimengerti tapi agak lama.

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

Ini pada dasarnya menghitung usia seperti halnya manusia.


Solusi 3: Teman saya refactored ke dalam ini:

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

Yang ini adalah yang terpendek tetapi paling sulit untuk dipahami. 50hanya berat sehingga perbedaan hari hanya penting ketika bulan adalah sama. SIGNfungsi untuk mengubah nilai apa pun yang didapat menjadi -1, 0 atau 1. CEILING(0.5 *sama dengan Math.max(0, value)tetapi tidak ada hal seperti itu dalam SQL.


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

Ada banyak 365,25 jawaban di sini. Ingat bagaimana tahun kabisat didefinisikan:

  • Setiap empat tahun
    • kecuali setiap 100 tahun
      • kecuali setiap 400 tahun

Jawaban yang sangat bagus. Bagi mereka yang penasaran di sini adalah penjelasan mengapa 365.2425 adalah nilai yang benar untuk digunakan: grc.nasa.gov/WWW/k-12/Numbers/Math/Mathematical_Thinking/…
vvvv4d

0

Bagaimana dengan ini:

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

Coba ini

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

Coba solusi ini:

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

Ini akan menangani masalah dengan ulang tahun dan pembulatan dengan benar:

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

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

2
Tidak menangani tahun kabisat dengan benar SELECT DATEDIFF (YEAR, '0: 0', convert (datetime, '2014-02-28') -'2012-02-29 ') memberi 2, tetapi seharusnya hanya 1
Peter Kerr

0

Solusi Ed Harper adalah yang paling sederhana yang saya temukan yang tidak pernah mengembalikan jawaban yang salah ketika bulan dan hari dari dua tanggal terpisah 1 atau kurang hari. Saya membuat sedikit modifikasi untuk menangani zaman negatif.

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

Jawaban yang ditandai sebagai benar lebih dekat ke akurasi tetapi, gagal dalam skenario berikut - di mana Tahun kelahiran adalah tahun dan hari kabisat setelah bulan Februari

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

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


ATAU

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

- Solusi berikut memberi saya hasil yang lebih akurat.

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

Ini bekerja di hampir semua skenario, mengingat tahun kabisat, tanggal 29 Februari, dll.

Harap perbaiki saya jika rumus ini memiliki celah.


Rumus akhir hampir tepat seperti pada jawaban ini stackoverflow.com/a/1572235/168747 . Tapi yang di sini kurang bisa dibaca dan mengandung yang tidak perlu 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

Berikut ini cara menghitung usia yang diberikan tanggal lahir dan tanggal saat ini.

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: Akan salah kapan saja month(compare) > month(dob)TETAPI day(compare) < day(dob), mis select dbo.AgeAtDate('2000-01-14', '2016-02-12').
JonBrave

Anda benar, terima kasih untuk kasus ini, telah memperbarui fungsi
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

Bagaimana dengan solusi dengan hanya fungsi tanggal, bukan matematika, tidak khawatir tentang tahun kabisat

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

Setelah mencoba metode BANYAK, ini berfungsi 100% dari waktu menggunakan fungsi MS SQL FORMAT modern alih-alih dikonversi ke gaya 112. Entah akan bekerja tetapi ini adalah kode paling sedikit.

Adakah yang bisa menemukan kombinasi tanggal yang tidak berfungsi? Saya tidak berpikir ada :)

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

Kami menggunakan sesuatu seperti di sini, tetapi kemudian mengambil usia rata-rata:

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

Perhatikan, ROUND berada di luar daripada di dalam. Ini akan memungkinkan AVG menjadi lebih akurat dan kami ROUND hanya sekali. Membuatnya lebih cepat juga.


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

Saya melihat suara tetapi saya tidak melihat contoh yang membuktikan ini rusak.
Alex
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.