Time zone conversion should not be handled at time of serialization or deserialization. Those are separate concerns.
Instead:
Leave DateTimeZoneHandling at its default of RoundtripKind. (Don't set it to Utc.)
This has the behavior of:
- If you are deserializing to a
DateTime, and passing no offset in your data, then DateTimeKind.Unspecified will be set.
- If you are deserializing to a
DateTime, and passing a trailing Z in your data, then DateTimeKind.Utc will be set.
- If you are deserializing to a
DateTime, and passing an offset in your data, then `DateTimeKind.Local will be set, and the value will be converted to the local time zone (generally one should avoid this).
- If you are deserializing to a
DateTimeOffset, then the offset will be persisted and the value will not change (this is the better approach if passing offsets).
Once you have a DateTime or DateTimeOffset value, then use TimeZoneInfo.ConvertTime and similar methods to change time zones if necessary. This part should be in your application code, as it tends to be specific to the logic of a particular API.
Generally speaking, it's an antipattern (SRP violation) to try to treat all incoming or outgoing date/time data to be in the same time zone, whether via serialization or some other mechanism.