I know they're different in how they are constructed. They're similar in what they do. For the majority of people who ever need to do anything with upstart/systemd it will be: it starts a service and its dependencies; it restarts the service that crashes if configured to do so; service operations can be triggered from outside.
Yes, underneath they have completely different implementation, but it shouldn't really matter apart from OS-level edge cases. If it does matter, it's a sign they failed to provide a simple and usable tool in my opinion.
I have not used systemd in practice but my experiences with upstart in practice are very different from both sysvinit and from what I read about systemd. I actually think systemd seems to be closer to sysvinit than to upstart.
EDIT: It is the reversed dependency logic in upstart which makes it so different from anything else.
They are also different in practice. For example, you can kill services cleanly with systemd, because it keeps track of what processes belong to which service via CGroups.
If you're interested in edge cases, then cgroup support can be included in your upstart configuration too. It's not a simple switch in the configuration, but can be made to work in the same way - I do that for some forking services which sometimes fail to collect children properly. I wouldn't consider this to be a big difference between the systems - each has some features that the other doesn't.
They're quite different. Upstart is event-based while systemd is based on automatic dependency resolution and socket activation: http://www.youtube.com/watch?v=TyMLi8QF6sw&t=11m18s