---
title: "Years with an era"
output: 
  rmarkdown::html_vignette:
    toc: true
    toc_depth: 2
vignette: >
  %\VignetteIndexEntry{Years with an era}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r include=FALSE}
this_year <- as.integer(format(Sys.Date(), "%Y"))
```

Archaeologists, geologists, and other palaeoscientists use different systems for numbering years in the distant past.
For example, the year 10,000 BCE is 11,950 [Before Present](https://en.wikipedia.org/wiki/Before_Present) or 11.95 [ka](https://en.wikipedia.org/wiki/Year#Symbols).
It is usually fine to store years as a plain numeric vector in R, but sometimes it helps to be explicit about which system is being used:

* When you have data that mixes different systems
* When you want to transform years between different systems
* When you need to do arithmetic with years

The **era** package helps in these cases by providing classes which define the 'era' associated with a vector of years and functions for formatting, combining, and transforming years with different eras.
This vignette is an introduction to the main features of the package.

```{r setup, message=FALSE}
library("era")
library("tibble")
library("dplyr")
```

## Years with an era {#yr}

Vectors of years with an era are represented by the `yr` (`era_yr`) class, which is constructed with `yr()`:

```{r yr}
yr(c(10000, 11000, 12000), "BP")
```

The first argument is a numeric vector of years.
These can be integers or doubles.

The second argument, `era`, defines the numbering system associated with the years.
This is an object of class `era` which defines the [parameters of the calendar, epoch and time scale](#era).
Most of the time, you can simply specify the abbreviated label of the era, which will be looked up in the standard eras defined by `eras()`:

```{r yr-era-eg}
yr(c(10000, 11000, 12000), "BCE")
yr(c(10000, 11000, 12000), "uncal BP")
yr(c(10000, 11000, 12000), "ka")
```

`yr_era()` returns details of the era associated with a `yr` vector:

```{r yr-era-get}
neolithic <- yr(11700:7500, "BP")
yr_era(neolithic)
```

`yr_era()`, and its pipe-friendly alias `yr_set_era()`, can also be used to set the era of an existing object:

```{r yr-era-set}
chalcolithic <- 7500:6000
yr_era(chalcolithic) <- yr_era(neolithic)
yr_era(chalcolithic)
```

Note that this only updates the vector's era attribute; it doesn't change the data itself.
To *convert* years from one era to another, you need to use [the `yr_transform()` function](#yr_transform).

`yr` vectors fit nicely into tables, both base data frames and tibbles:

```{r eg-tbl}
postglacial <- tribble(
  ~period,           ~start_ka,
  "Late Holocene",   4.2,
  "Mid Holocene",    8.326,
  "Early Holocene",  11.7,
  "Younger Dryas",   12.9,
  "Bølling-Allerød", 14.7,
  "Heinrich 1",      17.0
)

postglacial |> 
  mutate(start_ka = yr(start_ka, "ka"))
```

## Era definitions {#era}

era includes built-in definitions of many time scales and year numbering systems from contemporary and historic calendars.
`eras()` returns the [full list](#era-list) of built-in definitions. 
You can use any definition in this list by passing its abbreviated `label` to `era()` or as the `era` argument of `yr()` or any other function in the package:

```{r eg-use-era}
era("BP")

yr(10000, "BP")

yr_transform(yr(10000, "BP"), "BCE")
```

If you need to use a time scale that is not in this list, you can [define it yourself](#defining-other-eras) with `era()`.
Suggestions for new eras to include in the package are also welcome; please [create an issue](https://github.com/joeroe/era/issues) on GitHub with suggestions.

### List of built-in eras {#era-list}

```{r era-table, echo=FALSE}
all_eras <- eras() 
all_eras$this_year <- NA
na_era <- is.na(era_year_days(all_eras$unit))
all_eras$this_year[!na_era] <- this_year(all_eras$label[!na_era])

