Skip to content

Commit 6d3e49d

Browse files
author
maechler
committed
seq.Date() no longer coerces to double unnecessarily
git-svn-id: https://svn.r-project.org/R/trunk@87284 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 91a84c0 commit 6d3e49d

File tree

5 files changed

+58
-41
lines changed

5 files changed

+58
-41
lines changed

doc/NEWS.Rd

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@
292292
\item \code{update_pkg_po()} now copies \file{.mo} files to the
293293
\pkg{translation} package even if a \file{DESCRIPTION} file
294294
exists, thanks to \I{Michael Chirico} fixing \PR{18694}.
295-
295+
296296
\item Auto-generated \code{citation()} entries no longer include
297297
(additional) URLs in the \samp{note} field (\PR{18547}).
298298
@@ -343,6 +343,11 @@
343343
\item \code{rowSums(A, dims = dd)}, \code{colMeans(..)}, etc, give a
344344
more helpful error message when \code{dd} is not of length one,
345345
thanks to \I{Michael Chirico}'s \PR{18811}.
346+
347+
\item \code{seq.Date()} no longer explicitly coerces results from
348+
integer to double, analogously with \code{seq.default()},
349+
\code{seq.int()} and \code{seq.POSIXt()}, resolving a \emph{modified}
350+
\PR{18782}.
346351
}
347352
}
348353
}

src/library/base/R/dates.R

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -255,22 +255,21 @@ seq.Date <- function(from, to, by, length.out = NULL, along.with = NULL, ...)
255255
if (length(length.out) != 1L) stop("'length.out' must be of length 1")
256256
length.out <- ceiling(length.out)
257257
}
258+
if (!missing(to) && missing(by)) {
259+
from <- as.integer(as.Date(from))
260+
to <- as.integer(as.Date(to))
261+
res <- seq.int(from, to, length.out = length.out)
262+
return(.Date(res))
263+
}
264+
## else
258265
status <- c(!missing(to), !missing(by), !is.null(length.out))
259266
if(sum(status) != 2L)
260267
stop("exactly two of 'to', 'by' and 'length.out' / 'along.with' must be specified")
261-
if (missing(by)) {
262-
from <- unclass(as.Date(from))
263-
to <- unclass(as.Date(to))
264-
res <- seq.int(from, to, length.out = length.out)
265-
## force double storage for consistency
266-
return(.Date(as.numeric(res)))
267-
}
268-
269268
if (length(by) != 1L) stop("'by' must be of length 1")
270269
valid <- 0L
271270
if (inherits(by, "difftime")) {
272271
by <- switch(attr(by,"units"), secs = 1/86400, mins = 1/1440,
273-
hours = 1/24, days = 1, weeks = 7) * unclass(by)
272+
hours = 1/24, days = 1, weeks = 7) * as.integer(by)
274273
} else if(is.character(by)) {
275274
by2 <- strsplit(by, " ", fixed = TRUE)[[1L]]
276275
if(length(by2) > 2L || length(by2) < 1L)
@@ -279,44 +278,37 @@ seq.Date <- function(from, to, by, length.out = NULL, along.with = NULL, ...)
279278
c("days", "weeks", "months", "quarters", "years"))
280279
if(is.na(valid)) stop("invalid string for 'by'")
281280
if(valid <= 2L) {
282-
by <- c(1, 7)[valid]
281+
by <- c(1L, 7L)[valid]
283282
if (length(by2) == 2L) by <- by * as.integer(by2[1L])
284283
} else
285-
by <- if(length(by2) == 2L) as.integer(by2[1L]) else 1
284+
by <- if(length(by2) == 2L) as.integer(by2[1L]) else 1L
286285
} else if(!is.numeric(by)) stop("invalid mode for 'by'")
287286
if(is.na(by)) stop("'by' is NA")
288287

