Home > Software design >  What are good ways to omit the zero parts when formatting a time difference without manual checking?
What are good ways to omit the zero parts when formatting a time difference without manual checking?

Time:05-06

I would like to display a complete sentence to user like this:

The difference is 5 days, 3 hours, 16 minutes, 10 seconds, and 150 microseconds.

but exclude the zero terms.

For example: 91 days, 23:00:00 is printed as:

The difference is 91 days and 23 hours.

The only way I could think of now is creating a bunch of if statements, as I posted below. I think this might be over-complicated and I was hoping that there was an easier way.

# prompts the user to enter the date following the order
d1 = input('Please enter the date time (YYYY-mm-dd hour:minute:second:microsecond): ')
m_d1 = datetime.strptime(d1, '%Y-%m-%d %H:%M:%S:%f')  # a datetime variable with the entered info
# prompts the user to enter another date following the order
d2 = input('Please enter the date time (YYYY-mm-dd hour:minute:second:microsecond): ')
m_d2 = datetime.strptime(d2, '%Y-%m-%d %H:%M:%S:%f')  # another datetime variable with the entered info
if m_d1 > m_d2:
    result_date = m_d1 - m_d2
else:
    result_date = m_d2 - m_d1

# total difference in number of days with fraction
difference_days = result_date.total_seconds() / timedelta(days=1).total_seconds()
# total difference in number of hours with fraction
difference_hours = result_date.total_seconds() / timedelta(hours=1).total_seconds()
# total difference in number of minutes with fraction
difference_minutes = result_date.total_seconds() / timedelta(minutes=1).total_seconds()
# total difference in number of seconds with fraction
difference_seconds = result_date.total_seconds()
# total difference in number of microseconds with fraction
difference_microseconds = result_date.total_seconds() / timedelta(microseconds=1).total_seconds()

# now, A complete sentence that breaks everything down to the
# correct units and excluding any 0s.
if difference_days.is_integer():
    print(f'The difference is {int(difference_days)} days.')
else:
    hours = (Decimal(difference_days) - int(difference_days)) * 24
    if difference_hours.is_integer():
        if difference_days > 1:
            print(f'The difference is {int(difference_days)} days and {int(hours)} hours.')
        else:
            print(f'The difference is {int(hours)} hours.')
    else:
        minutes = (hours - int(hours)) * 60
        if difference_minutes.is_integer():
            if difference_days < 1 and hours < 1:
                print(f'The difference is {int(minutes)} minutes.')
            elif difference_days > 1 and hours < 1:
                print(f'The difference is {int(difference_days)} days and {int(minutes)} minutes.')
            else:
                print(
                    f'The difference is {int(difference_days)} days, {int(hours)} hours, and {int(minutes)} minutes.')
        else:
            seconds = (minutes - int(minutes)) * 60
            if difference_seconds.is_integer():
                if difference_days < 1 and hours < 1 and minutes < 1:
                    print(f'The difference is {int(seconds)} seconds.')
                elif difference_days > 1 and hours < 1 and minutes < 1:
                    print(f'The difference is {int(difference_days)} days and {int(seconds)} seconds.')
                elif difference_days < 1 and hours > 1 and minutes < 1:
                    print(f'The difference is {int(hours)} hours and {int(seconds)} seconds.')
                else:
                    # ... other code

CodePudding user response:

Use the DRY (don't repeat yourself) principle. You don't have to rewrite the code for every unit of time, since it's the same:

non_zero_counts = {}
rest = result_date
for duration in ["days", "hours", "minutes", "seconds", "microseconds"]:
    td = timedelta(**{duration: 1})
    count = int(rest / td)
    rest = rest - count * td
    if count:
        non_zero_counts[duration] = count

The result is a dictionary:

non_zero_counts
Out[27]: {'days': 31, 'hours': 3, 'seconds': 34, 'microseconds': 50000}

I'll leave dealing with all the special cases for getting the language right up to you. Feel free to edit this answer to add your solution for forming the sentence itself.

EDITS

Forming the sentence:

if non_zero_counts:
    result = ', '.join(f'{value} {key}' for key, value in 
    non_zero_counts.items())
    print(f'The difference is {result}')
else:
    print('The two dates are the same.')

Input:

Please enter the date time (YYYY-mm-dd hour:minute:second:microsecond): 2022-08-04 15:30:20:12470
Please enter the date time (YYYY-mm-dd hour:minute:second:microsecond): 2022-09-08 12:44:33:12348

output:

The difference is 34 days, 21 hours, 14 minutes, 12 seconds, 998780 microseconds
  • Related