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

Henrik Bengtsson henr|k@bengt@@on @end|ng |rom gm@||@com
Thu Feb 8 18:23:25 CET 2024


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 using r-project.org> wrote:
>
> > On 8 Feb 2024, at 15:15, Martin Maechler <maechler using 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 using r-project.org mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-devel
> ______________________________________________
> R-devel using 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 using 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 using 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 using r-project.org mailing list
> >> https://stat.ethz.ch/mailman/listinfo/r-devel
> > ______________________________________________
> > R-devel using 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 using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list