Duncan Murdoch
2024-Feb-08 18:03 UTC
[Rd] round.Date and trunc.Date not working / implemented
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 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 > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel
Jiří Moravec
2024-Feb-09 00:58 UTC
[Rd] round.Date and trunc.Date not working / implemented
> This is a workaround, and could be the basis for a round.Dateimprovement: >?? date <- Sys.Date() >?? as.Date(round(as.POSIXct(date), "years")) >?? as.Date(round(as.POSIXct(Sys.Date() + 180), "years")) > Duncan Murdoch That would work, perhaps structured similarly as `trunc.Date` is. The only issue might be that `trunc.Date` is currently using `round.Date` in its numeric form likely to prevent ?expensive? conversion to POSIXt when it is not required. > trunc.Date > function (x, units = c("secs", "mins", "hours", "days", "months", >? ?? "years"), ...) > { >??? units <- match.arg(units) >??? if (units == "months" || units == "years") >??????? as.Date(trunc.POSIXt(x, units, ...)) >??? else round(x - 0.4999999) > } Perhaps the working version of `round.Date` could be: ? round.Date = function(x, units = c("secs", "mins", "hours", "days", "months", "years")){ ??? units = match.arg(units) ??? if (units == "months" || units == "years") ??? ? as.Date(round.POSIXt(x, units, ...)) ??? else .Date(round(as.numeric(x))) ? } Or perhaps `unclass` instead of `as.numeric`. Since the default `units` for round(x) evaluates to `sec`, this should correctly skip the first condition in `round` and get to the correct numeric rounding. Perhaps the `trunc.Date` should be modified as well so that the call to `round.Date` is skipped in favour of internal `round.numeric`, saving few cycles. -- Jirka
Maybe Matching Threads
- round.Date and trunc.Date not working / implemented
- round.Date and trunc.Date not working / implemented
- round.Date and trunc.Date not working / implemented
- round.Date and trunc.Date not working / implemented
- round.Date and trunc.Date not working / implemented