From murdoch@dunc@n @end|ng |rom gm@||@com  Thu Feb  8 19:03:40 2024
From: murdoch@dunc@n @end|ng |rom gm@||@com (Duncan Murdoch)
Date: Thu, 8 Feb 2024 13:03:40 -0500
Subject: [Rd] round.Date and trunc.Date not working / implemented
In-Reply-To: <CAFDcVCTtMK3OPhRT3N-piGwxwfZgbydcofE4-K_am3J+y9ZY7Q@mail.gmail.com>
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>
 <CAFDcVCTtMK3OPhRT3N-piGwxwfZgbydcofE4-K_am3J+y9ZY7Q@mail.gmail.com>
Message-ID: <41265ce9-5a0c-4e38-af69-461e065ab81f@gmail.com>

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



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