def print_datum(datum=None, units='GiB'):
    """
    Print out the relevant fields from a bin containing aggregated values

    Args:
        datum (dict): the results of bin_datum
        units (str): units to print (KiB, MiB, GiB, TiB)
    """

    if datum is None:
        return "%28s %12s %12s %5s %5s %5s %5s %5s\n" % ("date/time",
                                                         "%ss read" % units.lower(),
                                                         "%ss writ" % units.lower(),
                                                         "ossav", "ossmx", "mdsav",
                                                         "mdsmx", "mssng")

    # The per-line "mssng" only counts read/write bytes, not CPU data
    frac_missing = float(datum.get('missing_ost_read', 0) + datum.get('missing_ost_write', 0)) \
                   / (datum.get('num_ost_read', 0) + datum.get('num_ost_write', 0))

    print_str = "%19s-%8s " % (datum['tstart'].strftime("%Y-%m-%d %H:%M:%S"),
                               datum['tend'].strftime("%H:%M:%S"))
    print_str += ("%%(sum_ost_read_%ss)12.2f " % units.lower()) % datum
    print_str += ("%%(sum_ost_write_%ss)12.2f " % units.lower()) % datum

    # The following data may not always be present; leave them blank if missing
    if 'ave_oss_cpu' in datum:
        print_str += "%(ave_oss_cpu)5.1f " % datum
    else:
        print_str += "%5s " % ''
    if 'max_oss_cpu' in datum:
        print_str += "%(max_oss_cpu)5.1f " % datum
    else:
        print_str += "%5s " % ''
    if 'ave_mds_cpu' in datum:
        print_str += "%(ave_mds_cpu)5.1f " % datum
    else:
        print_str += "%5s " % ''
    if 'max_mds_cpu' in datum:
        print_str += "%(max_mds_cpu)5.1f" % datum
    else:
        print_str += "%5s" % ''

    print_str += "%6.1f" % (100.0 * frac_missing)

    return print_str + "\n"