The twist that makes this otherwise fairly trivial problem complicated is having to respect Daylight Savings Time. I once had to convert times given in UTC to their local equivalents for all of the US and Canada. We had to query a service in order to determine if the given city respected Daylight Savings Time or not, but after that we could use a hash to provide a close enough approximation. Since you want to convert to UTC, you most likely will need not the following code. But in the event you (or others who are reading) need to convert to local US and Canada time zones, the following can help. Just note that the data in the hash was determined 3 years ago and some areas might have changed.

And you have to know beforehand (via some lookup table provided by some external source) what the rules are for the city you are converting to. This all makes you wonder why we still have DST, and if fact many people would like to abolish it.

P.S. My co-worker that helped derive this solution was going to release this as TimeZone::CloseEnough.