File: invalid.R

package info (click to toggle)
r-cran-clock 0.7.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,856 kB
  • sloc: cpp: 19,564; sh: 17; makefile: 2
file content (189 lines) | stat: -rw-r--r-- 5,241 bytes parent folder | download
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
#' Invalid calendar dates
#'
#' @description
#' This family of functions is for working with _invalid_ calendar dates.
#'
#' Invalid dates represent dates made up of valid individual components, which
#' taken as a whole don't represent valid calendar dates. For example, for
#' [year_month_day()] the following component ranges are valid:
#' `year: [-32767, 32767]`, `month: [1, 12]`, `day: [1, 31]`.
#' However, the date `2019-02-31` doesn't exist even though it is made up
#' of valid components. This is an example of an invalid date.
#'
#' Invalid dates are allowed in clock, provided that they are eventually
#' resolved by using `invalid_resolve()` or by manually resolving them through
#' arithmetic or setter functions.
#'
#' @details
#' Invalid dates must be resolved before converting them to a time point.
#'
#' It is recommended to use `"previous"` or `"next"` for resolving invalid
#' dates, as these ensure that _relative ordering_ among `x` is maintained.
#' This is a often a very important property to maintain when doing time series
#' data analysis. See the examples for more information.
#'
#' @inheritParams rlang::args_dots_empty
#'
#' @param x `[calendar]`
#'
#'   A calendar vector.
#'
#' @param invalid `[character(1) / NULL]`
#'
#'   One of the following invalid date resolution strategies:
#'
#'   - `"previous"`: The previous valid instant in time.
#'
#'   - `"previous-day"`: The previous valid day in time, keeping the time of
#'     day.
#'
#'   - `"next"`: The next valid instant in time.
#'
#'   - `"next-day"`: The next valid day in time, keeping the time of day.
#'
#'   - `"overflow"`: Overflow by the number of days that the input is invalid
#'     by. Time of day is dropped.
#'
#'   - `"overflow-day"`: Overflow by the number of days that the input is
#'     invalid by. Time of day is kept.
#'
#'   - `"NA"`: Replace invalid dates with `NA`.
#'
#'   - `"error"`: Error on invalid dates.
#'
#'   Using either `"previous"` or `"next"` is generally recommended, as these
#'   two strategies maintain the _relative ordering_ between elements of the
#'   input.
#'
#'   If `NULL`, defaults to `"error"`.
#'
#'   If `getOption("clock.strict")` is `TRUE`, `invalid` must be supplied and
#'   cannot be `NULL`. This is a convenient way to make production code robust
#'   to invalid dates.
#'
#' @return
#' - `invalid_detect()`: Returns a logical vector detecting invalid dates.
#'
#' - `invalid_any()`: Returns `TRUE` if any invalid dates are detected.
#'
#' - `invalid_count()`: Returns a single integer containing the number of
#'   invalid dates.
#'
#' - `invalid_remove()`: Returns `x` with invalid dates removed.
#'
#' - `invalid_resolve()`: Returns `x` with invalid dates resolved using the
#'   `invalid` strategy.
#'
#' @name clock-invalid
#' @examples
#' # Invalid date
#' x <- year_month_day(2019, 04, 30:31, c(3, 2), 30, 00)
#' x
#'
#' invalid_detect(x)
#'
#' # Previous valid moment in time
#' x_previous <- invalid_resolve(x, invalid = "previous")
#' x_previous
#'
#' # Previous valid day, retaining time of day
#' x_previous_day <- invalid_resolve(x, invalid = "previous-day")
#' x_previous_day
#'
#' # Note that `"previous"` retains the relative ordering in `x`
#' x[1] < x[2]
#' x_previous[1] < x_previous[2]
#'
#' # But `"previous-day"` here does not!
#' x_previous_day[1] < x_previous_day[2]
#'
#' # Remove invalid dates entirely
#' invalid_remove(x)
#'
#' y <- year_quarter_day(2019, 1, 90:92)
#' y
#'
#' # Overflow rolls forward by the number of days between `y` and the previous
#' # valid date
#' invalid_resolve(y, invalid = "overflow")
NULL

# ------------------------------------------------------------------------------

#' @rdname clock-invalid
#' @export
invalid_detect <- function(x) {
  UseMethod("invalid_detect")
}

#' @export
invalid_detect.default <- function(x) {
  stop_clock_unsupported(x)
}

# ------------------------------------------------------------------------------

#' @rdname clock-invalid
#' @export
invalid_any <- function(x) {
  UseMethod("invalid_any")
}

#' @export
invalid_any.default <- function(x) {
  stop_clock_unsupported(x)
}

# ------------------------------------------------------------------------------

#' @rdname clock-invalid
#' @export
invalid_count <- function(x) {
  UseMethod("invalid_count")
}

#' @export
invalid_count.default <- function(x) {
  stop_clock_unsupported(x)
}

# ------------------------------------------------------------------------------

#' @rdname clock-invalid
#' @export
invalid_remove <- function(x) {
  UseMethod("invalid_remove")
}

#' @export
invalid_remove.default <- function(x) {
  stop_clock_unsupported(x)
}

#' @export
invalid_remove.clock_calendar <- function(x) {
  x[!invalid_detect(x)]
}

# ------------------------------------------------------------------------------

#' @rdname clock-invalid
#' @export
invalid_resolve <- function(x, ..., invalid = NULL) {
  UseMethod("invalid_resolve")
}

#' @export
invalid_resolve.default <- function(x, ..., invalid = NULL) {
  stop_clock_unsupported(x)
}

validate_invalid <- function(invalid) {
  invalid <- strict_validate_invalid(invalid)

  if (!is_string(invalid)) {
    abort("`invalid` must be a character vector with length 1.")
  }

  invalid
}