Ops.Date <- function (e1, e2)
{
if (nargs() == 1)
stop("unary ", .Generic, " not defined for Date objects")
boolean <- switch(.Generic, "<" = , ">" = , "==" = , "!=" = ,
"<=" = , ">=" = TRUE, FALSE)
if (!boolean)
stop(.Generic, " not defined for Date objects")
+ if (!nchar(e1)) e1 <- as.Date(e1)
+ if (!nchar(e2)) e2 <- as.Date(e2)
NextMethod(.Generic)
}
adding the above two lines to Ops.Date makes, e.g.
as.Date("1999-12-13") == "1999-06-14"
behave as "expected".
Does it seem like a good idea?
(I was inspired by a student's confusion, and by
the fact that Ops.factor does a similar thing -- although
in this case it seems more sensible to promote the
character to a Date rather than demoting the Date
to a character (in which case comparisons might not
work right?))
Similar questions might apply to Ops.POSIXt ...
Ben Bolker
Ops.Date: promote characters to Dates?
5 messages · Ben Bolker, Gabor Grothendieck, Brian Ripley
Note that the first argument still cannot be character since Ops.Date won't get dispatched in that case.
On 6/24/06, Ben Bolker <bolker at ufl.edu> wrote:
Ops.Date <- function (e1, e2)
{
if (nargs() == 1)
stop("unary ", .Generic, " not defined for Date objects")
boolean <- switch(.Generic, "<" = , ">" = , "==" = , "!=" = ,
"<=" = , ">=" = TRUE, FALSE)
if (!boolean)
stop(.Generic, " not defined for Date objects")
+ if (!nchar(e1)) e1 <- as.Date(e1)
+ if (!nchar(e2)) e2 <- as.Date(e2)
NextMethod(.Generic)
}
adding the above two lines to Ops.Date makes, e.g.
as.Date("1999-12-13") == "1999-06-14"
behave as "expected".
Does it seem like a good idea?
(I was inspired by a student's confusion, and by
the fact that Ops.factor does a similar thing -- although
in this case it seems more sensible to promote the
character to a Date rather than demoting the Date
to a character (in which case comparisons might not
work right?))
Similar questions might apply to Ops.POSIXt ...
Ben Bolker
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
1 day later
Believe it or not, it works either way: I haven't fully
figured out the logic yet (except to note that I had the
logic reversed below):
Ops.Date <- function (e1, e2)
{
if (nargs() == 1)
stop("unary ", .Generic, " not defined for Date objects")
boolean <- switch(.Generic, "<" = , ">" = , "==" = , "!=" = ,
"<=" = , ">=" = TRUE, FALSE)
if (!boolean)
stop(.Generic, " not defined for Date objects")
if (nchar(e1)) e1 <- as.Date(e1)
if (nchar(e2)) e2 <- as.Date(e2)
NextMethod(.Generic)
}
datechar1 = "1999-12-03"
datechar2 = "2000-12-07"
date1 = as.Date(datechar1)
date2 = as.Date(datechar2)
date1 == datechar1
datechar1 == date1
datechar1 < date2
date2 > datechar1
I also propose
as.Date.numeric <- function(x, ...) {
class(x) <- "Date"
x
}
this takes a number of seconds since 1970 and
converts it into a Date object ...
cheers
Ben
Gabor Grothendieck wrote:
Note that the first argument still cannot be character since Ops.Date won't get dispatched in that case. On 6/24/06, Ben Bolker <bolker at ufl.edu> wrote:
Ops.Date <- function (e1, e2)
{
if (nargs() == 1)
stop("unary ", .Generic, " not defined for Date objects")
boolean <- switch(.Generic, "<" = , ">" = , "==" = , "!=" = ,
"<=" = , ">=" = TRUE, FALSE)
if (!boolean)
stop(.Generic, " not defined for Date objects")
+ if (!nchar(e1)) e1 <- as.Date(e1)
+ if (!nchar(e2)) e2 <- as.Date(e2)
NextMethod(.Generic)
}
adding the above two lines to Ops.Date makes, e.g.
as.Date("1999-12-13") == "1999-06-14"
behave as "expected".
Does it seem like a good idea?
(I was inspired by a student's confusion, and by
the fact that Ops.factor does a similar thing -- although
in this case it seems more sensible to promote the
character to a Date rather than demoting the Date
to a character (in which case comparisons might not
work right?))
Similar questions might apply to Ops.POSIXt ...
Ben Bolker
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
On Sun, 25 Jun 2006, Ben Bolker wrote:
Believe it or not, it works either way: I haven't fully figured out the logic yet (except to note that I had the logic reversed below):
This is as documented (White Book p.473, referenced on the help page for
'Ops'). [Surely part of the homework that the posting guide asks for.]
I have recently been expanding the help pages for group generics (and
trying to remove some of the confusion caused by adding S4 group generics
to the page for S3 group generics). This now says (about S3 group
generics only)
2. Group '"Ops"':
* '"+"', '"-"', '"*"', '"/"', '"^"', '"%%"', '"%/%"'
* '"&"', '"|"', '"!"'
* '"=="', '"!="', '"<"', '"<="', '">="', '">"'
The classes of both arguments are considered in dispatching.
If a method is found for just one or the same method is found
for both, it is used. If different methods are found, there is
a warning about 'incompatible methods': in that case or if no
method is found for either argument the default method is used.
Ops.Date <- function (e1, e2)
{
if (nargs() == 1)
stop("unary ", .Generic, " not defined for Date objects")
boolean <- switch(.Generic, "<" = , ">" = , "==" = , "!=" = ,
"<=" = , ">=" = TRUE, FALSE)
if (!boolean)
stop(.Generic, " not defined for Date objects")
if (nchar(e1)) e1 <- as.Date(e1)
if (nchar(e2)) e2 <- as.Date(e2)
NextMethod(.Generic)
}
Eh? nchar is non-zero for almost all objects to be passed through here, including any coercible to Date. (Remember nchar will itself coerce to character.) And nchar(e1) will be a vector, not a scalar: perhaps is.character(e1) was what was intended? I believe the issue is more general: naive users (those who confuse an object with its printed representation) expect to be able to compare classed objects to character strings, and for the classed objects to be converted by as.character() when doing so. That is not what is done: coerceVector(x, STRSXP) is used internally. At some point we need to consider changing that, but it is not easy as method dispatch depends on the environment, something that is often not known when coerceVector is invoked.
datechar1 = "1999-12-03"
datechar2 = "2000-12-07"
date1 = as.Date(datechar1)
date2 = as.Date(datechar2)
date1 == datechar1
datechar1 == date1
datechar1 < date2
date2 > datechar1
I also propose
as.Date.numeric <- function(x, ...) {
class(x) <- "Date"
x
}
this takes a number of seconds since 1970 and
converts it into a Date object ...
That it would not do so is further evidence of the good reasons for not providing such a method for people to misinterpret. (It would be the number of days since 1970-01-01, but probably one would want to take floor() of a number here.)
cheers
Ben
Gabor Grothendieck wrote:
Note that the first argument still cannot be character since Ops.Date won't get dispatched in that case. On 6/24/06, Ben Bolker <bolker at ufl.edu> wrote:
Ops.Date <- function (e1, e2)
{
if (nargs() == 1)
stop("unary ", .Generic, " not defined for Date objects")
boolean <- switch(.Generic, "<" = , ">" = , "==" = , "!=" = ,
"<=" = , ">=" = TRUE, FALSE)
if (!boolean)
stop(.Generic, " not defined for Date objects")
+ if (!nchar(e1)) e1 <- as.Date(e1)
+ if (!nchar(e2)) e2 <- as.Date(e2)
NextMethod(.Generic)
}
adding the above two lines to Ops.Date makes, e.g.
as.Date("1999-12-13") == "1999-06-14"
behave as "expected".
Depends who is doing the expecting ....
Does it seem like a good idea? (I was inspired by a student's confusion, and by the fact that Ops.factor does a similar thing -- although in this case it seems more sensible to promote the character to a Date rather than demoting the Date to a character (in which case comparisons might not work right?)) Similar questions might apply to Ops.POSIXt ... Ben Bolker
______________________________________________ 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
Brian D. Ripley, ripley at stats.ox.ac.uk Professor of Applied Statistics, http://www.stats.ox.ac.uk/~ripley/ University of Oxford, Tel: +44 1865 272861 (self) 1 South Parks Road, +44 1865 272866 (PA) Oxford OX1 3TG, UK Fax: +44 1865 272595
Prof Brian Ripley wrote:
On Sun, 25 Jun 2006, Ben Bolker wrote:
Eh? nchar is non-zero for almost all objects to be passed through here, including any coercible to Date. (Remember nchar will itself coerce to character.) And nchar(e1) will be a vector, not a scalar: perhaps is.character(e1) was what was intended?
Yes. I was following Ops.factor too closely and not thinking carefully enough.
I believe the issue is more general: naive users (those who confuse an object with its printed representation) expect to be able to compare classed objects to character strings, and for the classed objects to be converted by as.character() when doing so.
(My suggestion actually went the other way, converting the character string to a date: I think the results would be the same in this case since the particular character representation yyyy-mm-dd sorts in the same order as dates ...) That is not what is done:
coerceVector(x, STRSXP) is used internally. At some point we need to consider changing that, but it is not easy as method dispatch depends on the environment, something that is often not known when coerceVector is invoked.
[snip as.numeric.Date]
this takes a number of seconds since 1970 and converts it into a Date object ...
That it would not do so is further evidence of the good reasons for not providing such a method for people to misinterpret. (It would be the number of days since 1970-01-01, but probably one would want to take floor() of a number here.)
oops again: typo.
I think my main point is that there are several aspects of working
with dates at this point that are confusing to the naive user, and
it would be nice if there were a consistent way to make them
less confusing without breaking anything. I only offered the
suggestions above to try to start a conversation about it.
For example, not only is
"1999-12-02"==as.Date("1999-12-03")
FALSE, but so is
"1999-12-02"<as.Date("1999-12-03")
(I believe it is equivalent to
"1999-12-02"<as.character(as.numeric(as.Date("1999-12-03")))
You could just say "don't do that"; I would submit that it is
a reasonable thing for a naive user to do (particularly when
they have been conditioned by having a similar strategy
work for factors) and could get them
into trouble.
cheers
Ben Bolker