0

This is sort of a followup question to one of my previous questions. I have some dictionaries where I need to look at every value they contain and if that value is a datetime I need to format it a specific way. I also need to be able to recurse into nested dictionaries and lists. This is what I have so far:

def fix_time(in_time):
    out_time = '{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}'.format(in_time.year, in_time.month, in_time.day, in_time.hour, in_time.minute, in_time.second)
    return out_time

def fix_recursive(dct):
    for key, value in dct.items():
        if isinstance(value, datetime.datetime):
            mydict[key] = fix_time(value)
        elif isinstance(value, dict):
            fix_recursive(value)    

mydict={
    'Field1':'Value1'
    'SomeDateField1':1516312413.729,
    'Field2':'Value2',
    'Field3': [
        {
           'Subfield3_1':'SubValue1',
           'SubDateField3_1':1516312413.729
        },
        {
           'Subfield3_2':'SubValue2',
           'SubDateField3_2':1516312413.729
        },
        {
           'Subfield3_3':'SubValue3',
           'SubDateField3_3':1516312413.729
        }
     ],
     'Field4': {
        'Subfield4_1':'SubValue1',
        'SubDateField4_1':1516312413.729
     }
}

fix_recursive(mydict)

This works great for dictionaries and nested dictionaries, but not so much for lists. So in the above example fix_recursive would correct SomeDateField1 and SubDateField4_1, but not SubDateField3_1, SubDateField3_2, or SubDateField3_3. Also, as I don't know what the input will look like before I get it, I am trying to create a function that could get values in listed nested 3 or 4 levels deep.

And suggestions would be appreciated.

Thanks!

TroggleDorf
  • 410
  • 2
  • 8
  • 14
  • You may find my code [here](http://stackoverflow.com/q/41777880/4014959) of interest. Also see my other code linked at the end of that answer. – PM 2Ring Aug 21 '18 at 13:51
  • 2
    Totally unrelated, but there's a bug in your code - you are updating the global variable `mydict` instead of the local variable `dct`. Also, you may want to learn about `datetime.strftime()` for datetime formatting. And finally, there's NO datetimes in your dict, only timestamps (expressed as floats). – bruno desthuilliers Aug 21 '18 at 13:57
  • Well spotted, @brunodesthuilliers! I guess we've all made that "mutate the global instead of the local" mistake once or twice. :D – PM 2Ring Aug 21 '18 at 14:10
  • As Bruno mentioned, it's a good idea to become familiar with [strftime](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior). As well as calling `strftime` explicitly, `datetime` objects know how to format themselves using those codes, so you can do stuff like `'{:%Y-%m-%d %H:%M:%S}'.format(in_time)` – PM 2Ring Aug 21 '18 at 14:13

2 Answers2

3

You need to differentiate between looping over a list and a dictionary

def fix_recursive(obj):

    if isinstance(obj, list):  # could replace with collections.abc.MutableSequence
        itr = enumerate(obj)
    elif isinstance(obj, dict):  # could replace with collections.abc.MutableMapping
        itr = obj.items()
    else:
        return  # don't iterate -- pass back up

    for key, value in itr:
        if isinstance(value, datetime.datetime):
            obj[key] = fix_time(value)
        else:
            fix_recursive(value)
FHTMitchell
  • 11,793
  • 2
  • 35
  • 47
-1
  1. Flow your current route, added list support to recursive function.
  2. Why use fix_time, for serialize and deserialize? Use JSON or pickle, no need to convert datetime.
zhiwen
  • 82
  • 4