ENH: add origin to to_datetime
State: closed

closes #11276
closes #11745

superseded #11470 

Labels:
name: Enhancement
name: Datetime
description: Datetime data dtype

Comments:
@jorisvandenbossche @chris-b1 

ok, rebase and updated original PR. pls have  a look.

IIRC there were some more test cases needed, but dont' really remember 
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=h1) Report
> Merging [#15828](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/67cc0213def8b9f56c4d1f71bb95ebef22790b24?src=pr&el=desc) will **decrease** coverage by `0.03%`.
> The diff coverage is `91.11%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/15828/graphs/tree.svg?token=eZ4WkYLtcO&width=650&src=pr&height=150)](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #15828      +/-   ##
==========================================
- Coverage   90.98%   90.95%   -0.04%     
==========================================
  Files         143      143              
  Lines       49449    49464      +15     
==========================================
- Hits        44993    44991       -2     
- Misses       4456     4473      +17
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `?` | |
| #single | `?` | |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/tseries/tdi.py](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree#diff-cGFuZGFzL3RzZXJpZXMvdGRpLnB5) | `90.37% <100%> (+0.03%)` | :arrow_up: |
| [pandas/tseries/tools.py](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree#diff-cGFuZGFzL3RzZXJpZXMvdG9vbHMucHk=) | `85.2% <90.24%> (+0.26%)` | :arrow_up: |
| [pandas/io/gbq.py](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree#diff-cGFuZGFzL2lvL2dicS5weQ==) | `25% <0%> (-58.34%)` | :arrow_down: |
| [pandas/io/packers.py](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree#diff-cGFuZGFzL2lvL3BhY2tlcnMucHk=) | `87.57% <0%> (-0.94%)` | :arrow_down: |
| [pandas/core/common.py](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvY29tbW9uLnB5) | `90.96% <0%> (-0.34%)` | :arrow_down: |
| [pandas/io/html.py](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree#diff-cGFuZGFzL2lvL2h0bWwucHk=) | `84.48% <0%> (-0.33%)` | :arrow_down: |
| [pandas/core/series.py](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvc2VyaWVzLnB5) | `94.86% <0%> (-0.11%)` | :arrow_down: |
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.56% <0%> (-0.1%)` | :arrow_down: |
| [pandas/compat/numpy/function.py](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree#diff-cGFuZGFzL2NvbXBhdC9udW1weS9mdW5jdGlvbi5weQ==) | `94.19% <0%> (-0.04%)` | :arrow_down: |
| [pandas/core/indexing.py](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhpbmcucHk=) | `94.08% <0%> (-0.03%)` | :arrow_down: |
| ... and [6 more](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=footer). Last update [67cc021...ebb4acd](https://codecov.io/gh/pandas-dev/pandas/pull/15828?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
ok changed ``epoch`` -> ``unix`` and updated docs.
Some cases where something goes wrong:

* This should raise an error (if the origin is first processed and the argument adapted for it, then this will raise an error):

    ```
    In [2]: pd.to_datetime("2005-01-01", origin="1960-01-01")
    Out[2]: Timestamp('1995-01-01 00:00:00')
    ```

* Not sure how this can return 12:00 as the hour? (EDIT -> this is probably just the definition? "starting at noon")

    ```
    In [4]: pd.to_datetime(2456658, origin='julian', unit='D')
    Out[4]: Timestamp('2013-12-31 12:00:00')
    ```

* The error message in case of out of bounds here:

    ```
    In [3]: pd.to_datetime(1, origin="julian", unit='D')
    ....
    OutOfBoundsDatetime: cannot convert input -2440586.5 with the unit 'D'
    ```

    is a bit unfortunate (the "input -2440586.5"). But that is of course the consequence of processing the origin first and adapting the arg based on that, before passing to the actual parsing methods ... (so that's a clear drawback of this approach I suggested also for the other origins). Not sure whether this could easily be solved ..
Here are the results with new push.

```
In [1]: pd.to_datetime(200*365, unit='D')
Out[1]: Timestamp('2169-11-13 00:00:00')

In [2]: pd.to_datetime(200*365, unit='D', origin='1870-01-01')
Out[2]: Timestamp('2069-11-13 00:00:00')

In [3]: pd.to_datetime(300*365, unit='D', origin='1870-01-01')
Out[3]: Timestamp('2169-10-20 00:00:00')

In [4]: pd.to_datetime("2005-01-01", origin="1960-01-01")
ValueError: '2005-01-01' is not compatible with origin='1960-01-01'; it must be numeric with a unit specified 

In [5]: pd.to_datetime(2456658, origin='julian', unit='D')
Out[5]: Timestamp('2013-12-31 12:00:00')

In [6]: pd.to_datetime(1, origin="julian", unit='D')
OutOfBoundsDatetime: 1 is Out of Bounds for origin='julian'
```

note [1], [2] (were correct before)
[5] seems fine as well.
@jorisvandenbossche make those changes and merged. thanks for the review.
And thanks for picking up the PR!