# \`Type(val)\` vs \`convert(Type, val)\` (Converting more than 365 days to months and years)

**URL:** <https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684>\
**Category:** General Usage\
**Tags:** dates, time, convert\
**Created:** [November 2, 2023, 10:15am UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684 "2023-11-02T10:15:24Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![TheLateKronos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thelatekronos/32/12824_2.png) [@TheLateKronos](https://discourse.julialang.org/u/TheLateKronos)\
**Post date:** [November 2, 2023, 10:15am UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/1 "2023-11-02T10:15:24Z")

</div>

I was wondering how many years were between two events. So I define the timepoints, and find their difference:

```julia
julia> using Dates

julia> d0 = Date(1980, 6, 17)
1980-06-17

julia> d1 = Date(2015, 1, 4)
2015-01-04

julia> Δd = d1-d0
12619 days

```

I now wonder how many years and months this is, and try to convert it to a date:

```julia
julia> Date(Δd)
ERROR: ArgumentError: Day: 12619 out of range (1:31)
Stacktrace:
 [1] Date(y::Int64, m::Int64, d::Int64)
   @ Dates ~/.julia/juliaup/julia-1.10.0-beta3+0.x64.linux.gnu/share/julia/stdlib/v1.10/Dates/src/types.jl:257
 [2] Date
   @ Dates ~/.julia/juliaup/julia-1.10.0-beta3+0.x64.linux.gnu/share/julia/stdlib/v1.10/Dates/src/types.jl:305 [inlined]
 [3] Date(::Day)
   @ Dates ~/.julia/juliaup/julia-1.10.0-beta3+0.x64.linux.gnu/share/julia/stdlib/v1.10/Dates/src/types.jl:349
 [4] top-level scope
   @ REPL[33]:1

```

Okay, so I can not convert directly to date (this turns out to be false). So I google, and find [this](https://stackoverflow.com/questions/54654197/problem-with-julia-function-to-convert-seconds-to-hours-minutes-seconds) stackoverflow question. To convert more than 60 seconds to hours and minutes (similar problem), it reccomends an approach along the lines of

```julia
julia> Time(0) + Second(4000)
01:06:40

```

So I give that a shot:

```julia
julia> Δd + Date(0)
0034-07-20

```

Okay, so that works. But what happens here is just that `Day(12619)` is converted to `Date`:

```julia
julia> Δd + Date(0) |> typeof
Date

```

But that is what I attempted initially, with `Date(Δd)`! Or, that is what I thought. Apparently the two are different:

```julia
julia> convert(Date, Δd)
0035-07-20

```

I can see from using `@code_lowered` that `Type(val)` produces quite different code from `convert(Type, val)`. Notably, the `convert` version produces significantly less code. My mental model was `Type(val)` essentially lowered to `convert(Type, val)`, or the other way around. The examples with dates and times are the only cases where I have seen the effects from the difference.

An example of why I thought that they lowered to essentially the same is how the expressions below have similar stack traces and identical errors:

```julia
julia> Int(1.1)
ERROR: InexactError: Int64(1.1)
Stacktrace:
 [1] Int64(x::Float64)
   @ Base ./float.jl:909
 [2] top-level scope
   @ REPL[53]:1

julia> convert(Int, 1.1)
ERROR: InexactError: Int64(1.1)
Stacktrace:
 [1] Int64
   @ Base ./float.jl:909 [inlined]
 [2] convert(::Type{Int64}, x::Float64)
   @ Base ./number.jl:7
 [3] top-level scope
   @ REPL[52]:1

```

Could someone give me some interpretation as to why the two are different? Should they generally not be used interchangeably?

---

<div class="post-metadata">

**Author:** ![sostock](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sostock/32/5546_2.png) [@sostock](https://discourse.julialang.org/u/sostock)\
**Post date:** [November 2, 2023, 10:59am UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/2 "2023-11-02T10:59:52Z")

</div>

> [@TheLateKronos](#):
>
> ```julia
> julia> convert(Date, Δd)
> 0035-07-20
> 
> ```

IMHO, this shouldn’t be allowed. A `Date` corresponds to a specific point in time (in the proleptic Gregorian calendar) while `Day(12619)` refers to any period of 12619 days, regardless of when they took place (if they even refer to an event that happened in reality at all).

Why should a period of 12619 days be _the same_ as any specific point in time (in this case some day in the year 35 AD)? To me, this seems wrong, and `==` seems to agree:

```julia
julia> Δd == convert(Date, Δd)
false

```

(although it’s just hitting the `===` fallback, so this might be an oversight). I would argue that `convert` should error here.

As for converting `Δd` to a number of years and months: Since not all years/months have the same number of days, this is not well-defined, so `canonicalize` returns a number of weeks and days:

```julia
julia> canonicalize(Δd)
1802 weeks, 5 days

```

Maybe there should be a `CompoundPeriod(d1, d0)` method for returning the difference of two dates in Years, months, etc.? Or is there already something like this?

---

<div class="post-metadata">

**Author:** ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)\
**Post date:** [November 2, 2023, 11:07am UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/3 "2023-11-02T11:07:04Z")

</div>

EDIT: Ah, nevermind, I didn’t see @sostock already raised the same points 😅

> [@TheLateKronos](#):
>
> My mental model was `Type(val)` essentially lowered to `convert(Type, val)`, or the other way around.

I think it’s usually the latter (`convert(T, val)` will in most cases call the consructor `T` at some point, since it is supposed to return something of type `T` – that’s also what your example with `Int(1.1)` shows), but I’m sure there are cases where the constructor tries to `convert` something. It seems to happen for example when trying to construct a `Year` out of your time difference:

```julia
julia> Year(Δd)
ERROR: MethodError: Cannot `convert` an object of type Day to an object of type Year
Closest candidates are:
  convert(::Type{T}, ::Dates.CompoundPeriod) where T<:Period at ~/Applications/Julia-1.8.app/Contents/Resources/julia/share/julia/stdlib/v1.8/Dates/src/periods.jl:363
  convert(::Type{Year}, ::Month) at ~/Applications/Julia-1.8.app/Contents/Resources/julia/share/julia/stdlib/v1.8/Dates/src/periods.jl:455
  convert(::Type{Year}, ::Quarter) at ~/Applications/Julia-1.8.app/Contents/Resources/julia/share/julia/stdlib/v1.8/Dates/src/periods.jl:464
  ...
Stacktrace:
 [1] Year(p::Day)
   @ Dates ~/Applications/Julia-1.8.app/Contents/Resources/julia/share/julia/stdlib/v1.8/Dates/src/periods.jl:420
 [2] top-level scope
   @ REPL[12]:1

```

* * *

This doesn’t really answer your questions, but is converting the difference between two dates again to a date really the right thing to do to get to the duration expressed in years? There is e.g. the `canonicalize` function, but it doesn’t seem to go beyond weeks by default…

```julia
julia> canonicalize(Δd)
1802 weeks, 5 days

```

---

<div class="post-metadata">

**Author:** ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)\
**Post date:** [November 2, 2023, 11:15am UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/4 "2023-11-02T11:15:26Z")

</div>

Well how would it go beyond weeks? `Month` and `Year` are both variable length, so you can’t in general say e.g. how many months 61 days are or how many years are in 1802 weeks.

---

<div class="post-metadata">

**Author:** ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)\
**Post date:** [November 2, 2023, 11:22am UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/5 "2023-11-02T11:22:45Z")

</div>

My bad, I forgot people are still using the Gregorian calendar 🙄 😜

(I couldn’t find an “official” English version of this, but this is the reference: [Der Migokalender](https://prlbr.de/2016/migokalender/) It’s a pretty interesting idea, but I doubt that it will stick…)

---

<div class="post-metadata">

**Author:** ![TheLateKronos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thelatekronos/32/12824_2.png) [@TheLateKronos](https://discourse.julialang.org/u/TheLateKronos)\
**Post date:** [November 2, 2023, 3:31pm UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/6 "2023-11-02T15:31:19Z")

</div>

> [@nilshg](#):
>
> Well how would it go beyond weeks? `Month` and `Year` are both variable length, so you can’t in general say e.g. how many months 61 days are or how many years are in 1802 weeks.

This is true, but I still find it very useful to be able to express the difference between two timepoints in years. Especially when _they are years appart_ (see how natural language uses the unit of years?).

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [November 2, 2023, 3:43pm UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/7 "2023-11-02T15:43:50Z")

</div>

> [@TheLateKronos](#):
>
> ```julia
> julia> convert(Date, Δd)
> 0035-07-20
> 
> ```

oh gosh, yet another one on the `Dates` pile

---

<div class="post-metadata">

**Author:** ![TheLateKronos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thelatekronos/32/12824_2.png) [@TheLateKronos](https://discourse.julialang.org/u/TheLateKronos)\
**Post date:** [November 2, 2023, 5:27pm UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/8 "2023-11-02T17:27:59Z")

</div>

So being able to do `convert(Date, Day(1000))` is bad, because it is inherently an ill-defined operation. It makes the mistake of conflating a point and a period/duration, and also it is ill-defined due to irregularities in the duration of months and years. Making this operation error would require Julia 2.0 though, right?

But if we ever make conversion of a `<:Dates.Period` to a `<:Dates.TimeType` throw an error, it would be awesome if the error-text was along the lines of

> That operation is ill-defined, because it is converting a period of time to a point in time. Concider finding a point in time away from a reference-point, as in `Dates(0) + Day(1000)`.

As opposed to some obscure method error.

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [November 2, 2023, 5:50pm UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/9 "2023-11-02T17:50:25Z")

</div>

> [@TheLateKronos](#):
>
> Making this operation error would require Julia 2.0 though, right?

no, but it might require `Dates` 2.0

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [November 2, 2023, 6:03pm UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/10 "2023-11-02T18:03:53Z")

</div>

To the general point about `convert` vs. the constructor, the difference is described in the manual: [Conversion and Promotion · The Julia Language](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#Conversion-vs.-Construction)

---

<div class="post-metadata">

**Author:** ![TheLateKronos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thelatekronos/32/12824_2.png) [@TheLateKronos](https://discourse.julialang.org/u/TheLateKronos)\
**Post date:** [November 2, 2023, 7:57pm UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/11 "2023-11-02T19:57:22Z")

</div>

Oh wow, that is spot on. Thanks!

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [November 2, 2023, 8:09pm UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/12 "2023-11-02T20:09:45Z")

</div>

> [@TheLateKronos](#):
>
> This is true, but I still find it very useful to be able to express the difference between two timepoints in years. Especially when _they are years appart_ (see how natural language uses the unit of years?).

If the `Dates` supported floats, it would look like `Year(Day(1234)) == Year(3.38)` (:  
It doesn’t though, and you may find external packages useful and convenient for that:

```julia
julia> using Dates, DateFormats

julia> Day(1234) /ₜ Year
3.3785772466238186

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [November 3, 2023, 8:03am UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/13 "2023-11-03T08:03:46Z")

</div>

> [@TheLateKronos](#):
>
> how many years [months, days, h, min, s, μs] between two events

Here is [a solution to this problem that calls Python packages](https://discourse.julialang.org/t/how-to-decompose-a-dateperiod-or-timeperiod-in-tuple-of-y-m-d-h-m-s-s/74929/4).

At the time I looked at this, I could not find equivalent code in Julia.

---

<div class="post-metadata">

**Author:** ![sostock](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sostock/32/5546_2.png) [@sostock](https://discourse.julialang.org/u/sostock)\
**Post date:** [November 3, 2023, 1:22pm UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/14 "2023-11-03T13:22:50Z")

</div>

If you just want the number of years, you can use Unitful, because it can convert `Dates.Day` and other periods to Unitful quantities:

```julia
julia> using Dates, Unitful

julia> Δd = Day(12619)
12619 days

julia> uconvert(u"yr", Δd) # a `yr` equals 365.25 days
50476//1461 yr

julia> float(ans)
34.548939082819984 yr

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [November 3, 2023, 1:32pm UTC](https://discourse.julialang.org/t/type-val-vs-convert-type-val-converting-more-than-365-days-to-months-and-years/105684/15 "2023-11-03T13:32:37Z")

</div>

Among other things, the Python code takes into account leap years.
