r"""Convert strings and datetime objects in the values of a dict into float/int/long, if possible

    Arguments:
      field_dict (dict): The dict to have any values (not keys) that are strings "quantified"
      precision (int): Number of digits of precision to enforce
      cleaner: A string cleaner to apply to all string before


    FIXME: define a time zone for the datetime object and get it to be consistent for travis and local

    >>> sorted(viewitems(quantify_field_dict({'_state': object(), 'x': 12345678911131517, 'y': "\t  Wash Me! \n",
    ...     'z': datetime.datetime(1970, 10, 23, 23, 59, 59, 123456)})))  # doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS
    [('x', 12345678911131517), ('y', 'Wash Me!'), ('z', 25...99.123456)]

def quantify_field_dict(field_dict, precision=None, date_precision=None, cleaner=str.strip):
    r"""Convert strings and datetime objects in the values of a dict into float/int/long, if possible

    Arguments:
      field_dict (dict): The dict to have any values (not keys) that are strings "quantified"
      precision (int): Number of digits of precision to enforce
      cleaner: A string cleaner to apply to all string before


    FIXME: define a time zone for the datetime object and get it to be consistent for travis and local

    >>> sorted(viewitems(quantify_field_dict({'_state': object(), 'x': 12345678911131517, 'y': "\t  Wash Me! \n",
    ...     'z': datetime.datetime(1970, 10, 23, 23, 59, 59, 123456)})))  # doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS
    [('x', 12345678911131517), ('y', 'Wash Me!'), ('z', 25...99.123456)]
    """
    if cleaner:
        d = clean_field_dict(field_dict, cleaner=cleaner)
    for k, v in viewitems(d):
        if isinstance(d[k], datetime.datetime):
            # seconds since epoch = datetime.datetime(1969,12,31,18,0,0)
            try:
                # around the year 2250, a float conversion of this string will lose 1 microsecond of precision,
                # and around 22500 the loss of precision will be 10 microseconds
                d[k] = float(d[k].strftime('%s.%f'))  # seconds since Jan 1, 1970
                if date_precision is not None and isinstance(d[k], ROUNDABLE_NUMERIC_TYPES):
                    d[k] = round(d[k], date_precision)
                    continue
            except (IndexError, ValueError, AttributeError, TypeError):
                pass
        if not isinstance(d[k], (int, float)):
            try:
                d[k] = float(d[k])
            except (IndexError, ValueError, AttributeError, TypeError):
                pass
        if precision is not None and isinstance(d[k], ROUNDABLE_NUMERIC_TYPES):
            d[k] = round(d[k], precision)
        if isinstance(d[k], float) and d[k].is_integer():
            # `int()` will convert to a long, if value overflows an integer type
            # use the original value, `v`, in case it was a long and d[k] is has been
            # truncated by the conversion to float!
            d[k] = int(v)
    return d