Issue when Converting object of Type day to year

dates

#1

Hi,

I think I am having a bug when I want to convert number of days between 2 dates into years:
I have:
DateFinObservation = Dates.Date(2008,12,31)
DateNaiss = Dates.Date.(t.DateNaissance,“mm/dd/yyyy”)

test= DateFinObservation - DateNaissance #will give me number of days between 2 dates in type days
then if I want to make
test2=Dates.year(test) # I have error message MethodError : no method matching +(::Day,::Int64)

Can you please help?


#2

What you were looking for is Dates.Year, but that does not work the way you want it either because a number of days cannot be converted into years as years have a variable number of days.

Two possible solutions are:

julia> Dates.year(d1) - Dates.year(d2)
9

julia> Dates.days(d1-d2)/365.25
9.100616016427105

PS: have a read through PSA: make it easier to help you.


#3

I understand but:
Let’s say that NumDays = d1-d2 = 367 days
if I make Date.year (NumDays) I have an error message
if I make Date.year (367) i Have the right answer

As a scientific calculation I should be able to calculate datediff(d1,d2,yyyy) like we have in vba or R
Is that something that someone can work on the package Dates?


#4

If you want the number of years as a fraction, there are many conventions in use: DayCounts.jl attempts to cover them all.

However it sounds like you want the largest integer n such that dt1 + Year(n) <= dt2, in which case you could do something like:

function nyears(dt1, dt2)
    n = div(dt2 - dt1, Day(365))
    dt1 + Year(n) <= dt2 ? n : n-1
end

#5
julia> d1 = Dates.Date(2010,1,2)
2010-01-02

julia> d2 = Dates.Date(2008,12,31)
2008-12-31

julia> numdays = d1 - d2
367 days

julia> Dates.year(numdays)
ERROR: MethodError: no method matching +(::Day, ::Int64)

julia> Dates.year(Dates.value(numdays))
2

Note: This is not the same as DateDiff in VB (which only looks at the two years, not the months and days).


#6

Note that Dates.year with an integer argument is undocumented: it effectively gives you the number of Rata Die years: see https://github.com/JuliaLang/julia/blob/master/stdlib/Dates/src/accessors.jl


#7

Thank you very much everyone. Actually Dates.values is very useful as well I tried a trick that works I did Dates.year(Dates.day(startDate-EnDate))
Otherwise I coded a function that replicate Datediff from vba


#8

Isn’t this just year(d1) - year(d2) ?


#9

It is not the exact calculation of age as it should consider months and days


#10

Note that you cannot calculate the age of a person in years when you know their age in days. So your function will need to work on both dates and not on their difference:

julia> function age(dob, date)
       age = Dates.year(date)- Dates.year(dob) -1
       if Dates.month(date)>Dates.month(dob) || (Dates.month(date)==Dates.month(dob) &&  Dates.day(date)>=Dates.day(dob))
         age += 1
       end
       return age
       end

PS: have another read on how to quote your code: PSA: how to quote code with backticks


#11

Some alternatives to the above age function…

Emphasis on performance, using yearmonthday:

function age2(dob, date)
    y,m,d = yearmonthday(date) .- yearmonthday(dob)
    y - (m > 0 || (m == 0 && d >= 0) ? 0 : 1)
end

Emphasis on brevity and simplicity (still faster than age):

function age3(dob, date)
    y = year(date) - year(dob)
    y - (dob > date - Year(y) ? 1 : 0)
end
For reference, here's the above `age` function
function age(dob, date)
    age = Dates.year(date)- Dates.year(dob) -1
    if Dates.month(date)>Dates.month(dob) || (Dates.month(date)==Dates.month(dob) &&  Dates.day(date)>=Dates.day(dob))
        age += 1
    end
    return age
end

Are they all the same?

range = Date(1996,1,1):Day(1):Date(2010,1,1)
for d1 = range, d2 = range
    age(d1, d2) ≡ age2(d1, d2) ≡ age3(d1, d2) || println(d1," ",d2)
end

Yes (no output generated). How do they perform?

julia> @btime [age(d1, d2) for d1=$range, d2=$range];
  1.675 s (2 allocations: 199.61 MiB)

julia> @btime [age2(d1, d2) for d1=$range, d2=$range];
  874.106 ms (2 allocations: 199.61 MiB)

julia> @btime [age3(d1, d2) for d1=$range, d2=$range];
  1.470 s (2 allocations: 199.61 MiB)