class ActiveSupport::TimeWithZone

def change(options)

t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00.116992711 EST -05:00
t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00.116992711 EST -05:00
t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15.116992711 EST -05:00
t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15.116992711 EST -05:00

:offset, not both.
or :nsec, not both. Similarly, pass either :zone or
:nsec, :offset, :zone. Pass either :usec
:day, :hour, :min, :sec, :usec,
parameter takes a hash with any of these keys: :year, :month,
hour and minute is passed, then sec, usec, and nsec is set to 0. The +options+
so if only the hour is passed, then minute, sec, usec, and nsec is set to 0. If the
:min, :sec, :usec, :nsec) reset cascadingly,
been changed according to the +options+ parameter. The time options (:hour,
Returns a new +ActiveSupport::TimeWithZone+ where one or more of the elements have
def change(options)
  if options[:zone] && options[:offset]
    raise ArgumentError, "Can't change both :offset and :zone at the same time: #{options.inspect}"
  end
  new_time = time.change(options)
  if options[:zone]
    new_zone = ::Time.find_zone(options[:zone])
  elsif options[:offset]
    new_zone = ::Time.find_zone(new_time.utc_offset)
  end
  new_zone ||= time_zone
  periods = new_zone.periods_for_local(new_time)
  self.class.new(nil, new_zone, new_time, periods.include?(period) ? period : nil)
end