Dates References: A Timely Affair
Tags: programming, softwareengineering, softwaredevelopment, codequality
Published: 2024-06-12 19:35:15

**One notation to rule them all**

For some time now, I've been working on a [Web App framework](https://github.com/equalframework/equal), and this led me to think about a lot of things, amongst which data typing.

eQual provides a structured way to reference dates allowing to describe and retrieve any date based on the current date, which can be used in Domains for filtering or conditioning visibility. 

Date References allow to reference dates relatively to various intervals and dynamically compute dates for a wide range of scenarios by combining methods and parameters.



A **Date Reference** descriptor is built using the following structure : 

```
date.<origin>(<offset>).<interval>.<method>(<arguments>)
```
or, in a more explicit notation : 
```
date.{this|prev|next}[(<offset>)].{day|week|month|quarter|semester|year}.{first|last|get(reference:index)}
```


### Attributes and Arguments

#### 1. Origin

| Method     | Description                                          | Offset | Possible Values          |
|------------|------------------------------------------------------|--------|--------------------------|
| prev(n)    | Previous period with an offset of n intervals        | n > 0  | `prev`, `prev(n)`        |
| next(n)    | Next period with an offset of n intervals            | n > 0  | `next`, `next(n)`        |
| this()     | Current period (n=0 by default)                      | n = 0  | `this`, `this(0)`        |

#### 2. Interval

| Interval   | Description        |
|------------|--------------------|
| day        | Day                |
| week       | Week               |
| month      | Month              |
| quarter    | Quarter            |
| semester   | Semester           |
| year       | Year               |

#### 3. Method

| Method     | Description                          |
|------------|--------------------------------------|
| first()    | First day of the interval            |
| last()     | Last day of the interval             |
| get()      | Get a specific date with arguments   |



### Tables of Possible Values

#### Origin

| Method     | Possible Values                   |
|------------|------------------------------------|
| `prev(<increment>)` | `prev`, `prev(0)`, `prev(n)` (n ≥ 0) |
| `next(<increment>)` | `next`, `next(0)`, `next(n)` (n ≥ 0) |
| `this()`   | `this`, `this(0)`                  |

#### Interval

| Interval   | Description |
| ---------- | ----------- |
| `day`      | Day         |
| `week`     | Week        |
| `month`    | Month       |
| `quarter`  | Quarter     |
| `semester` | Semester    |
| `year`     | Year        |

#### Method

Methods can be applied on the chosen interval (except for `day`, for which the method has no effect).

| Method     | Description                           |
|------------|---------------------------------------|
| first()    | First day of the interval             |
| last()     | Last day of the interval              |
| get()      | Get a specific date                   |

#### Arguments for the `get()` Method

| Argument                    | Concerned Interval               | Possible Values                                 |
|-----------------------------|-----------------------------------|-------------------------------------------------|
| day:<number>                | month, quarter, semester, year   | Month: `day:1` to `day:31`<br>Year: `day:1` to `day:365` |
| week:<number>               | month, quarter, semester, year | `week:1` to `week:52` (or `week:53`)            |
| <day_of_week>:first         | month, quarter, semester, year | `monday:first` to `sunday:first`                |
| <day_of_week>:last          | month, quarter, semester, year | `monday:last` to `sunday:last`                  |
| <day_of_week>:<number>      | month, quarter, semester, year | `monday:1` to `monday:5` (month)<br>`monday:1` to `monday:14` (quarter)<br>`monday:1` to `monday:26` (semester)<br>`monday:1` to `monday:52` (or `monday:53`) (year) |

### Usage Examples

* **today**
    ```
    date.this.day
    ```

* **Seven days from now**
    ```
    date.next(7).day
    ```
    
* **First day of the month 5 months before the current month:**
    ```
    date.prev(5).month.first()
    ```
   
* **Last day of the quarter 2 quarters after the current quarter:**
    ```
    date.next(2).quarter.last()
    ```

* **34th week of the next year:**
    ```
    date.next(1).year.get(week:34)
    ```

* **First Monday of the semester 3 semesters before the current semester:**
    ```
    date.prev(3).semester.get(monday:first)
    ```

* **Second Wednesday of the month 4 months after the current month:**
    ```
    date.next(4).month.get(wednesday:2)
    ```

* **first day of current year:**
    ```
    date.this.year.first
    ```
    or
    ```
    date.this.year.get(day:1)
    ```