Skip to content

v1.0.0 - #93

Merged
jhollway merged 74 commits into
mainfrom
develop
Jul 16, 2026
Merged

v1.0.0#93
jhollway merged 74 commits into
mainfrom
develop

Conversation

@jhollway

@jhollway jhollway commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Description

Package

  • Updated the {messydates} logo to better reflect the package's purpose
    and be more brand-consistent with manydata packages
  • Removed purrr and dplyr dependencies (replaced with base R),
    leaving only stringi and lubridate as imports
  • Updated the cheatsheet to reflect the new time support and other changes

Class

  • Added support for ISO 8601-2:2019 times of day in the mdate class
    • as_messydate() now parses an optional date-time separator,
      hh, hh:mm, and hh:mm:ss (with fractional seconds), am/pm times, the UTC designator
      Z, and numeric offsets (e.g. +02:00), zero-padding and normalising them
    • Dates and times are separated by a space (e.g. 2019-03-01 14:30:00)
      for readability (as permitted by ISO 8601-1 sec. 4.3.2 and RFC 3339),
      but a T separator 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-01 is a range while 2019-03-01 14:30:00 is a time
    • Time components can carry the same annotations as dates:
      approximate (~), uncertain (?), both (%), and unspecified (X),
      e.g. 2019-03-01 ~14:30

Coercion

  • Improved parsing of written dates (closed Expand the types of dates that can be extracted from texts with as_messydate() #52):
    • Ordinal days ("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)
    • Connectives:
      • "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
      • plain "13th and 15th", or a comma-separated list of dates, becomes several dates
    • Reduced-precision expressions:
      • month-and-year ("February 2004" -> 2004-02)
      • decades ("the 1910s" -> 191X)
      • centuries ("the 19th century" -> 18XX)
    • Open ranges: "before 1910" -> ..1910 and "after 1910" -> 1910..,
      where the bound may itself be imprecise ("before the 1920s" -> ..192X)
    • Prose qualifiers:
      • approximate words ("around", "circa", ...) add ~
      • uncertain words ("possibly", "reportedly", ...) add ?
      • both together add %, applied to the most specific component
    • Roman numerals (e.g. "MDCCLXXVI" becomes 1776)
    • Roman calendar references, e.g. "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)
  • Coercion from POSIXct/POSIXlt now preserves the time of day (midnight is
    treated as date-only); as.POSIXct()/as.POSIXlt() restore it

Resolution

  • Fixed how median()/vmedian() treat an even number of dates,
    which no longer silently returns NA but instead averages the two middle values
  • Fixed how mean()/vmean()/median()/vmedian() average precise date-times,
    honouring the time of day, instead of miscomputing via lubridate::as_date()

Expand/Contract

  • Fixed expand() error when approx_range was set and the vector contained a
    reduced-precision value (e.g. a bare year-month) alongside an approximate one
  • Improved expand() with a by argument (default "day")
    • Ranges are enumerated at day granularity to avoid combinatorial explosion;
      set by to "hour", "min", or "sec" for finer enumeration
    • Precise date-times keep their time

Operations

  • Improved arithmetic (+/-) and seq() to accept sub-day units
    ("hours", "minutes", "seconds") and operate on times
    • messyduration() keeps sub-day precision
  • Improved how arithmetic treats time of day and shifts the calendar components,
    so "2012-02-03 14:30" + "1 year" is 2013-02-03 14:30 (with month-end rollback)
  • Fixed bug where adding/subtracting from an open-ended range ("2012-01-01T09:00.." + "2 hours"
    or "..2012-01-01T09:00" + "1 month") dropped .. marker
  • Fixed how </>/<=/>= compare time of day on the same calendar day,
    no longer silently truncating both sides to a date first and treating them as equal
  • Fixed two related bugs (messydates changes date comparisons affecting other packages #92) affecting any comparison of two Date/POSIXct
    objects in a session with {messydates} loaded, including in unrelated packages:
    • since </>/<=/>= are registered for "Date"/"POSIXt" classes
      (so that e.g. Date < mdate works),
      any comparison of a zero-length or all-NA Date/POSIXct/POSIXlt value
      was passed through as_messydate(),
      where ifelse() and paste0() silently changed type or length
      and tripped an internal is.character() check.
      This broke loading packages whose .onLoad hooks compare timestamps,
      such as {httr2}'s cache pruning, which in turn broke pkgdown::build_news()
    • when one side of a comparison had a time of day and the other did not,
      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 breaking httr2::req_perform()
      (and so any request made while {messydates} is loaded,
      including pkgdown's GitHub release-timeline lookup)

Annotation

  • Improved as_approximate()/as_uncertain() to accept
    "hour", "minute", "second", and "time" components

Extraction

  • Added hour(), minute(), second(), and tz() time component extractors
  • Improved month(), day(), and precision() to be vectorised and
    no longer call expand() more than necessary
  • Improved precision() to extend below the day: 24 to the hour, 1440 to the
    minute, and 86400 to the second (date-level precision is unchanged)

Checklist:

  • Documentation
    • DESCRIPTION file version is bumped by the appropriate increment (major, minor, patch)
    • Longer functions are commented inline or broken down into helper functions to help debugging
  • PR form
    • Title indicates expected version number
    • PR description above and the NEWS.md file are aligned
    • Description above itemizes changes under subsection titles, e.g. "## Data""
    • Closed, fixed, or related issues are referenced and explained in the description above, e.g. "Fixed #0 by adding A"

Copilot AI review requested due to automatic review settings July 2, 2026 15:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/dplyr usages with base R equivalents and update docs/examples.
  • Add comprehensive testthat coverage 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.

Comment thread R/class_mdate.R Outdated
Comment thread R/class_mdate.R
Comment thread R/component_annotate.R
Comment thread R/coerce_from_messydate.R
Comment thread R/operate_arithmetic.R
Comment thread R/component_extract.R Outdated
Comment thread R/component_extract.R Outdated
Comment thread R/component_extract.R Outdated
@jhollway jhollway self-assigned this Jul 2, 2026
jhollway and others added 7 commits July 2, 2026 20:38
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>
jhollway added 23 commits July 7, 2026 09:55
…s `%` when both are applied to the same component
@jhollway
jhollway requested a review from henriquesposito July 9, 2026 16:30

@henriquesposito henriquesposito left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@jhollway
jhollway merged commit 1a40ac5 into main Jul 16, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

messydates changes date comparisons affecting other packages Expand the types of dates that can be extracted from texts with as_messydate()

4 participants