Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 4.3k
ARROW-16516: [R] Implement ym() my() and yq() parsers#13163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
ed0478c20e5cab0051609d172d82bdaf97e39b6709cbe518178251babca48d05af27219368c88File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -159,6 +159,26 @@ build_formats <- function(orders) { | ||
| orders <- gsub("[^A-Za-z_]", "", orders) | ||
| orders <- gsub("Y", "y", orders) | ||
| # we separate "ym', "my", and "yq" from the rest of the `orders` vector and | ||
| # transform them. `ym` and `yq` -> `ymd` & `my` -> `myd` | ||
| # this is needed for 2 reasons: | ||
| # 1. strptime does not parse "2022-05" -> we add "-01", thus changing the format, | ||
| # 2. for equivalence to lubridate, which parses `ym` to the first day of the month | ||
| short_orders <- c("ym", "my") | ||
| if (any(orders %in% short_orders)) { | ||
| orders1 <- setdiff(orders, short_orders) | ||
| orders2 <- intersect(orders, short_orders) | ||
| orders2 <- paste0(orders2, "d") | ||
| orders <- unique(c(orders1, orders2)) | ||
| } | ||
| if (any(orders == "yq")) { | ||
| orders1 <- setdiff(orders, "yq") | ||
| orders2 <- "ymd" | ||
dragosmg marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| orders <- unique(c(orders1, orders2)) | ||
| } | ||
| supported_orders <- c("ymd", "ydm", "mdy", "myd", "dmy", "dym") | ||
| unsupported_passed_orders <- setdiff(orders, supported_orders) | ||
| supported_passed_orders <- intersect(orders, supported_orders) | ||
| @@ -176,7 +196,8 @@ build_formats <- function(orders) { | ||
| } | ||
| formats_list <- map(orders, build_format_from_order) | ||
| purrr::flatten_chr(formats_list) | ||
| formats <- purrr::flatten_chr(formats_list) | ||
dragosmg marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| unique(formats) | ||
| } | ||
| build_format_from_order <- function(order) { | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -493,27 +493,99 @@ register_bindings_datetime_parsers <- function() { | ||
| # each order is translated into possible formats | ||
| formats <- build_formats(orders) | ||
| x <- x$cast(string()) | ||
| # make all separators (non-letters and non-numbers) into "-" | ||
| x <- call_binding("gsub", "[^A-Za-z0-9]", "-", x) | ||
| # collapse multiple separators into a single one | ||
| x <- call_binding("gsub", "-{2,}", "-", x) | ||
| # we need to transform `x` when orders are `ym`, `my`, and `yq` | ||
| # for `ym` and `my` orders we add a day ("01") | ||
| augmented_x <- NULL | ||
| if (any(orders %in% c("ym", "my"))) { | ||
| augmented_x <- call_binding("paste0", x, "-01") | ||
| } | ||
| # for `yq` we need to transform the quarter into the start month (lubridate | ||
| # behaviour) and then add 01 to parse to the first day of the quarter | ||
| augmented_x2 <- NULL | ||
| if (any(orders == "yq")) { | ||
| # extract everything that comes after the `-` separator, i.e. the quarter | ||
| # (e.g. 4 from 2022-4) | ||
| quarter_x <- call_binding("gsub", "^.*?-", "", x) | ||
dragosmg marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| # we should probably error if quarter is not in 1:4 | ||
| # extract everything that comes before the `-`, i.e. the year (e.g. 2002 | ||
| # in 2002-4) | ||
| year_x <- call_binding("gsub", "-.*$", "", x) | ||
| quarter_x <- quarter_x$cast(int32()) | ||
| month_x <- (quarter_x - 1) * 3 + 1 | ||
| augmented_x2 <- call_binding("paste0", year_x, "-", month_x, "-01") | ||
| } | ||
| # TODO figure out how to parse strings that have no separators | ||
| # https://issues.apache.org/jira/browse/ARROW-16446 | ||
| # we could insert separators at the "likely" positions, but it might be | ||
| # tricky given the possible combinations between dmy formats + locale | ||
| # build a list of expressions for each format | ||
| parse_attempt_expressions <- list() | ||
| for (i in seq_along(formats)) { | ||
| parse_attempt_expressions[[i]] <- build_expr( | ||
| parse_attempt_expressions <- map( | ||
| formats, | ||
| ~ build_expr( | ||
| "strptime", | ||
| x, | ||
| options = list(format = formats[[i]], unit = 0L, error_is_null = TRUE) | ||
| options = list( | ||
| format = .x, | ||
| unit = 0L, | ||
| error_is_null = TRUE | ||
| ) | ||
| ) | ||
| ) | ||
| # build separate expression lists of parsing attempts for the orders that | ||
| # need an augmented `x` | ||
| # list for attempts when orders %in% c("ym", "my") | ||
| parse_attempt_exp_augmented_x <- list() | ||
| if (!is.null(augmented_x)) { | ||
| parse_attempt_exp_augmented_x <- map( | ||
| formats, | ||
| ~ build_expr( | ||
| "strptime", | ||
| augmented_x, | ||
| options = list( | ||
| format = .x, | ||
| unit = 0L, | ||
| error_is_null = TRUE | ||
| ) | ||
| ) | ||
| ) | ||
| } | ||
| # list for attempts when orders %in% c("yq") | ||
| parse_attempt_exp_augmented_x2 <- list() | ||
| if (!is.null(augmented_x2)) { | ||
| parse_attempt_exp_augmented_x2 <- map( | ||
| formats, | ||
| ~ build_expr( | ||
| "strptime", | ||
| augmented_x2, | ||
| options = list( | ||
| format = .x, | ||
| unit = 0L, | ||
| error_is_null = TRUE | ||
| ) | ||
| ) | ||
| ) | ||
| } | ||
| # combine all attempts expressions in prep for coalesce | ||
| parse_attempt_expressions <- c( | ||
dragosmg marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| parse_attempt_expressions, | ||
| parse_attempt_exp_augmented_x, | ||
| parse_attempt_exp_augmented_x2 | ||
| ) | ||
| coalesce_output <- build_expr("coalesce", args = parse_attempt_expressions) | ||
| # we need this binding to be able to handle a NULL `tz`, which will then be | ||
| @@ -527,7 +599,7 @@ register_bindings_datetime_parsers <- function() { | ||
| }) | ||
| ymd_parser_vec <- c("ymd", "ydm", "mdy", "myd", "dmy", "dym") | ||
| ymd_parser_vec <- c("ymd", "ydm", "mdy", "myd", "dmy", "dym", "ym", "my", "yq") | ||
| ymd_parser_map_factory <- function(order) { | ||
| force(order) | ||
Uh oh!
There was an error while loading. Please reload this page.