From henr|k@bengt@@on @end|ng |rom gm@||@com  Thu Feb  8 18:23:25 2024
From: henr|k@bengt@@on @end|ng |rom gm@||@com (Henrik Bengtsson)
Date: Thu, 8 Feb 2024 09:23:25 -0800
Subject: [Rd] round.Date and trunc.Date not working / implemented
In-Reply-To: <4241f2e5-71bf-4b68-adc9-6f69af371206@sapo.pt>
References: <ab3376ac-5694-4a53-9606-c11bd97a4f0a@gmail.com>
 <26052.57850.412172.408639@stat.math.ethz.ch>
 <BE1306E2-32F4-4AD1-ACE1-C91D503203E4@b-data.ch>
 <4241f2e5-71bf-4b68-adc9-6f69af371206@sapo.pt>
Message-ID: <CAFDcVCTtMK3OPhRT3N-piGwxwfZgbydcofE4-K_am3J+y9ZY7Q@mail.gmail.com>

Technically, there is a round() for 'Date' objects, but it doesn't
seem very useful, because it basically just fall back to the default
round() method, which only takes the 'digits' argument.

Here's an example:

> date <- Sys.Date()
> class(date)
[1] "Date"

We see that there are only two round() methods in addition to the
implicit built-in one;

> methods("round")
[1] round.Date   round.POSIXt
see '?methods' for accessing help and source code

Looking at round() for 'Date';

> round.Date
function (x, ...)
{
    .Date(NextMethod(), oldClass(x))
}
<environment: namespace:base>

we see that it defers to the next method here, which is the built-in
one. The built-in one, only accepts 'digits', which does nothing for
digits >= 0.  For digits < 0, it rounds to power of ten, e.g.

> date
[1] "2024-02-08"
> round(date, digits = 0)
[1] "2024-02-08"
> round(date, digits = 1)
[1] "2024-02-08"
> round(date, digits = 2)
[1] "2024-02-08"
> round(date, digits = -1)
[1] "2024-02-07"
> round(date, digits = -2)
[1] "2024-03-18"
> round(date, digits = -3)
[1] "2024-10-04"
> round(date, digits = -4)
[1] "2024-10-04"
> round(date, digits = -5)
[1] "1970-01-01"

So, although technically invalid, OPs remark is a valid one. I'd also
expect `round()` for Date to support 'units' similar to timestamps,
e.g.

> time <- Sys.time()
> class(time)
[1] "POSIXct" "POSIXt"
> time
[1] "2024-02-08 09:17:02 PST"
> round(time, units = "days")
[1] "2024-02-08 PST"
> round(time, units = "months")
[1] "2024-02-01 PST"
> round(time, units = "years")
[1] "2024-01-01 PST"

So, I agree with OP that one would expect:

> round(date, units = "days")
[1] "2024-02-08"
> round(date, units = "months")
[1] "2024-02-01"
> round(date, units = "years")
[1] "2024-01-01"

to also work here.

FWIW, I don't think we want to encourage circumventing the S3 generic
and calling S3 methods directly, i.e. I don't recommend doing things
like round.POSIXt(...). Ideally, all S3 methods in R would be
non-exported, but some remain exported for legacy reason. But, I think
we should treat them as if they in the future will become
non-exported.

/Henrik

On Thu, Feb 8, 2024 at 8:18?AM Olivier Benz via R-devel
<r-devel at r-project.org> wrote:
>
> > On 8 Feb 2024, at 15:15, Martin Maechler <maechler at stat.math.ethz.ch> wrote:
> >
> >>>>>> Ji?? Moravec
> >>>>>>    on Wed, 7 Feb 2024 10:23:15 +1300 writes:
> >
> >> This is my first time working with dates, so if the answer is "Duh, work
> >> with POSIXt", please ignore it.
> >
> >> Why is not `round.Date` and `trunc.Date` "implemented" for `Date`?
> >
> >> Is this because `Date` is (mostly) a virtual class setup for a better
> >> inheritance or is that something that is just missing? (like
> >> `sort.data.frame`). Would R core welcome a patch?
> >
> >> I decided to convert some dates to date using `as.Date` function, which
> >> converts to a plain `Date` class, because that felt natural.
> >
> >> But then when trying to round to closest year, I have realized that the
> >> `round` and `trunc` for `Date` do not behave as for `POSIXt`.
> >
> >> I would assume that these will have equivalent output:
> >
> >> Sys.time() |> round("years") # 2024-01-01 NZDT
> >
> >> Sys.Date() |> round("years") # Error in round.default(...): non-numeric
> >> argument to mathematical function
> >
> >
> >> Looking at the code (and reading the documentation more carefully) shows
> >> the issue, but this looks like an omission that should be patched.
> >
> >> -- Jirka
> >
> > You are wrong:  They *are* implemented,
> > both even visible since they are in the 'base' package!
> >
> > ==> they have help pages you can read ....
> >
> > Here are examples:
> >
> >> trunc(Sys.Date())
> > [1] "2024-02-08"
> >> trunc(Sys.Date(), "month")
> > [1] "2024-02-01"
> >> trunc(Sys.Date(), "year")
> > [1] "2024-01-01"
> >>
> >
>
> Maybe he meant
>
> r$> Sys.time() |> round.POSIXt("years")
> [1] "2024-01-01 CET"
>
> r$> Sys.Date() |> round.POSIXt("years")
> [1] "2024-01-01 UTC"
>
> The only difference is the timezone
>
> > ______________________________________________
> > R-devel at r-project.org mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-devel
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

