Automatic related software tables
The purpose of this page is to automatically get publication dates off CRAN Archive web pages.
To construct a related work table for a paper, we want publication dates from CRAN packages.
As mentioned in my previous post about data.table’s 20th birthday, we can download the CRAN archive meta-data via:
adb <- tools::CRAN_archive_db()
head(adb)
## $a11yShiny
## size isdir mode mtime ctime atime uid gid
## a11yShiny/a11yShiny_0.1.3.tar.gz 71907 FALSE 664 2026-03-30 15:20:21 2026-07-28 00:04:54 2026-07-28 00:54:13 1010 1001
## uname grname
## a11yShiny/a11yShiny_0.1.3.tar.gz ligges cranadmin
##
## $A3
## size isdir mode mtime ctime atime uid gid uname
## A3/A3_0.9.1.tar.gz 45252 FALSE 664 2013-02-07 04:00:29 2026-07-28 00:04:52 2026-07-27 20:42:44 1001 1001 hornik
## A3/A3_0.9.2.tar.gz 45907 FALSE 664 2013-03-26 14:58:40 2026-07-28 00:04:52 2026-07-27 20:42:41 1010 1001 ligges
## A3/A3_1.0.0.tar.gz 42810 FALSE 664 2015-08-16 17:05:54 2026-07-28 00:04:52 2026-07-28 01:00:20 1001 1001 hornik
## grname
## A3/A3_0.9.1.tar.gz cranadmin
## A3/A3_0.9.2.tar.gz cranadmin
## A3/A3_1.0.0.tar.gz cranadmin
##
## $a5R
## size isdir mode mtime ctime atime uid gid uname
## a5R/a5R_0.2.0.tar.gz 3685016 FALSE 664 2026-03-16 15:10:23 2026-07-28 00:04:54 2026-07-28 01:00:25 1010 1001 ligges
## a5R/a5R_0.3.1.tar.gz 3706043 FALSE 664 2026-03-26 08:30:08 2026-07-28 00:04:54 2026-07-28 01:00:26 1010 1001 ligges
## a5R/a5R_0.4.0.tar.gz 3579867 FALSE 664 2026-05-14 09:00:11 2026-07-28 00:04:54 2026-07-28 00:55:51 1010 1001 ligges
## grname
## a5R/a5R_0.2.0.tar.gz cranadmin
## a5R/a5R_0.3.1.tar.gz cranadmin
## a5R/a5R_0.4.0.tar.gz cranadmin
##
## $aamatch
## size isdir mode mtime ctime atime uid gid
## aamatch/aamatch_0.3.7.tar.gz 222104 FALSE 664 2025-06-24 05:40:05 2026-07-28 00:04:54 2026-07-28 01:00:36 1010 1001
## uname grname
## aamatch/aamatch_0.3.7.tar.gz ligges cranadmin
##
## $aaMI
## size isdir mode mtime ctime atime uid gid uname
## aaMI/aaMI_1.0-0.tar.gz 2968 FALSE 664 2005-06-24 11:55:17 2026-07-28 00:04:52 2026-07-28 01:00:34 0 1001 root
## aaMI/aaMI_1.0-1.tar.gz 3487 FALSE 664 2005-10-17 15:24:18 2026-07-28 00:04:52 2026-07-28 01:00:34 0 1001 root
## grname
## aaMI/aaMI_1.0-0.tar.gz cranadmin
## aaMI/aaMI_1.0-1.tar.gz cranadmin
##
## $aaSEA
## size isdir mode mtime ctime atime uid gid
## aaSEA/aaSEA_1.0.0.tar.gz 1474389 FALSE 664 2019-08-01 05:10:08 2026-07-28 00:04:52 2026-07-28 01:00:34 1010 1001
## aaSEA/aaSEA_1.1.0.tar.gz 1531632 FALSE 664 2019-11-09 11:20:04 2026-07-28 00:04:52 2026-07-28 01:00:36 1010 1001
## uname grname
## aaSEA/aaSEA_1.0.0.tar.gz ligges cranadmin
## aaSEA/aaSEA_1.1.0.tar.gz ligges cranadmin
Above we see a list of matrices, one per package.
Below we define the packages of interest by parsing an org-mode readme file using a regular expression.
(pdt <- nc::capture_all_str(
"~/projects/sparse-label-positions/README.org",
" ",
pkg="[^ ]+?",
"::"))
## pkg
## <char>
## 1: monreg
## 2: fdrtool
## 3: cir
## 4: Iso
## 5: clue
## 6: logcondens
## 7: sandwich
## 8: intcox
## 9: SAGx
## 10: smacof
## 11: isotone
## 12: quadprog
Above we see a table with one row per package of interest.
Below we query the current CRAN web pages to determine if each package is currently published.
pdt[, available := {
tfile <- file.path(tempdir(), pkg)
if(!file.exists(tfile)){
u <- sprintf("https://cloud.r-project.org/web/packages/%s", pkg)
download.file(u, tfile)
}
adt <- nc::capture_all_str(tfile, dl="tar.gz")
nrow(adt)>0
}, by=pkg][]
## pkg available
## <char> <lgcl>
## 1: monreg TRUE
## 2: fdrtool TRUE
## 3: cir TRUE
## 4: Iso TRUE
## 5: clue TRUE
## 6: logcondens TRUE
## 7: sandwich TRUE
## 8: intcox FALSE
## 9: SAGx FALSE
## 10: smacof TRUE
## 11: isotone TRUE
## 12: quadprog TRUE
Above we see that all but two packages are currently available.
Below we create a data table for packages of interest.
library(data.table)
(time.dt <- pdt[
, as.data.table(adb[[paste(pkg)]])[, .(mtime)], by=.(pkg=factor(pkg, pkg), available)
][
, year := strftime(mtime, "%Y")
][])
## pkg available mtime year
## <fctr> <lgcl> <POSc> <char>
## 1: monreg TRUE 2009-02-25 03:29:22 2009
## 2: monreg TRUE 2013-02-14 09:47:21 2013
## 3: monreg TRUE 2015-03-04 15:31:32 2015
## 4: monreg TRUE 2020-04-26 03:00:11 2020
## 5: monreg TRUE 2006-01-30 15:10:27 2006
## ---
## 256: quadprog TRUE 2010-04-09 13:30:51 2010
## 257: quadprog TRUE 2011-05-12 06:25:50 2011
## 258: quadprog TRUE 2013-04-17 07:42:50 2013
## 259: quadprog TRUE 2019-04-26 09:21:16 2019
## 260: quadprog TRUE 2019-05-06 15:00:04 2019
Above we see a table with one row per publication time, per package of interest.
Below we reshape to one row per package:
time.wide <- dcast(
time.dt,
pkg + available ~ .,
list(min, max),
value.var=c("mtime", "year")
)[
, years := sprintf("%s–%s", year_min, year_max)
][]
time.wide[, .(pkg, available, years)]
## Key: <pkg, available>
## pkg available years
## <fctr> <lgcl> <char>
## 1: monreg TRUE 2006–2020
## 2: fdrtool TRUE 2006–2021
## 3: cir TRUE 2008–2024
## 4: Iso TRUE 2008–2020
## 5: clue TRUE 2004–2026
## 6: logcondens TRUE 2006–2023
## 7: sandwich TRUE 2004–2026
## 8: intcox FALSE 2006–2013
## 9: SAGx FALSE 2005–2006
## 10: smacof TRUE 2008–2024
## 11: isotone TRUE 2009–2023
## 12: quadprog TRUE 1999–2019
Above we see the packages presented in the same order as they were defined.
time.wide[order(mtime_min), .(pkg, available, years)]
## pkg available years
## <fctr> <lgcl> <char>
## 1: quadprog TRUE 1999–2019
## 2: sandwich TRUE 2004–2026
## 3: clue TRUE 2004–2026
## 4: SAGx FALSE 2005–2006
## 5: monreg TRUE 2006–2020
## 6: intcox FALSE 2006–2013
## 7: fdrtool TRUE 2006–2021
## 8: logcondens TRUE 2006–2023
## 9: cir TRUE 2008–2024
## 10: Iso TRUE 2008–2020
## 11: smacof TRUE 2008–2024
## 12: isotone TRUE 2009–2023
Above packages are sorted by first publication date.
Below packages are sorted by last publication date.
time.wide[order(mtime_max), .(pkg, available, years)]
## pkg available years
## <fctr> <lgcl> <char>
## 1: SAGx FALSE 2005–2006
## 2: intcox FALSE 2006–2013
## 3: quadprog TRUE 1999–2019
## 4: monreg TRUE 2006–2020
## 5: Iso TRUE 2008–2020
## 6: fdrtool TRUE 2006–2021
## 7: isotone TRUE 2009–2023
## 8: logcondens TRUE 2006–2023
## 9: smacof TRUE 2008–2024
## 10: cir TRUE 2008–2024
## 11: clue TRUE 2004–2026
## 12: sandwich TRUE 2004–2026
Conclusions
We have shown how to get CRAN publication dates for a list of R packages of interest.
session info
sessionInfo()
## R Under development (unstable) (2026-07-28 r90311)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.4 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.12.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0 LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=fr_FR.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=fr_FR.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=fr_FR.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C
##
## time zone: America/Toronto
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] data.table_1.18.4
##
## loaded via a namespace (and not attached):
## [1] compiler_4.7.0 nc_2026.4.20 cli_3.6.6 tools_4.7.0 knitr_1.51 xfun_0.60 rlang_1.3.0
## [8] evaluate_1.0.5