Nothing
#' Changes the components of a date object
#'
#' `update.Date()` and `update.POSIXt()` return a date with the specified
#' elements updated. Elements not specified will be left unaltered. update.Date
#' and update.POSIXt do not add the specified values to the existing date, they
#' substitute them for the appropriate parts of the existing date.
#'
#'
#' @name DateTimeUpdate
#' @param object a date-time object
#' @param ... named arguments: years, months, ydays, wdays, mdays, days, hours, minutes,
#' seconds, tzs (time zone component)
#' @param week_start week start day (Default is 7, Sunday. Set `lubridate.week.start` to
#' override). Full or abbreviated names of the days of the week can be in English or
#' as provided by the current locale.
#' @param simple,roll deprecated
#' @return a date object with the requested elements updated. The object will retain its
#' original class unless an element is updated which the original class does not
#' support. In this case, the date returned will be a POSIXlt date object.
#' @inheritParams timechange::time_add
#' @keywords manip chron
#' @examples
#' date <- ymd("2009-02-10")
#' update(date, year = 2010, month = 1, mday = 1)
#'
#' update(date, year = 2010, month = 13, mday = 1)
#'
#' update(date, minute = 10, second = 3)
#' @export
update.POSIXt <- function(object, ...,
roll_dst = c("NA", "post"),
week_start = getOption("lubridate.week.start", 7),
roll = NULL, simple = NULL) {
if (!is.null(simple)) roll <- simple
do.call(update_datetime, c(
list(object, week_start = week_start, roll_dst = roll_dst, roll = roll),
list(...)
))
}
update_datetime <- function(object, years = NULL, months = NULL,
days = NULL, mdays = NULL, ydays = NULL, wdays = NULL,
hours = NULL, minutes = NULL, seconds = NULL, tzs = NULL,
roll_month = "full",
roll_dst = c("NA", "post"),
roll = NULL,
week_start = 7,
exact = FALSE) {
roll_dst <- normalize_roll_dst(roll_dst, roll, 1)
week_start <- as_week_start(week_start)
if (!is.null(days)) {
if (!is.null(mdays)) {
stop("Only one of `days` and `mdays` must be supplied")
}
mdays <- days
}
updates <- list(
year = years, month = months,
mday = mdays, wday = wdays, yday = ydays,
hour = hours, minute = minutes, second = seconds
)
timechange::time_update(
object, updates = normalize_units_length(updates), tz = tzs,
roll_dst = roll_dst, roll_month = roll_month,
week_start = as_week_start(week_start),
exact = exact
)
}
normalize_units_length <- function(units) {
if (length(units) == 0)
return(units)
maxlen <- max(unlist(lapply(units, length)))
if (maxlen > 1) {
for (nm in names(units)) {
len <- length(units[[nm]])
if (len != maxlen && len > 1)
units[[nm]] <- rep_len(units[[nm]], maxlen)
}
}
units
}
as_week_start <- function(x) {
if (is.numeric(x)) {
if (x > 7 || x < 1) {
stop("Invalid 'week_start' argument; must be between 1 and 7")
}
return(x)
}
if (length(x) != 1L)
stop("Invalid `week_start` argument; must be of length 1")
if (!is.character(x))
stop("Invalid `week_start` argument; must be a number in 1-7 (Monday based) or string day of the week", call. = FALSE)
# Use pmatch to also capture abbreviations.
english_idx <- pmatch(x, c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"))
if (!is.na(english_idx)) {
return(english_idx)
}
# Other locales might use abbreviations that are not so pmatch-friendly; try full first, then partial.
native_full_idx <- match(x, .get_locale_regs()$wday_names$full)
if (!is.na(native_full_idx)) {
return(native_full_idx)
}
native_abbr_idx <- match(x, .get_locale_regs()$wday_names$abr)
if (!is.na(native_abbr_idx)) {
return(native_abbr_idx)
}
}
## prior to v1.7.0
update_posixt_old <- function(object, ..., simple = FALSE) {
if (!length(object)) {
return(object)
}
date <- as.POSIXlt(object)
## adjudicate units input
units <- list(...)
names(units) <- standardise_lt_names(names(units))
if (!is.null(new_tz <- units$tz)) {
units$tz <- NULL
}
day.units <- c("day", "wday", "mday", "yday")
wunit <- day.units %in% names(units)
if (n <- sum(wunit)) {
if (n > 1) stop("conflicting days input")
uname <- day.units[wunit]
if (uname != "mday") {
## we compute everything with mdays (operating with ydays doesn't work)
if (uname != "day") {
if (uname == "yday" & !is.null(units$year)) {
warning("Updating on both 'year' and 'yday' can lead to wrong results. See bug #319.", call. = F)
}
diff <- units[[uname]] - date[[uname]] - 1
units[[uname]] <- diff + date$mday
}
names(units)[names(units) == uname] <- "mday"
}
}
if (!is.null(units$mon)) units$mon <- units$mon - 1
if (!is.null(units$year)) units$year <- units$year - 1900
## make new date-times
date <- unclass(date)
date[names(units)] <- units
date[c("wday", "yday")] <- list(wday = NA, yday = NA)
## unbalanced POSIXlt often results in R crashes
maxlen <- max(unlist(lapply(date, length)))
if (maxlen > 1) {
for (nm in names(date)) {
if (length(date[[nm]]) != maxlen) {
date[[nm]] <- rep_len(date[[nm]], maxlen)
}
}
}
class(date) <- c("POSIXlt", "POSIXt")
if (!is.null(new_tz)) {
attr(date, "tzone") <- new_tz
}
## fit to timeline
## POSIXct format avoids negative and NA elements in POSIXlt format
fit_to_timeline(date, class(object)[[1]], simple = simple)
}
is_zero_hms <- function(hours = NULL, minutes = NULL, seconds = NULL, tzs = NULL, ...) {
is.null(tzs) &&
(is.null(hours) || sum(hours, na.rm = TRUE) == 0) &&
(is.null(minutes) || sum(minutes, na.rm = TRUE) == 0) &&
(is.null(seconds) || sum(seconds, na.rm = TRUE) == 0)
}
#' @export
update.Date <- function(object, ...) {
out <- update_datetime(object, ...)
## lubridate's missing hms component checks for actual zeros. Not a great idea as the
## return type is unpredictable but we are stuck with it.
if (is.POSIXct(out) && is_zero_hms(...))
as_date(out)
else
out
}
#' Fit a POSIXlt date-time to the timeline
#'
#' The POSIXlt format allows you to create instants that do not exist in real
#' life due to daylight savings time and other conventions. fit_to_timeline
#' matches POSIXlt date-times to a real times. If an instant does not exist, fit
#' to timeline will replace it with an NA. If an instant does exist, but has
#' been paired with an incorrect timezone/daylight savings time combination,
#' fit_to_timeline returns the instant with the correct combination.
#'
#'
#' @param lt a POSIXlt date-time object.
#' @param class a character string that describes what type of object to return,
#' POSIXlt or POSIXct. Defaults to POSIXct. This is an optimization to avoid
#' needless conversions.
#' @param simple if TRUE, \pkg{lubridate} makes no attempt to detect
#' meaningless time-dates or to correct time zones. No NAs are produced and
#' the most meaningful valid dates are returned instead. See examples.
#' @return a POSIXct or POSIXlt object that contains no illusory date-times
#'
#' @examples
#' \dontrun{
#'
#' tricky <- structure(list(
#' sec = c(5, 0, 0, -1),
#' min = c(0L, 5L, 5L, 0L),
#' hour = c(2L, 0L, 2L, 2L),
#' mday = c(4L, 4L, 14L, 4L),
#' mon = c(10L, 10L, 2L, 10L),
#' year = c(112L, 112L, 110L, 112L),
#' wday = c(0L, 0L, 0L, 0L),
#' yday = c(308L, 308L, 72L, 308L),
#' isdst = c(1L, 0L, 0L, 1L)
#' ),
#' .Names = c(
#' "sec", "min", "hour", "mday", "mon",
#' "year", "wday", "yday", "isdst"
#' ),
#' class = c("POSIXlt", "POSIXt"),
#' tzone = c("America/Chicago", "CST", "CDT")
#' )
#'
#' tricky
#' ## [1] "2012-11-04 02:00:00 CDT" Doesn't exist because clocks "fall back" to 1:00 CST
#' ## [2] "2012-11-04 00:05:00 CST" Times are still CDT, not CST at this instant
#' ## [3] "2010-03-14 02:00:00 CDT" DST gap
#' ## [4] "2012-11-04 01:59:59 CDT" Does exist, but has deceptive internal structure
#'
#' fit_to_timeline(tricky)
#' ## Returns:
#' ## [1] "2012-11-04 02:00:00 CST" instant paired with correct tz & DST combination
#' ## [2] "2012-11-04 00:05:00 CDT" instant paired with correct tz & DST combination
#' ## [3] NA - fake time changed to NA (compare to as.POSIXct(tricky))
#' ## [4] "2012-11-04 01:59:59 CDT" -real instant, left as is
#'
#' fit_to_timeline(tricky, simple = TRUE)
#' ## Returns valid time-dates by extrapolating CDT and CST zones:
#' ## [1] "2012-11-04 01:00:05 CST" "2012-11-04 01:05:00 CDT"
#' ## [3] "2010-03-14 03:05:00 CDT" "2012-11-04 01:59:59 CDT"
#' }
#' @export
fit_to_timeline <- function(lt, class = "POSIXct", simple = FALSE) {
if (class != "POSIXlt" && class != "POSIXct") {
stop("class argument must be POSIXlt or POSIXct")
}
if (simple) {
if (class == "POSIXct") {
as.POSIXct(lt)
} else {
as.POSIXlt(as.POSIXct(lt))
}
} else {
## fall break - DST only changes if it has to
ct <- as.POSIXct(lt)
lt2 <- as.POSIXlt(ct)
dstdiff <- !is.na(ct) & (lt$isdst != lt2$isdst)
if (any(dstdiff)) {
dlt <- lt[dstdiff]
dlt2 <- lt2[dstdiff]
dlt$isdst <- dlt2$isdst
dlt$zone <- dlt2$zone
dlt$gmtoff <- dlt2$gmtoff
dct <- as.POSIXct(dlt) # should directly match if not in gap
if (class == "POSIXct") {
ct[dstdiff] <- dct
} else {
lt2[dstdiff] <- dlt
}
chours <- format.POSIXlt(as.POSIXlt(dct), "%H", usetz = FALSE)
lhours <- format.POSIXlt(dlt, "%H", usetz = FALSE)
any <- any(hdiff <- chours != lhours)
if (!is.na(any) && any) {
if (class == "POSIXct") {
ct[dstdiff][hdiff] <- NA
} else {
lt2[dstdiff][hdiff] <- NA
}
}
}
if (class == "POSIXct") ct else lt2
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.