knitr::kable(all_eras)
```

### Defining other eras

Eras are defined by the `era` class with the following parameters:

* **label**: an abbreviated label that uniquely identifies the era
* **name**: the full name of the era
* **epoch**: the origin year from which years are counted (in Gregorian astronomical years)
* **unit**: the unit of years counted, defined as its length in solar days
* **scale**: the number of years represented by one unit
* **direction**: whether years are counted forwards (`1`) or backwards (`-1`) from the epoch

These parameters are passed to `era()` to construct an `era` object.
`epoch`, `unit`, `scale`, and `direction` determine the transformation between eras;
`label` and `name` are purely descriptive.

You can define arbitrary eras by using the `era()` function directly:

```{r custom-era}
era("T.A.", epoch = -9021, name = "Third Age", direction = 1)
```

As long as all the parameters are specified correctly, user-defined eras can also be used in `yr_transform()`.

## Converting between eras: `yr_transform()` {#yr_transform}

Use `yr_transform()` to convert between eras:

```{r transform}
postglacial |> 
  mutate(start_ka = yr(start_ka, "ka")) |> 
  mutate(start_bp = yr_transform(start_ka, era("BP")),
         start_bce = yr_transform(start_ka, era("BCE")))
```

This function implements a generic algorithm for transforming years based on the era parameters described above.
This means that, with a few exceptions (see [invalid transformations](#invalidtransform), you can transform between any two eras that can be described by the `era` class.

### Transformation precision

By default, era transformations are exact:

```{r yr-transform-precision1}
yr(500000, "BCE") |> 
  yr_transform(era("ka"))
```

Often, this precision is not necessary.
For example, when converting years between calendar- and present-based eras, the `r this_year - 1950` year difference between the formal definition of "Present" and the actual present is rarely significant on a geologic time scale.
Use the `precision` argument of `yr_transform` to get rounded results:

```{r yr-transform-precision2}
yr(10000, "BP") |> 
  yr_transform(era("BCE"), precision = 1000)

yr(500000, "BCE") |> 
  yr_transform(era("mya"), precision = 0.1)
```

### Invalid transformations {#invalidtransform}

Some transformations are not possible.
Notably, the length of a 'radiocarbon year' is not well defined on a calendar time scale without [calibration](https://en.wikipedia.org/wiki/Radiocarbon_calibration).
Eras that use non-calendar year unit are represented with an `NA` and will cause an error if passed to `yr_transform()`:

```{r transform-unit, error=TRUE}
era_unit(era("uncal BP"))
yr_transform(yr(9000, "uncal BP"), era("cal BP"))
```

`c14_calibrate()` from the [stratigraphr](https://stratigraphr.joeroe.io) package implements radiocarbon calibration with `yr` objects.

Conversion between eras that both have an `NA` unit are also an error, following the R convention that `NA == NA` is `NA`.
In other words, we don't know whether two non-calendar units are the *same* non-calendar unit.
This means that it is not possible to use `yr_transform()` to convert bp (radiocarbon years Before Present) to bce (radiocarbon years before the Common Era) years, for example.

## Arithmetic with year vectors {#arithmetic}

The `yr` class is based on [vctrs](https://vctrs.r-lib.org/), ensuring type- and size-stable computations.
For example, you can do arithmetic with year vectors:

```{r yr-arith}
a <- yr(1500, "CE")
b <- yr(2020, "CE")
b - a
```

But only when they have the same era:

```{r yr-arith-error, error=TRUE}
c <- yr(0.5, "ka")
b - c
```

Note that, when comparing eras, only the parameters significant to the transformation are considered (i.e. not `label` or `name`).
This means that it is possible to combine year vectors with differently-named but functionally equivalent eras, for example `era("BP")` and `era("cal BP")`, although doing so will print a warning about the loss of information:

```{r era-equality}
era("BP") == era("BC")
era("BP") == era("cal BP")

yr(1000, "BP") + yr(1000, "cal BP")
```


Years will be coerced to a plain numeric vector if a computation means their era no longer makes sense:

```{r yr-multiply}
a * b
```