Pretty print uptime given seconds and omit unnecessary strings
I feel like the datetime module isn't really doing much to help you.  By using it, you avoid performing arithmetic and hard-coding constants 86400, 3600, and 60.  However, in exchange, you end up hard-coding the accessors .day, .hour, .minute, and .second, in such a way that you have to write similar code four times, with no easy way to generalize them.  Attempts at generalization are further complicated by the fact that you need d.day-1, due to the way that you have abused datetime addition as a trick to convert the timedelta object into a datetime object.

Your output includes a trailing space, which I consider to be an annoyance.  One way to avoid that would be to use ' '.join(…).  On the other hand, if sec is 0, then the function would return an empty string, which is also unintuitive.  I would prefer 0s as output in that special case.

In my opinion, you would be no worse off doing all of the arithmetic and formatting yourself, without the use of the datetime module.

def format_seconds(sec):
    def repeatedly(f, xs, n):
        for x in xs:
            m, n = f(n, x)
            yield m
    return ' '.join(
        '{}{}'.format(n, unit)
        for n, unit in zip(
            repeatedly(divmod, [86400, 3600, 60, 1], sec),
            'dhms'
        )
        if n
    ) or '0s'