最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - numpy timedelta highest unit without loss of information - Stack Overflow

programmeradmin1浏览0评论

I have several numpy timedelta values. I want to convert them to the a format that is better to read for humans without losing information.
Let's say I have td = np.timedelta64(10800000000001, 'ns'). Then I can only have it in ns because if I convert it to msor higher it will lose information. If I have td = np.timedelta64(1080000000000, 'ns') I can convert it to 3 hours without losing information. What is a good way to do this automatically?
I tried it by taking the number of trailing zeros into account:

import numpy as np

if __name__ == "__main__":
    td = np.timedelta64(10800000000001, 'ns')
    number_of_zeros = len(str(td.item())) - len(str(td.item()).rstrip('0'))
    if number_of_zeros==0:
        print("[ns]")
    elif number_of_zeros<7:
        print("ms")
    elif number_of_zeros<10:
        print("s")
    elif number_of_zeros<12:
        print("min")
    else:
        print("h")

This is probably not a very elegant way to do it (not to mention that it will be wrong when we get to minutes and higher). Any recommendations?

I have several numpy timedelta values. I want to convert them to the a format that is better to read for humans without losing information.
Let's say I have td = np.timedelta64(10800000000001, 'ns'). Then I can only have it in ns because if I convert it to msor higher it will lose information. If I have td = np.timedelta64(1080000000000, 'ns') I can convert it to 3 hours without losing information. What is a good way to do this automatically?
I tried it by taking the number of trailing zeros into account:

import numpy as np

if __name__ == "__main__":
    td = np.timedelta64(10800000000001, 'ns')
    number_of_zeros = len(str(td.item())) - len(str(td.item()).rstrip('0'))
    if number_of_zeros==0:
        print("[ns]")
    elif number_of_zeros<7:
        print("ms")
    elif number_of_zeros<10:
        print("s")
    elif number_of_zeros<12:
        print("min")
    else:
        print("h")

This is probably not a very elegant way to do it (not to mention that it will be wrong when we get to minutes and higher). Any recommendations?

Share Improve this question asked Mar 12 at 14:11 AkariYukariAkariYukari 3731 gold badge6 silver badges19 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 2

If I understand the problem statement, you only want to express the time in terms of one unit: the largest that retains precision using only whole numbers.

import numpy as np
td = np.timedelta64(10800000000000, 'ns')
units = ['h', 'm', 's', 'ms', 'ns']

# Convert to each of the desired units
deltas = [td.astype(f'timedelta64[{unit}]') for unit in units]
# Retain only the ones that are equivalent to the original representation
delta = [delta for delta in deltas if delta == td]
delta[0]  # extract the zeroth
# np.timedelta64(3,'h')

It it a little faster to divide the integer representation of the timedelta by the the number of nanoseconds in each unit and check whether the result is a whole number.

# Check whether the number of nanoseconds in each unit is a whole number
divisible = np.divmod(td.astype(int), ns_per_unit)[1] == 0
# Use the first unit for which this is true
unit = units[np.where(divisible)[0][0]]
td.astype(f'timedelta64[{unit}]')  # perform the conversion

But the first bit of code is probably a little easier to interpret. Depends on what your goals are.

Can you leverage divmod() to retain accuracy and produce a human readable result?

import numpy as np

def convert_timedelta(delta):
    days, hours = divmod(delta, np.timedelta64(1, 'D'))
    hours, minutes = divmod(hours, np.timedelta64(1, 'h'))
    minutes, seconds = divmod(minutes, np.timedelta64(1, 'm'))
    seconds, miliseconds = divmod(seconds, np.timedelta64(1, 's'))
    miliseconds, nanoseconds = divmod(miliseconds, np.timedelta64(1, 'ms'))
    nanoseconds = nanoseconds.astype(int)

    result = []
    if days:
        result.append("{days!s} days".format(days=days))
    if hours:
        result.append("{hours!s} hours".format(hours=hours))
    if minutes:
        result.append("{minutes!s} minutes".format(minutes=minutes))
    if seconds:
        result.append("{seconds!s} seconds".format(seconds=seconds))
    if miliseconds:
        result.append("{miliseconds!s} miliseconds".format(miliseconds=miliseconds))
    if nanoseconds:
        result.append("{nanoseconds!s} nanoseconds".format(nanoseconds=nanoseconds))

    return " and ".join(result)

delta = np.timedelta64(10800000000001, 'ns')
print(f"{delta} is {convert_timedelta(delta)}")

import random
for _ in range(10):
    delta += np.timedelta64(random.randint(1, 100_000_000_000_00), 'ns')
    print(f"{delta} is {convert_timedelta(delta)}")

Giving you something like:

10800000000001 nanoseconds is 3 hours and 1 nanoseconds
17968658658269 nanoseconds is 4 hours and 59 minutes and 28 seconds and 658 miliseconds and 658269 nanoseconds
20543044526616 nanoseconds is 5 hours and 42 minutes and 23 seconds and 44 miliseconds and 526616 nanoseconds
29015180689078 nanoseconds is 8 hours and 3 minutes and 35 seconds and 180 miliseconds and 689078 nanoseconds
37145263105940 nanoseconds is 10 hours and 19 minutes and 5 seconds and 263 miliseconds and 105940 nanoseconds
41286247283586 nanoseconds is 11 hours and 28 minutes and 6 seconds and 247 miliseconds and 283586 nanoseconds
50577713246424 nanoseconds is 14 hours and 2 minutes and 57 seconds and 713 miliseconds and 246424 nanoseconds
59261942176619 nanoseconds is 16 hours and 27 minutes and 41 seconds and 942 miliseconds and 176619 nanoseconds
68450995316771 nanoseconds is 19 hours and 50 seconds and 995 miliseconds and 316771 nanoseconds
72938948086206 nanoseconds is 20 hours and 15 minutes and 38 seconds and 948 miliseconds and 86206 nanoseconds
76196764279710 nanoseconds is 21 hours and 9 minutes and 56 seconds and 764 miliseconds and 279710 nanoseconds
发布评论

评论列表(0)

  1. 暂无评论