Q:

Why does order of independent operations (Add and ToLocalTime/ToUniversalTime) on DateTime changes the outcome?

These two lines produces the same result (results are in my timezone) which is expected:
new DateTime(1970, 1, 1).ToLocalTime().AddHours(10000) // [21.02.1971 17:00:00]
new DateTime(1970, 1, 1).AddHours(10000).ToLocalTime() // [21.02.1971 17:00:00]

Now these two lines produces two different results:
new DateTime(1970, 1, 1).ToLocalTime().AddHours(100000) // [29.05.1981 17:00:00]
new DateTime(1970, 1, 1).AddHours(100000).ToLocalTime() // [29.05.1981 18:00:00]

That seem really strange and I cannot quite understand why this is happening. I know Jon Skeet would argue that we should not use DateTime at all since it's not good enough and use nodatime instead, but out of curiosity it's interesting to know why exactly is this happening.
Logically the point in time does not change depending on the order of operation and it's still the same time, though apparently it is not in C#.
P.S. ToUniveralTime behaves the same way and produces 2 different results in the second example (off by one hour).

A:

I'm assuming you're in the UK (where we spent the winter on UTC, but switch to UTC+1 in the summer). Therefore at midnight on 1/1/1970 we're on UTC.

new DateTime(1970, 1, 1).ToLocalTime() does nothing, except changes Kind to Local, because DateTime assumes that we specified a point in time in UTC. We then add 10,000 hours, which brings us to a point in winter time.
new DateTime(1970, 1, 1).AddHours(10,000) also brings us to a point in winter time UTC, so .ToLocalTime() again does nothing, except change Kind to Local.

However, things get different when we add 100,000 hours, since that brings us to a point after daylight savings kicks in.

new DateTime(1970, 1, 1).ToLocalTime().AddHours(100000) changes Kind to Local as before, and then adds 100,000 hours's worth of ticks. There's no appreciation that we moved from UTC to UTC+1.
new DateTime(1970, 1, 1).AddHours(100000) however brings us to a point in time where local time and UTC differ, because we're after the 29th March 1981 and daylight savings has kicked in. .ToLocalTime() therefore spots that there's a 1-hour difference and adds it, resulting in a time which is 1 hour ahead.

It's worth remember how DateTime behaves. It represents an instant in time - a number of ticks since an epoch. It also has a Kind property, which says whether that time is based on local time, UTC, or is "Unspecified" (i.e. you haven't told it).
For example, new DateTime(1980, 4, 1, 0, 0, 0, DateTimeKind.Local) (I chose a date after DST), and new DateTime(1980, 4, 1, 0, 0, 0, DateTimeKind.Utc) have the same value for their Ticks property, and they print the same string. However, calling .ToLocalTime() does different things: in the first case it does nothing (because the DateTime is already in local time), but in the second it adds an hour's worth of ticks to the DateTime.
So remember, always keep track of what Kind is, and be aware of the effect that it has when converting between UTC/local time. DateTime itself isn't particularly smart, but the timezone conversion methods do have a lot of special-case logic around Kind which can throw you.
I'd argue that you should probably be using DateTimeOffset instead of DateTime - that shows you what timezone you're currently in, and does away with the woolly notions of "Unspecified" and "Whatever timezone my PC is in". Try repeating this experiment with DateTimeOffsets.

