Conversation
There was a problem hiding this comment.
Pull request overview
This PR prepares the messydates package for the 1.0.0 release by extending the mdate class from “messy dates” to full ISO 8601-2:2019 date-times (time-of-day + optional zone/offset), while also removing purrr/dplyr runtime dependencies and updating documentation + tests accordingly.
Changes:
- Add parsing, formatting, coercion, arithmetic, sequencing, extraction, annotation, and expansion support for ISO 8601-2 style times (including offsets /
Z). - Replace several
purrr/dplyrusages with base R equivalents and update docs/examples. - Add comprehensive
testthatcoverage for time parsing/extraction/expansion/coercion/annotation and separator edge cases.
Reviewed changes
Copilot reviewed 35 out of 43 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/testthat/test-time-parse.R | New tests for parsing/round-tripping time-of-day forms, offsets, annotations, and ranges. |
| tests/testthat/test-time-extract.R | New tests for hour()/minute()/second()/tz() and time-aware precision(). |
| tests/testthat/test-time-expand.R | New tests for expand() behavior with precise date-times vs date-time ranges and sub-day by. |
| tests/testthat/test-time-coerce.R | New tests for POSIX coercion, sub-day arithmetic, seq(), and durations with time ranges. |
| tests/testthat/test-time-annotate.R | New tests for annotating time components (~/?) and round-tripping. |
| tests/testthat/test-separator-context.R | New tests ensuring :/_ still work as range separators while preserving : inside times. |
| tests/testthat/test-operate_operators.R | Regression test for zero-length comparison vectors after load (#92). |
| README.Rmd | Docs overhaul: stable lifecycle badge, new “Times” section, remove dplyr/tibble/kableExtra usage. |
| README.md | Regenerated README content reflecting new time support and comparison tables. |
| R/operate_statements.R | Extend is_precise() to accept date-times (optional offset/Z). |
| R/operate_proportional.R | Replace purrr::map2_dbl comparisons with base mapply. |
| R/operate_inequalities.R | Fix inequalities for zero-length vectors by allocating zero-length result. |
| R/operate_arithmetic.R | Add POSIXct-based sub-day (and time-carrying) arithmetic via shift_time(). |
| R/convert_sequence.R | Extend seq.mdate() to use POSIXct when times/sub-day steps are involved. |
| R/convert_expand.R | Add by argument; add sub-day range enumeration for precise date-time ranges. |
| R/convert_contract.R | Replace dplyr helpers with base indexing; update examples. |
| R/component_extract.R | Vectorize month()/day(); add hour()/minute()/second()/tz() extractors; extend precision below day. |
| R/component_annotate.R | Refactor annotation logic to support time components and unify approximate/uncertain handling. |
| R/coerce_to_messydate.R | Preserve times when coercing from POSIX; protect time substrings during parsing pipeline; add time standardisation helpers. |
| R/coerce_tendency.R | Replace purrr::map_chr with vapply. |
| R/coerce_from_messydate.R | Drop times when coercing to Date; add offset-aware POSIX conversion via mdate_to_posixct(). |
| R/coerce_extrema.R | Change extrema methods default na.rm to FALSE to match docs and generics. |
| R/class_mdate.R | Update validation rules to allow T/Z and time punctuation; refactor make_messydate() to base R. |
| R/class_duration.R | Preserve sub-day precision for date-time ranges in messyduration(). |
| NEWS.md | Add 1.0.0 release notes emphasizing time support and dependency removal. |
| NAMESPACE | Export new time extractors; remove dplyr/purrr imports. |
| man/operate_arithmetic.Rd | Update examples to base data.frame. |
| man/convert_expand.Rd | Document expand(..., by=) and time range enumeration behavior. |
| man/convert_contract.Rd | Update examples to base data.frame. |
| man/component_extract.Rd | Document new time extractors and sub-day precision() scaling. |
| man/component_annotate.Rd | Document time-component annotation options. |
| man/coerce_to.Rd | Document POSIX coercion behavior preserving time (midnight drops to date-only). |
| man/coerce_tendency.Rd | Align docs for na.rm default (FALSE). |
| man/coerce_extrema.Rd | Align docs for na.rm default (FALSE). |
| man/class_create.Rd | Document time-of-day support on mdate. |
| DESCRIPTION | Bump to 1.0.0; update R dependency; remove purrr/dplyr imports; update metadata. |
| data-raw/cheatsheet/cheatsheet.tex | New cheat sheet source reflecting time support and updated API. |
| data-raw/cheatsheet/build.R | Script to rebuild/distribute cheat sheet PDF/PNG assets. |
| .Rbuildignore | Ignore .claude directory in package builds. |
Files not reviewed (4)
- man/class_create.Rd: Generated file
- man/coerce_extrema.Rd: Generated file
- man/coerce_tendency.Rd: Generated file
- man/coerce_to.Rd: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…lendar references
…s "around" or "possibly", and semantic structures that indicate a range, set, or collection of dates
…s `%` when both are applied to the same component
…how/why annotations apply
…light the distinction
…s to coercion clearer
… tease readers into reading more
…rtain() respectively
henriquesposito
left a comment
There was a problem hiding this comment.
Wow, this was really a lot of work - congrats @jhollway the package is much more complete now and it is a well deserved bump to 1.0.0! I reviewed the PR and have no comments at this stage, all is good on my side to merge.
Description
Package
{messydates}logo to better reflect the package's purposeand be more brand-consistent with manydata packages
purrranddplyrdependencies (replaced with base R),leaving only
stringiandlubridateas importsClass
mdateclassas_messydate()now parses an optional date-time separator,hh,hh:mm, andhh:mm:ss(with fractional seconds), am/pm times, the UTC designatorZ, and numeric offsets (e.g.+02:00), zero-padding and normalising them2019-03-01 14:30:00)for readability (as permitted by ISO 8601-1 sec. 4.3.2 and RFC 3339),
but a
Tseparator can be used on input and is normalised to a space in the output:and_continue to work as range separators;times are detected and protected first,
so
2009-01-01:2019-01-01is a range while2019-03-01 14:30:00is a timeapproximate (
~), uncertain (?), both (%), and unspecified (X),e.g.
2019-03-01 ~14:30Coercion
as_messydate()#52):"4th July 1976"): either day-first or month-first order(
"Fourth of July 1976","July 4th 1976"), "day of" phrasings,and "last day of
<month>" (leap-year aware for February)"between the 13th and 15th of Feb 1977"(or"from the 13th to the 15th") becomes a range"the 13th or the 15th"a set"13th and 15th", or a comma-separated list of dates, becomes several dates"February 2004"->2004-02)"the 1910s"->191X)"the 19th century"->18XX)"before 1910"->..1910and"after 1910"->1910..,where the bound may itself be imprecise (
"before the 1920s"->..192X)"around","circa", ...) add~"possibly","reportedly", ...) add?%, applied to the most specific component"MDCCLXXVI"becomes1776)"the Ides of March, 44 BC"becomes-0044-03-15(Kalends, Nones, and Ides, with the later Nones/Ides of March, May, July, and October)
POSIXct/POSIXltnow preserves the time of day (midnight istreated as date-only);
as.POSIXct()/as.POSIXlt()restore itResolution
median()/vmedian()treat an even number of dates,which no longer silently returns
NAbut instead averages the two middle valuesmean()/vmean()/median()/vmedian()average precise date-times,honouring the time of day, instead of miscomputing via
lubridate::as_date()Expand/Contract
expand()error whenapprox_rangewas set and the vector contained areduced-precision value (e.g. a bare year-month) alongside an approximate one
expand()with abyargument (default"day")set
byto"hour","min", or"sec"for finer enumerationOperations
+/-) andseq()to accept sub-day units("hours", "minutes", "seconds") and operate on times
messyduration()keeps sub-day precisionso
"2012-02-03 14:30" + "1 year"is2013-02-03 14:30(with month-end rollback)"2012-01-01T09:00.." + "2 hours"or
"..2012-01-01T09:00" + "1 month") dropped..marker</>/<=/>=compare time of day on the same calendar day,no longer silently truncating both sides to a date first and treating them as equal
Date/POSIXctobjects in a session with
{messydates}loaded, including in unrelated packages:</>/<=/>=are registered for"Date"/"POSIXt"classes(so that e.g.
Date < mdateworks),any comparison of a zero-length or all-
NADate/POSIXct/POSIXltvaluewas passed through
as_messydate(),where
ifelse()andpaste0()silently changed type or lengthand tripped an internal
is.character()check.This broke loading packages whose
.onLoadhooks compare timestamps,such as
{httr2}'s cache pruning, which in turn brokepkgdown::build_news()their numeric bounds were computed in different units (e.g. seconds, days)
without converting to a common unit, which could silently reverse the result.
In particular,
Sys.time() < (Sys.time() + Inf)--the pattern
{httr2}uses to represent an unbounded retry deadline --incorrectly evaluated to
FALSE, in turn breakinghttr2::req_perform()(and so any request made while
{messydates}is loaded,including
pkgdown's GitHub release-timeline lookup)Annotation
as_approximate()/as_uncertain()to accept"hour", "minute", "second", and "time" components
Extraction
hour(),minute(),second(), andtz()time component extractorsmonth(),day(), andprecision()to be vectorised andno longer call
expand()more than necessaryprecision()to extend below the day: 24 to the hour, 1440 to theminute, and 86400 to the second (date-level precision is unchanged)
Checklist: