This is a workaround, and could be the basis for a round.Date improvement:

  date <- Sys.Date()

  as.Date(round(as.POSIXct(date), "years"))

  as.Date(round(as.POSIXct(Sys.Date() + 180), "years"))

Duncan Murdoch

On 08/02/2024 12:23 p.m., Henrik Bengtsson wrote:
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@r-project.org> wrote:

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

On Thu, Feb 8, 2024 at 9:06 AM Rui Barradas <ruipbarra...@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 <maech...@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@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
______________________________________________
R-devel@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@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to