|
1 | 1 | #' @title Assign a date to a quarter |
2 | 2 | #' |
3 | 3 | #' @description |
4 | | -#' |
5 | 4 | #' The qtr functions take a date input and calculate the relevant |
6 | 5 | #' quarter-related value from it. They all return the year as part of this |
7 | 6 | #' value. |
|
33 | 32 | #' @return A character vector of financial quarters in the specified format. |
34 | 33 | #' |
35 | 34 | #' @examples |
36 | | -#' x <- lubridate::dmy(c(26032012, 04052012, 23092012)) |
37 | | -#' qtr(x) |
38 | | -#' qtr_end(x, format = "short") |
39 | | -#' qtr_next(x) |
40 | | -#' qtr_prev(x, format = "short") |
| 35 | +#' dates <- lubridate::dmy(c(26032012, 04052012, 23092012)) |
| 36 | +#' qtr(dates) |
| 37 | +#' qtr_end(dates, format = "short") |
| 38 | +#' qtr_next(dates) |
| 39 | +#' qtr_prev(dates, format = "short") |
41 | 40 | #' |
| 41 | +#' @name qtr |
42 | 42 | #' @export |
43 | 43 | #' @rdname qtr |
44 | | -qtr <- function(date, format = c("long", "short")) { |
45 | | - format <- match.arg(format) |
46 | | - |
47 | | - if (!inherits(date, c("Date", "POSIXct"))) { |
48 | | - cli::cli_abort("{.arg date} must be a {.cls Date} or {.cls POSIXct} vector, not a {.cls {class(date)}} vector.") |
49 | | - } |
| 44 | +NULL |
50 | 45 |
|
| 46 | +#' @noRd |
| 47 | +format_quarter_internal <- function( |
| 48 | + date, |
| 49 | + format, |
| 50 | + type = c("current", "end", "next", "prev") |
| 51 | +) { |
51 | 52 | quarter_num <- lubridate::quarter(date) |
| 53 | + year <- lubridate::year(date) |
52 | 54 |
|
53 | | - if (format == "long") { |
54 | | - return(dplyr::case_when( |
55 | | - quarter_num == 1 ~ paste0( |
56 | | - "January to March ", |
57 | | - lubridate::year(date) |
58 | | - ), |
59 | | - quarter_num == 2 ~ paste0( |
60 | | - "April to June ", |
61 | | - lubridate::year(date) |
62 | | - ), |
63 | | - quarter_num == 3 ~ paste0( |
64 | | - "July to September ", |
65 | | - lubridate::year(date) |
66 | | - ), |
67 | | - quarter_num == 4 ~ paste0( |
68 | | - "October to December ", |
69 | | - lubridate::year(date) |
70 | | - ) |
71 | | - )) |
| 55 | + # Adjust quarter number and year based on type |
| 56 | + if (type == "next") { |
| 57 | + # Vectorized calculation for next quarter number and year |
| 58 | + # (quarter_num %% 4L) + 1L handles 1->2, 2->3, 3->4, 4->1 |
| 59 | + year_change <- (quarter_num == 4L) |
| 60 | + quarter_num <- (quarter_num %% 4L) + 1L |
| 61 | + year <- year + year_change |
| 62 | + } else if (type == "prev") { |
| 63 | + # Vectorized calculation for previous quarter number and year |
| 64 | + # ((quarter_num + 2L) %% 4L) + 1L handles 1->4, 2->1, 3->2, 4->3 |
| 65 | + year_change <- (quarter_num == 1L) |
| 66 | + quarter_num <- ((quarter_num + 2L) %% 4L) + 1L |
| 67 | + year <- year - year_change |
| 68 | + } |
| 69 | + |
| 70 | + # Select appropriate labels based on type and format |
| 71 | + if (type == "end") { |
| 72 | + labels <- if (format == "long") { |
| 73 | + c("March", "June", "September", "December") |
| 74 | + } else { |
| 75 | + c("Mar", "Jun", "Sep", "Dec") |
| 76 | + } |
72 | 77 | } else { |
73 | | - return(dplyr::case_when( |
74 | | - quarter_num == 1 ~ paste0( |
75 | | - "Jan-Mar ", |
76 | | - lubridate::year(date) |
77 | | - ), |
78 | | - quarter_num == 2 ~ paste0( |
79 | | - "Apr-Jun ", |
80 | | - lubridate::year(date) |
81 | | - ), |
82 | | - quarter_num == 3 ~ paste0( |
83 | | - "Jul-Sep ", |
84 | | - lubridate::year(date) |
85 | | - ), |
86 | | - quarter_num == 4 ~ paste0( |
87 | | - "Oct-Dec ", |
88 | | - lubridate::year(date) |
| 78 | + labels <- if (format == "long") { |
| 79 | + c( |
| 80 | + "January to March", |
| 81 | + "April to June", |
| 82 | + "July to September", |
| 83 | + "October to December" |
89 | 84 | ) |
90 | | - )) |
| 85 | + } else { |
| 86 | + c("Jan-Mar", "Apr-Jun", "Jul-Sep", "Oct-Dec") |
| 87 | + } |
91 | 88 | } |
| 89 | + |
| 90 | + paste(labels[quarter_num], year) |
92 | 91 | } |
93 | 92 |
|
94 | 93 | #' @export |
95 | 94 | #' @rdname qtr |
96 | | -qtr_end <- function(date, format = c("long", "short")) { |
97 | | - format <- match.arg(format) |
| 95 | +qtr <- function(date, format = c("long", "short")) { |
| 96 | + format <- rlang::arg_match(format) |
98 | 97 |
|
99 | 98 | if (!inherits(date, c("Date", "POSIXct"))) { |
100 | | - cli::cli_abort("{.arg date} must be a {.cls Date} or {.cls POSIXct} vector, not a {.cls {class(date)}} vector.") |
| 99 | + cli::cli_abort( |
| 100 | + "{.arg date} must be a {.cls Date} or {.cls POSIXct} vector, not a {.cls {class(date)}} vector." |
| 101 | + ) |
101 | 102 | } |
102 | 103 |
|
103 | | - quarter_num <- lubridate::quarter(date) |
| 104 | + format_quarter_internal(date, format, type = "current") |
| 105 | +} |
104 | 106 |
|
105 | | - if (format == "long") { |
106 | | - return(dplyr::case_when( |
107 | | - quarter_num == 1 ~ paste0( |
108 | | - "March ", |
109 | | - lubridate::year(date) |
110 | | - ), |
111 | | - quarter_num == 2 ~ paste0( |
112 | | - "June ", |
113 | | - lubridate::year(date) |
114 | | - ), |
115 | | - quarter_num == 3 ~ paste0( |
116 | | - "September ", |
117 | | - lubridate::year(date) |
118 | | - ), |
119 | | - quarter_num == 4 ~ paste0( |
120 | | - "December ", |
121 | | - lubridate::year(date) |
122 | | - ) |
123 | | - )) |
124 | | - } else { |
125 | | - return(dplyr::case_when( |
126 | | - quarter_num == 1 ~ paste0( |
127 | | - "Mar ", |
128 | | - lubridate::year(date) |
129 | | - ), |
130 | | - quarter_num == 2 ~ paste0( |
131 | | - "Jun ", |
132 | | - lubridate::year(date) |
133 | | - ), |
134 | | - quarter_num == 3 ~ paste0( |
135 | | - "Sep ", |
136 | | - lubridate::year(date) |
137 | | - ), |
138 | | - quarter_num == 4 ~ paste0( |
139 | | - "Dec ", |
140 | | - lubridate::year(date) |
141 | | - ) |
142 | | - )) |
| 107 | +#' @export |
| 108 | +#' @rdname qtr |
| 109 | +qtr_end <- function(date, format = c("long", "short")) { |
| 110 | + format <- rlang::arg_match(format) |
| 111 | + |
| 112 | + if (!inherits(date, c("Date", "POSIXct"))) { |
| 113 | + cli::cli_abort( |
| 114 | + "{.arg date} must be a {.cls Date} or {.cls POSIXct} vector, not a {.cls {class(date)}} vector." |
| 115 | + ) |
143 | 116 | } |
| 117 | + |
| 118 | + format_quarter_internal(date, format, type = "end") |
144 | 119 | } |
145 | 120 |
|
146 | 121 | #' @export |
147 | 122 | #' @rdname qtr |
148 | 123 | qtr_next <- function(date, format = c("long", "short")) { |
149 | | - format <- match.arg(format) |
| 124 | + format <- rlang::arg_match(format) |
150 | 125 |
|
151 | 126 | if (!inherits(date, c("Date", "POSIXct"))) { |
152 | | - cli::cli_abort("{.arg date} must be a {.cls Date} or {.cls POSIXct} vector, not a {.cls {class(date)}} vector.") |
| 127 | + cli::cli_abort( |
| 128 | + "{.arg date} must be a {.cls Date} or {.cls POSIXct} vector, not a {.cls {class(date)}} vector." |
| 129 | + ) |
153 | 130 | } |
154 | 131 |
|
155 | | - quarter_num <- lubridate::quarter(date) |
156 | | - |
157 | | - if (format == "long") { |
158 | | - return(dplyr::case_when( |
159 | | - quarter_num == 1 ~ paste0( |
160 | | - "April to June ", |
161 | | - lubridate::year(date) |
162 | | - ), |
163 | | - quarter_num == 2 ~ paste0( |
164 | | - "July to September ", |
165 | | - lubridate::year(date) |
166 | | - ), |
167 | | - quarter_num == 3 ~ paste0( |
168 | | - "October to December ", |
169 | | - lubridate::year(date) |
170 | | - ), |
171 | | - quarter_num == 4 ~ paste0( |
172 | | - "January to March ", |
173 | | - lubridate::year(date) + 1 |
174 | | - ) |
175 | | - )) |
176 | | - } else { |
177 | | - return(dplyr::case_when( |
178 | | - quarter_num == 1 ~ paste0( |
179 | | - "Apr-Jun ", |
180 | | - lubridate::year(date) |
181 | | - ), |
182 | | - quarter_num == 2 ~ paste0( |
183 | | - "Jul-Sep ", |
184 | | - lubridate::year(date) |
185 | | - ), |
186 | | - quarter_num == 3 ~ paste0( |
187 | | - "Oct-Dec ", |
188 | | - lubridate::year(date) |
189 | | - ), |
190 | | - quarter_num == 4 ~ paste0( |
191 | | - "Jan-Mar ", |
192 | | - lubridate::year(date) + 1 |
193 | | - ) |
194 | | - )) |
195 | | - } |
| 132 | + format_quarter_internal(date, format, type = "next") |
196 | 133 | } |
197 | 134 |
|
198 | 135 | #' @export |
199 | 136 | #' @rdname qtr |
200 | 137 | qtr_prev <- function(date, format = c("long", "short")) { |
201 | | - format <- match.arg(format) |
| 138 | + format <- rlang::arg_match(format) |
202 | 139 |
|
203 | 140 | if (!inherits(date, c("Date", "POSIXct"))) { |
204 | | - cli::cli_abort("{.arg date} must be a {.cls Date} or {.cls POSIXct} vector, not a {.cls {class(date)}} vector.") |
| 141 | + cli::cli_abort( |
| 142 | + "{.arg date} must be a {.cls Date} or {.cls POSIXct} vector, not a {.cls {class(date)}} vector." |
| 143 | + ) |
205 | 144 | } |
206 | 145 |
|
207 | | - quarter_num <- lubridate::quarter(date) |
208 | | - |
209 | | - if (format == "long") { |
210 | | - return(dplyr::case_when( |
211 | | - quarter_num == 1 ~ paste0( |
212 | | - "October to December ", |
213 | | - lubridate::year(date) - 1 |
214 | | - ), |
215 | | - quarter_num == 2 ~ paste0( |
216 | | - "January to March ", |
217 | | - lubridate::year(date) |
218 | | - ), |
219 | | - quarter_num == 3 ~ paste0( |
220 | | - "April to June ", |
221 | | - lubridate::year(date) |
222 | | - ), |
223 | | - quarter_num == 4 ~ paste0( |
224 | | - "July to September ", |
225 | | - lubridate::year(date) |
226 | | - ) |
227 | | - )) |
228 | | - } else { |
229 | | - return(dplyr::case_when( |
230 | | - quarter_num == 1 ~ paste0( |
231 | | - "Oct-Dec ", |
232 | | - lubridate::year(date) - 1 |
233 | | - ), |
234 | | - quarter_num == 2 ~ paste0( |
235 | | - "Jan-Mar ", |
236 | | - lubridate::year(date) |
237 | | - ), |
238 | | - quarter_num == 3 ~ paste0( |
239 | | - "Apr-Jun ", |
240 | | - lubridate::year(date) |
241 | | - ), |
242 | | - quarter_num == 4 ~ paste0( |
243 | | - "Jul-Sep ", |
244 | | - lubridate::year(date) |
245 | | - ) |
246 | | - )) |
247 | | - } |
| 146 | + format_quarter_internal(date, format, type = "prev") |
248 | 147 | } |
0 commit comments