-2

This is the best that I have come up with so far. I am not entirely happy with it because I have to use a % 100 to prevent an overflow of the year byte. As a result I have to add 2000 back to the year in the reverse function. Can anyone improve these functions?

def datetime_to_bcd(dt):
    """Converts a datetime object to BCD (Binary-Coded Decimal) format."""
    year_bcd = ((dt.year % 100) // 10) << 4 | (dt.year % 10)
    month_bcd = (dt.month // 10) << 4 | (dt.month % 10)
    day_bcd = (dt.day // 10) << 4 | (dt.day % 10)
    hour_bcd = (dt.hour // 10) << 4 | (dt.hour % 10)
    minute_bcd = (dt.minute // 10) << 4 | (dt.minute % 10)
    second_bcd = (dt.second // 10) << 4 | (dt.second % 10)
    return bytes([year_bcd, month_bcd, day_bcd, hour_bcd, minute_bcd, second_bcd])

def bcd_to_datetime(bcd_bytes):
    """Converts a BCD (Binary-Coded Decimal) format in bytes to a datetime object."""
    year_bcd, month_bcd, day_bcd, hour_bcd, minute_bcd, second_bcd = bcd_bytes
    year = 2000 + (year_bcd >> 4) * 10 + (year_bcd & 0x0F)
    month = (month_bcd >> 4) * 10 + (month_bcd & 0x0F)
    day = (day_bcd >> 4) * 10 + (day_bcd & 0x0F)
    hour = (hour_bcd >> 4) * 10 + (hour_bcd & 0x0F)
    minute = (minute_bcd >> 4) * 10 + (minute_bcd & 0x0F)
    second = (second_bcd >> 4) * 10 + (second_bcd & 0x0F)
    return datetime.datetime(year, month, day, hour, minute, second)
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Ryan Hope
  • 502
  • 2
  • 14

1 Answers1

1

You can use string conversions to make this shorter:

from datetime import datetime

def datetime_to_bcd(dt):
    return int(dt.strftime("%Y%m%d%H%M%S"),16).to_bytes(7,"big")

def bcd_to_datetime(bcd):
    return datetime.strptime(bcd.hex(),"%Y%m%d%H%M%S")

output:

dt = datetime.today()        
bcd = datetime_to_bcd(dt)    
dt2 = bcd_to_datetime(bcd)

print(dt)                        # 2023-03-14 18:03:37.096066
print(bcd.hex())                 # 20230314180337
print(dt2)                       # 2023-03-14 18:03:37 
Alain T.
  • 40,517
  • 4
  • 31
  • 51