289288
if(valid <= 2L) { # days or weeks
290-
from <- unclass(as.Date(from))
291-
if(!is.null(length.out))
292-
res <- seq.int(from, by = by, length.out = length.out)
293-
else {
294-
to0 <- unclass(as.Date(to))
295-
## defeat test in seq.default
296-
res <- seq.int(0, to0 - from, by) + from
297-
}
298-
## force double storage for consistency
299-
res <- .Date(as.numeric(res))
289+
from <- as.integer(as.Date(from))
290+
res <- .Date(if(!is.null(length.out))
291+
seq.int(from, by = by, length.out = length.out)
292+
else # defeat test in seq.default
293+
seq.int(0L, as.integer(as.Date(to)) - from, by) + from)
300294
} else { # months or quarters or years
301295
r1 <- as.POSIXlt(from)
302296
if(valid == 5L) { # years
303-
if(missing(to)) {
304-
yr <- seq.int(r1$year, by = by, length.out = length.out)
305-
} else {
306-
to0 <- as.POSIXlt(to)
307-
yr <- seq.int(r1$year, to0$year, by)
308-
}
309-
r1$year <- yr
297+
r1$year <-
298+
if(missing(to))
299+
seq.int(r1$year, by = by, length.out = length.out)
300+
else
301+
seq.int(r1$year, as.POSIXlt(to)$year, by)
310302
res <- as.Date(r1)
311303
} else { # months or quarters
312-
if (valid == 4L) by <- by * 3
313-
if(missing(to)) {
314-
mon <- seq.int(r1$mon, by = by, length.out = length.out)
315-
} else {
316-
to0 <- as.POSIXlt(to)
317-
mon <- seq.int(r1$mon, 12*(to0$year - r1$year) + to0$mon, by)
318-
}
319-
r1$mon <- mon
304+
if (valid == 4L) by <- by * 3L
305+
r1$mon <-
306+
if(missing(to))
307+
seq.int(r1$mon, by = by, length.out = length.out)
308+
else {
309+
to0 <- as.POSIXlt(to)
310+
seq.int(r1$mon, 12L*(to0$year - r1$year) + to0$mon, by)
311+
}
320312
res <- as.Date(r1)
321313
}
322314
}

src/library/base/man/seq.Date.Rd

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
% File src/library/base/man/seq.Date.Rd
22
% Part of the R package, https://www.R-project.org
3-
% Copyright 1995-2017 R Core Team
3+
% Copyright 1995-2024 R Core Team
44
% Distributed under GPL 2 or later
55

66
\name{seq.Date}
@@ -32,10 +32,14 @@
3232
and a space, or followed by \code{"s"}.
3333

3434
See \code{\link{seq.POSIXt}} for the details of \code{"month"}.
35+
36+
In the case \code{seq(from, to)}, the default for \code{by} is
37+
\code{"day"} (or \code{"1 day"}).
3538
}
3639
}
3740
\value{
3841
A vector of class \code{"Date"}.
42+
Type \code{"\link{integer}"} is preserved.
3943
}
4044
\seealso{\code{\link{Date}}}
4145

tests/datetime3.R

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,18 @@ stopifnot(exprs = {
588588
grepl('x[, "yday"]', print(tryCmsg(pl[["yday"]])))# new error msg
589589
})
590590

591+
## seq.Date() should preserve integer, seq(from, to) should work (default by = "1 day")
592+
D1 <- .Date(i1 <- 11111L)
593+
D2 <- .Date(i2 <- 11123L)
594+
D3 <- .Date(i3 <- 12345L)
595+
(seq1 <- seq(D1, D2))# 'by = "days" is now default
596+
head(seq3 <- seq(D1,D3, by = "weeks"))
597+
stopifnot(exprs = {
598+
identical(c("2000-06-03", "2000-06-15"), format(c(D1,D2)))
599+
identical(unclass(seq1), i1:i2) # preserve integer type
600+
typeof(seq3) == "integer"
601+
})
602+
591603

592604

593605
## keep at end

tests/reg-tests-1d.R

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -646,10 +646,14 @@ D1 <- as.Date("2017-01-06")
646646
D2 <- as.Date("2017-01-12")
647647
seqD1 <- seq.Date(D1, D2, by = "1 day")
648648
stopifnot(exprs = {
649+
identical(seqD1, seq(D1, D2)) # by = "days" now implicit default
649650
identical(seqD1, seq(D1, D2, by = "1 days"))
650-
## These two work "accidentally" via seq -> seq.default + "Date"-arithmetic
651-
identical(seqD1, seq(by = 1, from = D1, length.out = 7))
652-
identical(seqD1, seq(by = 1, to = D2, length.out = 7))
651+
## These work "accidentally" via seq -> seq.default + "Date"-arithmetic (but *not* seq.Date):
652+
## are equal, but 2nd is "double"
653+
seqD1 == seq(by = 1, from = D1, length.out = 7)
654+
seqD1 == seq(by = 1, to = D2, length.out = 7)
655+
seqD1 == seq(by = 1L, to = D2, length.out = 7)
656+
## not (yet) identical(seqD1, seq(by = 1L, from = D1, length.out = 7))
653657
## swap order of (by, to) ==> *FAILS* because directly calls seq.Date() - FIXME?
654658
TRUE ||
655659
identical(seqD1, seq(to = D2, by = 1, length.out = 7))

0 commit comments

Comments
 (0)