messydates 1.1.0
Package
- Improved package architecture documentation in
.github/CONTRIBUTING.md so that human contributors and
coding agents read the same notes
- Added a PR metadata job to the PR checks workflow, which verifies
that the
DESCRIPTION version is bumped, that the PR title
names the new version, and that the PR description itemizes changes
under subsection titles; these items are consequently dropped from the
pull request template
- Fixed the website deploy job installing
Config/Needs/check packages instead of
Config/Needs/website
Class
- Improved
validate_messydate() to report which elements
failed and what they contained, instead of naming only the rule that was
broken
- No longer passes a vector of empty strings as valid because a single
element somewhere in it happened to contain a digit
- Assigning an unparseable value into an
mdate with
[<- or [[<- now reports what could not
be parsed, rather than silently blanking the element
- Added
unique() and duplicated() methods
for mdate objects (closes #106)
- Previously
unique() fell through to the character
method and dropped the class, so a deduplicated column silently stopped
being an mdate
- Both compare the annotated strings rather than the dates they expand
to, so
"2012-01" and "2012-01-01..2012-01-31"
remain distinct
Coercion
- Improved
as_messydate() to validate its input rather
than carrying values it cannot interpret:
- dates with impossible components are rejected, so
"2019-02-30", "2019-06-31" and
"2019-01-01 25:00" now error instead of being accepted as
written; relatedly, "2019-13-45" is no longer silently
reordered into "2019-45-13", since month and day are only
swapped where the swap yields a date that could exist
- ISO 8601-2 notations that
{messydates} does not
represent (week dates, ordinal dates, season codes, significant digits,
extended years, the P-style duration notation, and
repeating intervals) now error naming the format, instead of passing
through as strings that nothing downstream could expand, resolve or
compare. Durations themselves are unaffected: they are written as date
ranges and handled by mduration, and the error for
"P1Y2M" points there
- text naming no date at all still becomes
NA, but now
warns, listing what could not be read
- Added
md_problems(), which reports one row per
unparseable element of a vector, with the reason for each, for checking
a column of dates before coercing it
- Added
as_messydate() methods for factors (coerced via
their labels, the common case when a column was read in with
stringsAsFactors = TRUE) and a default method that names
the offending class rather than failing with R’s UseMethod
message
- Improved parsing consistency across scalars and vectors
- a month-first date such as
"July 4 1976" previously
lost its day whenever another value shared the vector with it
- Fixed how
[] sets (“one member of”) silently rewrote as
{} sets (“all members of”).
- Note that the two still expand and resolve alike; giving
[] its own meaning in the resolution functions remains
outstanding
- Fixed BCE/CE prose off-by-one error (closed #94, thanks @njbart) to convert to ISO
8601-2 astronomical year numbering (proleptic Gregorian, in which a year
zero exists and equals 1 BCE):
- A historical
N BCE maps to the astronomical year
-(N-1), so "44 BC" becomes -0043
and "1 BC" becomes 0000 (year zero); a signed
ISO year such as "-0044" is already astronomical and is
left unchanged
- Year zero is preserved on input (previously
0000 was
misread as an unspecified year) and is traversed by seq()
and expand(), so a sequence spanning the BCE/CE boundary
now passes through the whole of year 0000 rather than
jumping from -0001 straight to 0001
- Era markers on input are now resolved for each year in an
expression separately, rather than by counting how many markers a string
contains (they are, as before, always removed in the parsed
mdate, which records the era in the sign of the year
alone). So an input marker written once at the end of a range or set
applies to every bound of it: "..200 BC",
"200..100 BC" and "44, 33 BC" now give
..-199, -0199..-0099 and
{-0043,-0032}, where previously the non-leading bounds
silently stayed CE; an input marker written before a date still governs
that date, so "{BC2010-10-10,BC2010-10-11}" gives
{-2009-10-10,-2009-10-11}; and
"200 BC..100 AD" spans the two eras, giving
-0199..0100
- Fixed how era markers could be dropped from approximate or uncertain
dates given in prose, so
"circa 200 BC" is now
~-199 rather than 0200~
Expand/Contract
- Fixed how
expand() handles unspecified years
- Previously
"192X" raised
'from' must be a finite number and "18XX"
silently returned a single date, even though these are what the prose
parser produces for decades and centuries
- Now a bare unspecified year expands to the whole span
(
"192X" gives every day of the 1920s)
- Now an attached month or day picks out that month or day in each
candidate year (
"192X-05-04" gives ten dates, not nine
years of them)
- Now BCE years are bounded the other way round,
-1999
being earlier than -1900
- Now a year too vague to enumerate, such as
"XXXX",
refused with a message suggesting
vmin()/vmax()
- Fixed how
expand() applies unspecified-component rules
to each member of a set separately, fixing over-expansion of sets whose
members had an unspecified month: "{2008-XX-31,2009-XX-31}"
gave 671 dates and now gives 24
- Fixed
contract() returning every set in {}
notation, so that a [] set no longer became a
{} set on a round-trip through
expand()/contract() (closes #99)
- Only applies where
contract() is given an
mdate, since a list of dates does not record which kind of
set its members came from
- Documented what the two set types mean once resolved or operated on,
having established that both should continue to expand to the same
members (closes #99):
?resolve_tendency now distinguishes a central tendency
that describes where several recorded occurrences sit ({})
from one that is a point estimate of a single unknown date
([]), as for a range
?operate_set and ?operate_proportional now
note that a result for a [] set reads as the candidates
that remain possible, or the probability that a comparison holds, rather
than a share of recorded occurrences
messydates 1.0.0
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
- Declared
anytime and clock in Suggests,
since the interoperability tests exercise them where installed
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
- A time of day can now be given on its own, with no date part
(e.g.
as_messydate("2:30pm") -> 14:30,
as_messydate("around 2pm") -> 14:00~); this
requires a clear time signal (a colon-clock or am/pm), so a bare
2019 is still a year, and a bare am/pm hour
(2pm) fills to 14:00. A leading “at”
("at 2:30pm", "at around 2pm") is recognised
and dropped.
hour()/minute()/second()/tz(),
precision(), expand(), and
approximate()/uncertain() all handle date-less
times
- Renamed
messyduration() to
make_messyduration() for consistency with other
make_*() functions, and renamed resulting class from
messyduration to mduration
- Fixed bug where a messyrange would shift instead of widen upon
approximation
Coercion
- Improved parsing of written dates (closed #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
- Improved interoperability with
{lubridate}: its
as_date() and as_datetime() coercion verbs now
work on an mdate, honouring the FUN resolver
(e.g. as_date(md, FUN = vmax)), as do format()
on mdate columns in data frames and tibbles
- Fixed
as.POSIXct()/as.POSIXlt() erroring
on a vector of two or more mdates (the check for
pre-common-era dates was not vectorised)
Annotation
- Renamed
as_approximate()/as_uncertain() to
approximate()/uncertain() for consistency with
on_or_before()/on_or_after() (these aren’t
coercion functions); old names are defunct and warn
- Improved
approximate()/uncertain() to
accept “hour”, “minute”, “second”, and “time” components
- Improved
approximate()/uncertain() to
combine annotations as % when both are applied to the same
component
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()
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 (#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)
- 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)
year(), month(), day(),
hour(), minute(), second(), and
tz() are now S3 methods on the same-named
{lubridate} generics rather than plain functions, so the
two packages can be loaded together (in either order) without one
masking the other: these accessors dispatch to the messy-date logic on
an mdate but to {lubridate}’s own methods on a
Date/POSIXct
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
messydates 0.5.4
Coercion
- Improved how
as_messydates() handles text with dates in
American format, e.g. October 10, 2010 (fixes #86)
messydates 0.5.3
Components
- Improved
year() to be faster and work on durations
- Improved
precision()
precision() is now a S3 generic, dispatching to
precision.mdate()
precision.mdate() now returns the inverse of the
previous measure, meaning maximising precision makes more sense
messydates 0.5.2
Package
- Moved
mreport() to {manydata}
- Consolidated and renamed scripts internally
Coerce to
- Fixed pkgdown#2855 by fixing how as_messydate methods interpret
infinite dates
- Fixed time zone defaults in
as.POSIXct.mdate() and
as.POSIXlt.mdate()
- Fixed set bug in
validate_messydate()
Coerce from
- Renamed
as.numeric() to as.double() to fix
S3 dispatching
- Separated extrema functions into
min.mdate() and
max.mdate() for summaries and vmin.mdate() and
vmax.mdate() for vector coercion
- Separated tendency functions into
mean.mdate(),
median.mdate(), and modal.mdate() for
summaries and vmean.mdate(), vmedian.mdate(),
and vmodal.mdate() for vector coercion
- Vector coercion previously in
random.mdate() now in
vrandom.mdate()
- Improved how coercion/resolution functions handle BCE dates
Manipulation
- Fixed how
precision() calculates precision
messydates 0.5.1
Package
- Fixed redirected url in README
- Fixed pkgdown help links
messydates 0.5.0
Package
- Dropped the vignettes as they were ‘outdated’
- Dropped a number of tests to provide rapid testing framework
- Dropped
{tibble} dependency by just using
{dplyr}
- Updated Github workflows
- Updated testthat to version 3, tests now run in parallel
- Updated pkgdown to bootstrap 5
- Updated DESCRIPTION with config packages
Functions
- Moved from
{stringr} to {stringi} for
speed
- Added
as.numeric.mdate() and
as_messydate.numeric() for coercing between messydates and
numbers (closes #85)
- Added
seq.mdate() for creating sequences from one or
two messydates
- This includes correct sequences for leap years and historical dates
including before the common era
- Added
is_bce() for testing whether dates are from
before the common era
- Added
stri_squish() helper for trimming white space
everywhere
- Improved
c.mdate() so that it will strip class from an
mdate object, as expected
- Improved
is_uncertain() and
is_approximate() so that they also recognise %
annotations
- Improved
min.mdate(), max.mdate(), and
modal.mdate() to avoid using expand() and
consequently run much faster
- Improved
min.mdate(), max.mdate(),
modal.mdate(), mean.mdate(),
median.mdate(), and random.mdate() by adding
recursive argument for resolving vectors down to a
scalar
- Fixed bug in
messyduration.mdate() where the minimum of
an underspecified later date was used
- Fixed bug in
as_messydate() where zero padding for
early dates was not added correctly
messydates 0.4.1
Package
- The package now depends on R versions bigger or equal to 4.0 since
functions for subsetting and comparing ‘mdate’ objects rely on functions
introduced in that version
Functions
- Closed #83 by fixing how logical comparisons works for negative and
year only dates
messydates 0.4.0
Functions
- Closed #46 by adding the
mdates_duration class that
introduces methods to annotate a duration or period with representations
of its uncertainty
- Closed #72 by fixing issues with double unspecified components not
being contracted correctly
- Closed #73 by fixing bugs with the conversion of dates where month
is spelled
- Closed #74 and #82 by adding other logical comparison operators for
‘mdate’ objects (e.g.
<, >,
<=, >=) (thanks @WerthPADOH)
- Closed #76 by adding proportional operators that calculate the
proportion of messy dates meeting logical tests (e.g.
%l%
%le%, %g%, %ge%,
%><%, %>=<%)
- Closed #77 by adding basic vector methods for subsetting and data
frames (thanks @WerthPADOH)
- Added alias function
mdate() for
as_messydate()
- Renamed set family of functions to work as operators
(i.e.
%intersect% and %union%)
- Replaced
is_element() by is_subset() for
clarity and consistency
- Closed #80 by updating
make_messydates() function to
also construct ranges of dates
messydates 0.3.5
Functions
- Updated how
contract() function checks if ‘mdate’
object has been expanded
messydates 0.3.4
Package
- Updated ‘battles’ internal data
- Corrected issues with zero padding for certain date ranges
- Added ‘US_party’ and ‘N_actors’ additional variables for replication
purposes
Functions
- Closed #68 by updating
as_messydate() function
- Fixed bugs with zero padding for ranges of dates
- Fixed bugs with the re-ordering of months and day components for
incorrectly specified dates
- Closed #69 by updating
contract() function to ‘expand’
dates before ‘contracting’ them
- Updated
expand() function to handle, and properly
convert, date objects that are not ‘mdate’
messydates 0.3.3
Package
- Moved cheatsheet.pdf to ‘inst’ folder instead of the ‘man’
folder
messydates 0.3.2
Package
- Closed #64 by updating failing tests to test for other aspects
instead of the printing of negative dates across OS
- Closed #65 by updating cheatsheet for new package changes
Functions
- Closed #62 by adding “resequence” as an argument to
as_messydates() for explicit date format conversion, if
necessary
- Closed #63 by fixing issues with unnecessary white spaces added in
date conversion
messydates 0.3.1
Package
- Updated README by removing unattractive package startup
messages
- Updated
battles data by adding ‘parties’ variable
Functions
- Closed #54 by adding new
mreport() function to properly
report on data containing ‘mdate’ variables
- Updated
expand() function
- Fixed bug with the expansion of approximate dates
- Removed unnecessary function message
messydates 0.3.0
Package
- Closed #51 by changing object class name to
mdate
- Note that this is a breaking change
- Closed #41 by creating
{skimr} template for
mdate class
Functions
- Updated coercion to messy dates
- Closed #26 by adding “resequence” argument to
as_messydate() allowing users to choose component order of
ambiguous dates
- Closed #45 by improving how
as_messydate() re-orders 6
digit date components if necessary
- Closed #48 by adding zero padding incomplete date ranges and sets of
dates
- Updated
as_messydate() to also extract dates from text
strings
- Added
is_precise() function that provides a logical
test for precise dates
- Updated messy dates expansion
- Updated
expand() to allow for the expansion of
incomplete date ranges and sets of dates
- Closed #49 by updating resolve functions to only expand dates if
they are not precise
messydates 0.2.1
Package
- Added a vignette for working with the
{messydates}
package
Functions
- Closed #9 by adding arithmetic operations for working with
messydt objects
- Added S3 methods for “+” and “-” operators
- Added
add() and subtract() helper
functions for arithmetic operations
- Updated
expand() function
- Closed #31 by updating how approximate dates are expanded to account
for leap years
- Closed #34 by updating
expand() to manage negative
dates
- Added
expand_negative_dates() helper function for
expanding ranges of negative dates
- Updated functions that coerce from
messydt objects to
Date to manage negative dates
- Added
negative_dates() helper function to coerce
negative messydt dates
- Closed #39 by updating how resolve mean methods work for negative
dates
- Closed #40 by updating contract function to manage the contraction
of negative dates
- Added
compact_negative_dates() helper function to
compact negative date ranges
- Added
is.sequence() as a helper function to check if
dates are a range
- Updated resequence script to export
interleave()
function
messydates 0.2.0
Package
- Added PANARCHIC project details to README file
- Added cheatsheet
- Added a new CSS style to website and updated functions
displayed
- Addressed workflow actions issues
- Updated pushrelease.yml workflow actions file to stop installing
{messydates} from Github
- Updated README file to stop installing
{messydates}
from Github
- Fixed Codecov test coverage URL on README file for CRAN
submission
Functions
- Expanded on messydates checks for class validity
- Fixed bugs for
make_messydate()
- Added annotation functions and standardized annotation so that it is
consistent with ISO2019E standards.
on_or_before()
on_or_after()
as_approximate()
as_uncertain() (includes discrimination between month
uncertainty and day and month uncertainty)
- Updated
as_messydate() by adding zero padding for
month, day or year
- Updated
resequence() to work consistently with
messydate objects
- Updated
expand() function to expand imprecise,
unspecified, approximate, uncertain, and negative dates according to
approximate ranges and added tests
- Updated
precision() to return the lengths of expanded
dates
- Updated
median() in resolve family of functions to work
with changes to expand()
- Added tests for functions
- Added tests for
expand()
- Added tests for
contract()
- Added tests for
precision()
- Added tests for
coerce_from_messydate()
messydates 0.1.1
Package
- Updated README with some more explanation about what the package
does/offers
- Fixed URL to the package website
messydates 0.1.0
Package
- Updated call to
messydt class in DESCRIPTION file
Functions
- Updated documentation for
as_messydate() functions
- Updated documentation for
expand() function
- Updated documentation for resolve family of functions
- Updated documentation for coerce from family of functions
- Updated documentation for coerce to family of functions
messydates 0.0.1
Package
- Setup
{messydates} package
- Added
DESCRIPTION file
- Added
R folder
- Added
LICENSE file
- Added
NAMESPACE file
- Added
NEWS file
- Added
README files
- Added
.github folder and files
- Added
tests folder and files
- Setup pkgdown website
- Added package logo
Functions
- Added a new
messydt class which follows the latest ISO
8601 (2019) standards
- Added validation checks for messydt class
- Added print methods for messydt class
- Added
as_messydate() function to coerce from date
objects to messydate
as_messydate() standardises date order, separators and
ambiguity
- Added date class coercion
- Added POSIXct class coercion
- Added POSIXlt class coercion
- Added character class coercion
- Added functions to coerce from messydate objects to other date
classes
- Added
as.Date.messydt() for coercing to date class
- Added
as.POSIXct.messydt() for coercing to POSIXct
class
- Added
as.POSIXlt.messydt() for coercing to POSIXlt
class
- Added
expand() function for expanding ranged and
uncertain dates
- Added functions to resolve expanded dates
- Added
min.messydt() to get minimum value from expanded
range
- Added
max.messydt() to get maximum value from expanded
range
- Added
median.messydt() to get median value from
expanded range
- Added
mean.messydt() to get mean value from expanded
range
- Added
modal.messydt() to get mode value from expanded
range
- Added
contract() function for contracting expanded
dates
- Added extract functions to get particular date components
- Added
year() to extract year from date
- Added
month() to extract month from date
- Added
day() to extract day from date
- Added
make_messydate() function to get messy dates from
multiple columns
- Added set functions for operations in sets of messy dates
- Added
md_intersect() to find intersection of sets of
messy dates
- Added
md_union() to find union of sets of messy
dates
- Added
md_multiset() to join two sets of messy
dates
- Added logical function for various logical tests for messy date
objects
- Added
is_messydate() to test for messydt class
- Added
is_intersecting() to test if dates intersect
- Added
is_element() to test for multiple elements in
dates
- Added
is_similar() to test for similarities in
dates
- Added tests for new functions
- Added tests for messydt class and
às_messydate()
function
- Added tests for coerce from messy dates functions
- Added tests for coerce to messy dates functions
- Added tests for
contract() function
- Added tests for
expand() function
- Added tests for extract functions
- Added tests for
make_messydate() function
- Added tests for resolve functions
- Added tests for set functions