# Replace date year

**URL:** <https://discourse.julialang.org/t/replace-date-year/68301>\
**Category:** General Usage\
**Tags:** dates, mutable-structure, accessors\
**Created:** [September 17, 2021, 4:22am UTC](https://discourse.julialang.org/t/replace-date-year/68301 "2021-09-17T04:22:09Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [September 17, 2021, 4:22am UTC](https://discourse.julialang.org/t/replace-date-year/68301/1 "2021-09-17T04:22:09Z")

</div>

```julia
d = Date(2010,01,01)

```

How can I replace the year with 2011?

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [September 17, 2021, 4:57am UTC](https://discourse.julialang.org/t/replace-date-year/68301/2 "2021-09-17T04:57:17Z")

</div>

```julia
julia> using Dates

julia> d= Date(2010,01,01)
2010-01-01

julia> d = d + Year(1)
2011-01-01

```

```julia

julia> using Dates

julia> adate = Date(2010,01,01)
2010-01-01
julia> ayear, amonth, aday = yearmonthday(adate)
(2010, 1, 1)

julia> a2011date = Date(2011, amonth, aday)
2011-01-01

```

---

<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:** [September 17, 2021, 8:15am UTC](https://discourse.julialang.org/t/replace-date-year/68301/3 "2021-09-17T08:15:25Z")

</div>

According to the docs, dates’ objects are immutable `Int64` wrappers, so it seems that they cannot be replaced (in place) but have to be re-constructed.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [September 17, 2021, 12:50pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/4 "2021-09-17T12:50:24Z")

</div>

That is correct. The best we can do is to reassign a revised date to the same var.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [September 17, 2021, 6:45pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/5 "2021-09-17T18:45:26Z")

</div>

I don’t want to change it in place. I want something like

```julia
d = Date(2010,01,01)
new_date = replace(d, year=1999)

```

Is there a function or package that supports this kind of thing?

BangBang.jl and SetField.jl do it for some structs, but `Date` doesn’t have a `year` field so those don’t work.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [September 17, 2021, 7:15pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/7 "2021-09-17T19:15:18Z")

</div>

```julia
>> replaceparts(d::Date; year=year(d), month=month(d), day=day(d)) = typeof(d)(year, month, day)
>> replaceparts(Date(2001,01,01), month=4)
2001-04-01

```

This works, though maybe there’s a better way via ConstructionBase/BangBang. I’m not sure how to use those packages without piracy. (cc @tkf @jw3126 if you happen to have any thoughts)

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [September 17, 2021, 7:33pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/8 "2021-09-17T19:33:11Z")

</div>

How about this?

```julia
julia> t = Date(2001,01,01);

julia> t_new = t + Year(1)
2002-01-01

```

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [September 17, 2021, 7:44pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/9 "2021-09-17T19:44:58Z")

</div>

That was suggested above but I don’t want the output year to depend on the input year.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [September 17, 2021, 7:46pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/10 "2021-09-17T19:46:09Z")

</div>

It shouldn’t be hard to write a function for that though

```julia
new_year(d::Date, y)
    diff = year(d) - y
    return d + Year(diff)
end

```

---

<div class="post-metadata">

**Author:** ![lbilli](https://avatars.discourse-cdn.com/v4/letter/l/59ef9b/32.png) [@lbilli](https://discourse.julialang.org/u/lbilli)\
**Post date:** [September 17, 2021, 7:46pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/11 "2021-09-17T19:46:46Z")

</div>

What about:

```julia
julia> replaceyear(d, y) = Date(y, monthday(d)...)

julia> replaceyear(today(), 2000)
2000-09-17

```

---

<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:** [September 17, 2021, 8:12pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/12 "2021-09-17T20:12:15Z")

</div>

> [@jzr](#):
>
> `replaceparts(d::Date; year=year(d), month=month(d), day=day(d)) = typeof(d)(year, month, day)`

Your solution looks really nice.

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [September 18, 2021, 6:37pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/13 "2021-09-18T18:37:06Z")

</div>

@jzr Since `year` is not a property of `Date`:

```julia
julia> using Dates

julia> d = Date(2021, 9, 18)
2021-09-18

julia> d.year
ERROR: type Date has no field year

```

I would rather not use `ConstructionBase`. Instead, the appropriate way to get the year is the `year` function. So in my view the appropriate way to set `year` would be to overload [Accessors.set](https://github.com/JuliaObjects/Accessors.jl):

```julia

julia> using Accessors, Dates

julia> Accessors.set(d::Date, ::typeof(year), y) = Date(y, month(d), day(d))

julia> d = Date(2021, 9, 18)
2021-09-18

julia> @set year(d) = 2022
2022-09-18

```

This makes things insanely composable and for instance gives nested updates for free:

```julia
julia> struct Person; name::String; birth::Date; end

julia> p = Person("Julia", Date(2009, 8, 22))
Person("Julia", Date("2009-08-22"))

julia> @set year(p.birth) = 123
Person("Julia", Date("0123-08-22"))

```

If you like this solution, a PR to Accessors would be welcome.

---

<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:** [September 18, 2021, 7:47pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/14 "2021-09-18T19:47:32Z")

</div>

@jw3126, this looks amazing (linking also your nice [JuliaCon2020 talk on Setfields.jl](https://youtu.be/vkAOYeTpLg0)).

In order to set year, month and day, do we need to write three times the Accessors.set constructor, as per your example, or is there a one-line option?

Thank you.

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [September 19, 2021, 6:31pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/15 "2021-09-19T18:31:03Z")

</div>

> In order to set year, month and day, do we need to write three times the Accessors.set constructor, as per your example, or is there a one-line option?

In this very special case, `Date(year, month, day)` is the way to set all three, but in general, the answer is “not automatically”. Since there is no “getter” function that returns all three, it is awkward to provide a setter function for all three. You could of course provide your own getter function and match it with a setter like so:

```julia
ymd(d::Date) = year(d), month(d), day(d)
Accessors.set(::Date, ::typeof(ymd), (y,m,d)) = Date(y,m,d)

```

This again gives you composability and allows things like `@set ymd(person.birth) = (2021, 10, 2)`.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [September 19, 2021, 6:39pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/16 "2021-09-19T18:39:47Z")

</div>

> [@jw3126](#):
>
> Since there is no “getter” function that returns all three

There is

```julia
  yearmonthday(dt::TimeType) -> (Int64, Int64, Int64)

  Simultaneously return the year, month and day parts of a Date or DateTime.

```

---

<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:** [September 19, 2021, 7:12pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/17 "2021-09-19T19:12:14Z")

</div>

Completely overwhelmed by this computer science, but totally amazed at how it works:

```julia
using Accessors, Dates

Accessors.set(::Date, ::typeof(yearmonthday), (y,m,d)) = Date(y,m,d)
struct Person; name::String; birth::Date; end

p = Person("Julia", Date(2009, 8, 22))

julia> @set yearmonthday(p.birth) = (2021, 10, 2)
Person("Julia", Date("2021-10-02"))

```

Thank you.

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [September 19, 2021, 7:27pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/18 "2021-09-19T19:27:31Z")

</div>

@rafael.guerra would be awesome if you could PR this to Accessors.jl.

---

<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:** [September 19, 2021, 7:29pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/19 "2021-09-19T19:29:04Z")

</div>

Would be glad to but @jzr has all the merit on this and is much more knowledgeable than me.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [September 19, 2021, 8:26pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/20 "2021-09-19T20:26:06Z")

</div>

What would be the Accessors version of this, which supports setting any 1, 2, or 3 attributes at once?

```julia
>> replaceparts(d::Date; year=year(d), month=month(d), day=day(d)) = typeof(d)(year, month, day)
>> replaceparts(Date(2001,01,01), month=4)

```

```julia

julia> Accessors.set(d::Date, ::typeof(yearmonthday), year=year(d), month=month(d), day=day(d)) = Date(year, month, day)

julia> d = Date(2000,01,01)
2000-01-01

julia> @set year(d) = 1999 month(d) = 4
ERROR: LoadError: MethodError: no method matching var"@set"(::LineNumberNode, ::Module, ::Expr, ::Expr)

```

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [September 19, 2021, 8:44pm UTC](https://discourse.julialang.org/t/replace-date-year/68301/21 "2021-09-19T20:44:28Z")

</div>

The idea is that `Accessors` provides a setter for each existing `Dates` getter. So all of the following should be overloaded:

```julia
set(d::Date, ::typeof(day), val) = ...
set(d::Date, ::typeof(month), val) = ...
set(d::Date, ::typeof(year), val) = ...
set(d::Date, ::typeof(monthday), val) = ...
...

```

I think it would make sense for `Accessors` to provide these.

If that is not flexible enough, you could define in your own project on top of that

```julia
parts(d::Date) = (year=year(d), month=month(d), day=day(d))
function Accessors.set(d::Date, ::typeof(parts), patch)
    Date(
        get(patch, :year, year(d)),
        get(patch, :month, month(d)),
        get(patch, :day, day(d)),
    )
end

```

Which could be used like `@set parts(person.birth) = (day=1, month=2)`. Or just stick with `replaceparts` and do

```julia
@modify(person.birth) do date
    replaceparts(date, day=1, month=2)
end

```

for nested updates.

[Next page](https://discourse.julialang.org/t/replace-date-year/68301.md?page=2)
