The simplest solution should be to call getTimezoneOffset() on a every login or page load, and not burden the user. I don’t know why it isn’t working for you; I thought getTimezoneOffset() accurately accounts for geographic location and local DST practice. Maybe you should investigate this some more to understand when, why, and how much getTimezoneOffset() gives errors.
If you have to show the users a list of time zones, then try filtering the list and adjusting the names for their locality, based either on their IP address or user-supplied country name. It becomes part of more general globalization/localization you need to do with your product.
Use Time, not Time Zone
Rather than ask the user for their time zone, perhaps it’s better to ask them for their local time and calculate a correction by comparing it to getTimezoneOffset() and UTC. In other words, displayed time = UTC + getTimezoneOffset() + user_supplied_correction. I’d expect that entering the time to the nearest 15 minutes to be easier than choosing among dozens of time zones, many of which would be unfamiliar. Use getTimezoneOffset() to set the default time and perhaps most of your users won’t even have to enter the time, or, at most, they make only a slight change.
Daylight Saving Time Practices
Getting local DST practices is harder. You cannot expect users to know the exact date that DST changes for them, and I wouldn’t even trust them to know which time of the year is DST for them. However, maybe getTimezoneOffset() does sufficiently accurately indicate local DST practices, which I believe vary less than time zones. If so, then using UTC + getTimezoneOffset() + user_supplied_correction would take care of it.
If getTimezoneOffset() just isn’t accurate for that, you need a table or service that relates location to DST practice. Again, maybe you can use the users' IP address, or use the user’s country (and maybe state/province), assuming you’re asking for that information anyway. It won’t be perfect, but maybe it’s acceptable if it works for the vast majority of your users. Given you’ve supplied an easy way for users to correct the time, the few edge case users always have the option of manually adjusting for DST, so you won’t be forcing them to live with the wrong time.
The above assumes you’re concerned with correctly displaying the local time. For entering a calendar event that can occur in another time zone, the name of the time zone in your dropdown should match how time zones are expressed to the user in the information sources that tell them about the events. For example, if the user sees or hears stuff like “Webinar 2:00pm Pacific Time,” then one option is “Pacific Time.” You’ll need to do some research to find out what those expressions are; it probably varies with the user population. Geeks might use UTC+/-X, but maybe no one else does. Sources used by pilots often use UTC regardless of the location (e.g., NOTAMs). Maybe different localities have different names for the same time zones.
It may be helpful to redundantly indicate the offset from the user’s local time (not UTC) –for example, “Pacific Time (3 hrs earlier)”. The user may have some idea what the offset is, so this would help them confirm their choice. Of course the user should always have the option of entering the equivalent local time for cases when they know the offset. Also, in some cases it’ll be easier to get the offset than to identify the time zone (e.g., call the person at the location the event will occur and ask them what the local time is).
It may make sense for the dropdown to list only the 5-15 most commonly used time zones (probably the times zone geographically closest to the user’s time zone), and include a More option to open a dialog or page listing time zones in detail (e.g., supplemented with a map).