On Thu, Feb 8, 2024 at 9:06?AM Rui Barradas <ruipbarradas at sapo.pt> wrote:
>
> ?s 14:36 de 08/02/2024, Olivier Benz via R-devel escreveu:
> >> On 8 Feb 2024, at 15:15, Martin Maechler <maechler at stat.math.ethz.ch> wrote:
> >>
> >>>>>>> Ji?? Moravec
> >>>>>>>     on Wed, 7 Feb 2024 10:23:15 +1300 writes:
> >>
> >>> This is my first time working with dates, so if the answer is "Duh, work
> >>> with POSIXt", please ignore it.
> >>
> >>> Why is not `round.Date` and `trunc.Date` "implemented" for `Date`?
> >>
> >>> Is this because `Date` is (mostly) a virtual class setup for a better
> >>> inheritance or is that something that is just missing? (like
> >>> `sort.data.frame`). Would R core welcome a patch?
> >>
> >>> I decided to convert some dates to date using `as.Date` function, which
> >>> converts to a plain `Date` class, because that felt natural.
> >>
> >>> But then when trying to round to closest year, I have realized that the
> >>> `round` and `trunc` for `Date` do not behave as for `POSIXt`.
> >>
> >>> I would assume that these will have equivalent output:
> >>
> >>> Sys.time() |> round("years") # 2024-01-01 NZDT
> >>
> >>> Sys.Date() |> round("years") # Error in round.default(...): non-numeric
> >>> argument to mathematical function
> >>
> >>
> >>> Looking at the code (and reading the documentation more carefully) shows
> >>> the issue, but this looks like an omission that should be patched.
> >>
> >>> -- Jirka
> >>
> >> You are wrong:  They *are* implemented,
> >> both even visible since they are in the 'base' package!
> >>
> >> ==> they have help pages you can read ....
> >>
> >> Here are examples:
> >>
> >>> trunc(Sys.Date())
> >> [1] "2024-02-08"
> >>> trunc(Sys.Date(), "month")
> >> [1] "2024-02-01"
> >>> trunc(Sys.Date(), "year")
> >> [1] "2024-01-01"
> >>>
> >>
> >
> > Maybe he meant
> >
> > r$> Sys.time() |> round.POSIXt("years")
> > [1] "2024-01-01 CET"
> >
> > r$> Sys.Date() |> round.POSIXt("years")
> > [1] "2024-01-01 UTC"
> >
> > The only difference is the timezone
> >
> >> ______________________________________________
> >> R-devel at r-project.org mailing list
> >> https://stat.ethz.ch/mailman/listinfo/r-devel
> > ______________________________________________
> > R-devel at r-project.org mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-devel
> Hello,
>
> You are right that the timezones are different but Sys.date() returns an
> object of class "Date" so the method called is not that one.
> Here an example with trunc.
>
>
> Sys.Date() |> class()
> Sys.Date() |> trunc("years")
> Sys.Date() |> trunc.Date("years")
> Sys.Date() |> trunc.POSIXt("years")
>
>
> As for the OP, the problem is thhat the generic roun())) doesn't have
> unit argument. So I am  nnnot understanding why round.POSIXt works.
>
>
> Sys.Date() |> round("years")
> #> Error in round.default(structure(19761, class = "Date"), "years"):
> non-numeric argument to mathematical function
> Sys.Date() |> round.Date("years")
> #> Error in NextMethod(): generic function not specified
>
> Sys.Date() |> round.POSIXt("years")
> #> [1] "2024-01-01 UTC"
> Sys.Date() |> round.POSIXt("months")
> #> [1] "2024-02-01 UTC"
> Sys.Date() |> round.POSIXt("days")
> #> [1] "2024-02-08 UTC"
>
>
> Hope this helps,
>
> Rui Barradas
>
>
>
> --
> Este e-mail foi analisado pelo software antiv?rus AVG para verificar a presen?a de v?rus.
> www.avg.com
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



[Rd] round.Date and trunc.Date not working / implemented
Henrik Bengtsson