GeodeticCuriosity
GeodeticCuriosity

Reputation: 41

Converting from Ordinal Time to Date-Time in Python

I want to convert a precise ordinal time array (see below) to date-time format (YYYY-MM-DD hh:mm:ss.sss) in anaconda/python 3. I cannot find any solutions to this problem that considers the precision of the original data.

The ordinal time array looks like:

[[733414.07083333]
 [733414.07430556]
 [733414.07777778]
 ...
 [737654.10902778]
 [737654.1125    ]
 [737654.11597222]]

datetime.fromordinal only works for integer numbers and the decimals MUST be considered in order to obtain the time component to the decimal second.

Upvotes: 1

Views: 2722

Answers (2)

Aloex
Aloex

Reputation: 103

I was facing a similar issue and found a faster way to convert from ordinal to datetime, which is done in your first function.

import datetime
def OrdinalToDatetime(ordinal):
    plaindate = datetime.date.fromordinal(int(ordinal))
    date_time = datetime.datetime.combine(plaindate, datetime.datetime.min.time())
    return date_time + datetime.timedelta(days=ordinal-int(ordinal))

The output would be in case of today OrdinalToDatetime(737998.46643556)

Out[1]: datetime.datetime(2021, 7, 27, 11, 11, 40, 32386)

Upvotes: 1

GeodeticCuriosity
GeodeticCuriosity

Reputation: 41

Thanks to a tip from a friend, who directed me to another website (https://www.programcreek.com/python/example/100062/datetime.datetime.fromordinal), I have found a solution to this challenge. This is the modified script that I used to convert ordinal time to date-time:

import numpy as _np
import datetime
from datetime import date

def _from_ordinal(x, tz=None) :
    ix = int(x)
    dt = date.fromordinal(ix)
    remainder = float(x) - ix
    hour, remainder = divmod(24 * remainder, 1)
    minute, remainder = divmod(60 * remainder, 1)
    second, remainder = divmod(60 * remainder, 1)
    microsecond = int(1e6 * remainder)
    # compensate for rounding errors
    if microsecond < 10 :
        microsecond = 0                             
    elif microsecond > 999990 : 
        microsecond = _np.subtract(1000000,microsecond)
    dt = datetime.datetime(dt.year, dt.month, dt.day, int(hour), int(minute), int(second), microsecond)
    dt = dt.isoformat(timespec='microseconds')
    if tz is not None:
        dt = dt.astimezone(tz)
    return dt

arrayDateTime = []
for i in range(0,len(arrayOrdinalTime)) :
    dateTime = _from_ordinal(arrayOrdinalTime[i])
    dateTime = dateTime.replace('T', ' ')
    arrayDateTime = _np.append(arrayDateTime, dateTime)

Please note, because of the for-loop in this script, processing can take a long time if teh data set is large. I tried to make this work directly with an array, but it failed.

Any tips to make this work directly with an array, therefore to save time, would be appreciated.

Upvotes: 1

Related Questions