from datetime import datetime
import pytz


def datetime_to_float(d):
    """
    Convert a datetime object to a floating point timestamp.
    Return a number of seconds elapsed from UTC epoch.

    If the input object is timezone-aware, the result includes timezone difference between UTC
    and the timezone.
    If the input object is timezone-naive, it's treated as UTC.

    For example, 2h into the epoch in CET is 1h into the epoch in UTC (CET = UTC + 1h), so:
    >> cet_tz = timezone('CET')
    >> dt = datetime(1970, 1, 1, 2, 0, 0, tzinfo=cet_tz)
    >> datetime_to_float(dt)
    3600.0

    In case of a timezone-naive object, we treat the input as UTC, so:
    >> dt = datetime(1970, 1, 1, 2, 0)
    >> ts_expected = 3600 * 2
    >> datetime_to_float(dt)
    7200.0

    See tests for more examples.

    Args:
        d (datetime): can be timezone-aware or not

    Returns:
        float: e.g. 123456.123, always counting from UTC
    """
    epoch = datetime.fromtimestamp(0, tz=pytz.UTC)
    if not d.tzinfo:
        epoch = epoch.replace(tzinfo=None)

    total_seconds = (d - epoch).total_seconds()
    return total_seconds