# Strings with stringr and Dates with lubridate — R Programming

Source: https://www.geekswithgeeks.com/en/r-programming/a-text-time

> Clean text and handle dates and times correctly.

## Two common sources of messy data

Text columns are often inconsistent: extra spaces, mixed case, typos and embedded codes. **stringr** offers consistent functions starting with `str_`: `str_trim()`, `str_squish()`, `str_to_lower()`/`str_to_title()`, `str_detect()` (does it match?), `str_replace()`/`str_replace_all()`, `str_extract()` (pull out a match, such as a PIN code), `str_split()`, `str_pad()`, `str_length()` and `str_glue()` for templating. Patterns are **regular expressions**: `"\\d{6}"` matches six digits (backslashes are doubled inside R strings, or use raw strings `r"(\d{6})"`). Dates and times cause subtle bugs. **lubridate** parses them with readable functions named after the input order: `dmy("03/10/2026")`, `ymd("2026-10-03")`, `ymd_hms(...)`. It extracts parts (`year()`, `month(label = TRUE)`, `wday()`), rounds (`floor_date(x, "week")`) and does arithmetic with **periods** (`months(1)`, calendar-aware) and **durations** (exact seconds). Store timestamps in UTC and convert with `with_tz(x, "Asia/Kolkata")` for display.

## Cleaning text and parsing dates

Messy strings and date formats become clean, typed columns.

![Left: jumbled text fragments and differently formatted dates. Right: neat aligned columns with consistent formats.](assets/figures/r-programming/section-7-map.svg) — Figure 7.1 — From messy text and dates to typed values.

## Cleaning addresses and working with dates

Regex extraction and calendar-aware date arithmetic.

```r
library(stringr)
library(lubridate)
library(dplyr)

addresses <- c("  12 MG Road , PUNE 411001 ", "Sector 18, noida-201301", "Anna Nagar Chennai 600040")

tibble(raw = addresses) |>
  mutate(
    clean = str_squish(raw),
    pin = str_extract(clean, "\\d{6}"),                         # six-digit PIN code
    city = str_to_title(str_extract(clean, "(?i)pune|noida|chennai"))
  )

order_dates <- dmy(c("03/10/2026", "31/01/2026"))
wday(order_dates, label = TRUE)                     # day of week
order_dates + months(1)                             # 2026-11-03 and NA (no 31 Feb)
order_dates %m+% months(1)                          # rolls back to month end: 2026-11-03, 2026-02-28

placed <- ymd_hms("2026-10-03 06:45:00", tz = "UTC")
with_tz(placed, "Asia/Kolkata")                     # 2026-10-03 12:15:00 IST
floor_date(placed, "week", week_start = 1)          # Monday of that week
```

## Month arithmetic is tricky

Adding one month to 31 January has no single right answer. lubridate's `+ months(1)` returns NA for impossible dates, while `%m+%` rolls back to the last valid day. Choose deliberately for billing dates.

**Quiz:** Which lubridate function parses "03/10/2026" written as day/month/year?

- [x] dmy
- [ ] ymd
- [ ] mdy
- [ ] ydm

*Answer:* dmy. The function name follows the order of components in the input.
