Validating a time zone is valid in rails

A more lightweight and performant solution would be using TZInfo::Timezone.all_identifiers instead of manipulating the list from ActiveSupport::TimeZone.all.

validates :timezone, presence: true, inclusion: { in: TZInfo::Timezone.all_identifiers }

Looks like you want this:

validates_inclusion_of :timezone,
                       :in => ActiveSupport::TimeZone.all.map { |tz| tz.tzinfo.name }

On my machine, that list includes the following names:

...
"Europe/Istanbul",
"Europe/Kaliningrad",
"Europe/Kiev",
"Europe/Lisbon",
"Europe/Ljubljana",
"Europe/London",
...

However, a cleaner solution would be a custom validation method, like this:

validates_presence_of :timezone
validate :timezone_exists

private

def timezone_exists
  return if timezone? && ActiveSupport::TimeZone[timezone].present?
  errors.add(:timezone, "does not exist")
end

This is more flexible in the values it accepts:

ActiveSupport::TimeZone["London"].present? # => true
ActiveSupport::TimeZone["Europe/London"].present? # => true
ActiveSupport::TimeZone["Pluto"].present? # => false

All of the other answers are good, especially Matt Brictson's. This one works when you have someone pass something like 'Paris' to the timezone, which can be used by rails, but isn't in the list (ActiveSupport::TimeZone) that are being checked. This validation checks if it is valid for rails, and allows for 'Paris' to be valid:

  validates_each :timezone do |record, attr, value|
    !!DateTime.new(2000).in_time_zone(value)
  rescue
    record.errors.add(attr, 'was not valid, please select one from the dropdown')
  end