1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
|
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/naive-time.R
\name{as-zoned-time-naive-time}
\alias{as-zoned-time-naive-time}
\alias{as_zoned_time.clock_naive_time}
\title{Convert to a zoned-time from a naive-time}
\usage{
\method{as_zoned_time}{clock_naive_time}(x, zone, ..., nonexistent = NULL, ambiguous = NULL)
}
\arguments{
\item{x}{\verb{[clock_naive_time]}
A naive-time to convert to a zoned-time.}
\item{zone}{\verb{[character(1)]}
The zone to convert to.}
\item{...}{These dots are for future extensions and must be empty.}
\item{nonexistent}{\verb{[character / NULL]}
One of the following nonexistent time resolution strategies, allowed to be
either length 1, or the same length as the input:
\itemize{
\item \code{"roll-forward"}: The next valid instant in time.
\item \code{"roll-backward"}: The previous valid instant in time.
\item \code{"shift-forward"}: Shift the nonexistent time forward by the size of
the daylight saving time gap.
\item \verb{"shift-backward}: Shift the nonexistent time backward by the size of
the daylight saving time gap.
\item \code{"NA"}: Replace nonexistent times with \code{NA}.
\item \code{"error"}: Error on nonexistent times.
}
Using either \code{"roll-forward"} or \code{"roll-backward"} is generally
recommended over shifting, as these two strategies maintain the
\emph{relative ordering} between elements of the input.
If \code{NULL}, defaults to \code{"error"}.
If \code{getOption("clock.strict")} is \code{TRUE}, \code{nonexistent} must be supplied
and cannot be \code{NULL}. This is a convenient way to make production code
robust to nonexistent times.}
\item{ambiguous}{\verb{[character / zoned_time / POSIXct / list(2) / NULL]}
One of the following ambiguous time resolution strategies, allowed to be
either length 1, or the same length as the input:
\itemize{
\item \code{"earliest"}: Of the two possible times, choose the earliest one.
\item \code{"latest"}: Of the two possible times, choose the latest one.
\item \code{"NA"}: Replace ambiguous times with \code{NA}.
\item \code{"error"}: Error on ambiguous times.
}
Alternatively, \code{ambiguous} is allowed to be a zoned_time (or POSIXct) that
is either length 1, or the same length as the input. If an ambiguous time
is encountered, the zoned_time is consulted. If the zoned_time corresponds
to a naive_time that is also ambiguous \emph{and} uses the same daylight saving
time transition point as the original ambiguous time, then the offset of
the zoned_time is used to resolve the ambiguity. If the ambiguity cannot be
resolved by consulting the zoned_time, then this method falls back to
\code{NULL}.
Finally, \code{ambiguous} is allowed to be a list of size 2, where the first
element of the list is a zoned_time (as described above), and the second
element of the list is an ambiguous time resolution strategy to use when
the ambiguous time cannot be resolved by consulting the zoned_time.
Specifying a zoned_time on its own is identical to \verb{list(<zoned_time>, NULL)}.
If \code{NULL}, defaults to \code{"error"}.
If \code{getOption("clock.strict")} is \code{TRUE}, \code{ambiguous} must be supplied and
cannot be \code{NULL}. Additionally, \code{ambiguous} cannot be specified as a
zoned_time on its own, as this implies \code{NULL} for ambiguous times that the
zoned_time cannot resolve. Instead, it must be specified as a list
alongside an ambiguous time resolution strategy as described above. This is
a convenient way to make production code robust to ambiguous times.}
}
\value{
A zoned-time vector.
}
\description{
This is a naive-time method for the \code{\link[=as_zoned_time]{as_zoned_time()}} generic.
Converting to a zoned-time from a naive-time retains the printed time,
but changes the underlying duration, depending on the \code{zone} that you choose.
Naive-times are time points with a yet-to-be-determined time zone. By
converting them to a zoned-time, all you are doing is specifying that
time zone while attempting to keep all other printed information the
same (if possible).
If you want to retain the underlying duration, try converting to a zoned-time
\link[=as-zoned-time-sys-time]{from a sys-time}, which is a time point
interpreted as having a UTC time zone.
}
\section{Daylight Saving Time}{
Converting from a naive-time to a zoned-time is not always possible due to
daylight saving time issues. There are two types of these issues:
\emph{Nonexistent} times are the result of daylight saving time "gaps".
For example, in the America/New_York time zone, there was a daylight
saving time gap 1 second after \code{"2020-03-08 01:59:59"}, where the clocks
changed from \code{01:59:59 -> 03:00:00}, completely skipping the 2 o'clock hour.
This means that if you had a naive time of \code{"2020-03-08 02:30:00"}, you
couldn't convert that straight into a zoned-time with this time zone. To
resolve these issues, the \code{nonexistent} argument can be used to specify
one of many nonexistent time resolution strategies.
\emph{Ambiguous} times are the result of daylight saving time "fallbacks".
For example, in the America/New_York time zone, there was a daylight
saving time fallback 1 second after \code{"2020-11-01 01:59:59 EDT"}, at which
point the clocks "fell backwards" by 1 hour, resulting in a printed time of
\code{"2020-11-01 01:00:00 EST"} (note the EDT->EST shift). This resulted in two
1 o'clock hours for this day, so if you had a naive time of
\code{"2020-11-01 01:30:00"}, you wouldn't be able to convert that directly
into a zoned-time with this time zone, as there is no way for clock to know
which of the two ambiguous times you wanted. To resolve these issues,
the \code{ambiguous} argument can be used to specify one of many ambiguous
time resolution strategies.
}
\examples{
library(magrittr)
x <- as_naive_time(year_month_day(2019, 1, 1))
# Converting a naive-time to a zoned-time generally retains the
# printed time, while changing the underlying duration.
as_zoned_time(x, "America/New_York")
as_zoned_time(x, "America/Los_Angeles")
# ---------------------------------------------------------------------------
# Nonexistent time:
new_york <- "America/New_York"
# There was a daylight saving gap in the America/New_York time zone on
# 2020-03-08 01:59:59 -> 03:00:00, which means that one of these
# naive-times don't exist in that time zone. By default, attempting to
# convert it to a zoned time will result in an error.
nonexistent_time <- year_month_day(2020, 03, 08, c(02, 03), c(45, 30), 00)
nonexistent_time <- as_naive_time(nonexistent_time)
try(as_zoned_time(nonexistent_time, new_york))
# Resolve this by specifying a nonexistent time resolution strategy
as_zoned_time(nonexistent_time, new_york, nonexistent = "roll-forward")
as_zoned_time(nonexistent_time, new_york, nonexistent = "roll-backward")
# Note that rolling backwards will choose the last possible moment in
# time at the current precision of the input
nonexistent_nanotime <- time_point_cast(nonexistent_time, "nanosecond")
nonexistent_nanotime
as_zoned_time(nonexistent_nanotime, new_york, nonexistent = "roll-backward")
# A word of caution - Shifting does not guarantee that the relative ordering
# of the input is maintained
shifted <- as_zoned_time(
nonexistent_time,
new_york,
nonexistent = "shift-forward"
)
shifted
# 02:45:00 < 03:30:00
nonexistent_time[1] < nonexistent_time[2]
# 03:45:00 > 03:30:00 (relative ordering is lost)
shifted[1] < shifted[2]
# ---------------------------------------------------------------------------
# Ambiguous time:
new_york <- "America/New_York"
# There was a daylight saving time fallback in the America/New_York time
# zone on 2020-11-01 01:59:59 EDT -> 2020-11-01 01:00:00 EST, resulting
# in two 1 o'clock hours. This means that the following naive time is
# ambiguous since we don't know which of the two 1 o'clocks it belongs to.
# By default, attempting to convert it to a zoned time will result in an
# error.
ambiguous_time <- year_month_day(2020, 11, 01, 01, 30, 00)
ambiguous_time <- as_naive_time(ambiguous_time)
try(as_zoned_time(ambiguous_time, new_york))
# Resolve this by specifying an ambiguous time resolution strategy
earliest <- as_zoned_time(ambiguous_time, new_york, ambiguous = "earliest")
latest <- as_zoned_time(ambiguous_time, new_york, ambiguous = "latest")
na <- as_zoned_time(ambiguous_time, new_york, ambiguous = "NA")
earliest
latest
na
# Now assume that you were given the following zoned-times, i.e.,
# you didn't build them from scratch so you already know their otherwise
# ambiguous offsets
x <- c(earliest, latest)
x
# To set the seconds to 5 in both, you might try:
x_naive <- x \%>\%
as_naive_time() \%>\%
as_year_month_day() \%>\%
set_second(5) \%>\%
as_naive_time()
x_naive
# But this fails because you've "lost" the information about which
# offsets these ambiguous times started in
try(as_zoned_time(x_naive, zoned_time_zone(x)))
# To get around this, you can use that information by specifying
# `ambiguous = x`, which will use the offset from `x` to resolve the
# ambiguity in `x_naive` as long as `x` is also an ambiguous time with the
# same daylight saving time transition point as `x_naive` (i.e. here
# everything has a transition point of `"2020-11-01 01:00:00 EST"`).
as_zoned_time(x_naive, zoned_time_zone(x), ambiguous = x)
# Say you added one more time to `x` that would not be considered ambiguous
# in naive-time
x <- c(x, as_zoned_time(as_sys_time(latest) + 3600, zoned_time_zone(latest)))
x
# Imagine you want to floor this vector to a multiple of 2 hours, with
# an origin of 1am that day. You can do this by subtracting the origin,
# flooring, then adding it back
origin <- year_month_day(2019, 11, 01, 01, 00, 00) \%>\%
as_naive_time() \%>\%
as_duration()
x_naive <- x \%>\%
as_naive_time() \%>\%
add_seconds(-origin) \%>\%
time_point_floor("hour", n = 2) \%>\%
add_seconds(origin)
x_naive
# You again have ambiguous naive-time points, so you might try using
# `ambiguous = x`. It looks like this took care of the first two problems,
# but we have an issue at location 3.
try(as_zoned_time(x_naive, zoned_time_zone(x), ambiguous = x))
# When we floored from 02:30:00 -> 01:00:00, we went from being
# unambiguous -> ambiguous. In clock, this is something you must handle
# explicitly, and cannot be handled by using information from `x`. You can
# handle this while still retaining the behavior for the other two
# time points that were ambiguous before and after the floor by passing a
# list containing `x` and an ambiguous time resolution strategy to use
# when information from `x` can't resolve ambiguities:
as_zoned_time(x_naive, zoned_time_zone(x), ambiguous = list(x, "latest"))
}
|