DEV: UserOption.user_tzinfo (#14088)

DEV: UserOption.user_tzinfo (#14088)

Provides a safe way to retrieve the timezone of a user.

This is not used in core yet, but used in multiple plugins.

diff --git a/app/models/user_option.rb b/app/models/user_option.rb
index d3d0a78..0c73533 100644
--- a/app/models/user_option.rb
+++ b/app/models/user_option.rb
@@ -195,6 +195,20 @@ class UserOption < ActiveRecord::Base
       email_messages_level == UserOption.email_level_types[:never]
   end
 
+  def self.user_tzinfo(user_id)
+    timezone = UserOption.where(user_id: user_id).pluck(:timezone).first || 'UTC'
+
+    tzinfo = nil
+    begin
+      tzinfo = ActiveSupport::TimeZone.find_tzinfo(timezone)
+    rescue TZInfo::InvalidTimezoneIdentifier
+      Rails.logger.warn("#{User.find_by(id: user_id)&.username} has the timezone #{timezone} set, we do not know how to parse it in Rails, fallback to UTC")
+      tzinfo = ActiveSupport::TimeZone.find_tzinfo('UTC')
+    end
+
+    tzinfo
+  end
+
   private
 
   def update_tracked_topics
diff --git a/spec/models/user_option_spec.rb b/spec/models/user_option_spec.rb
index 19a9ab5..cc4db58 100644
--- a/spec/models/user_option_spec.rb
+++ b/spec/models/user_option_spec.rb
@@ -166,4 +166,28 @@ describe UserOption do
     end
 
   end
+
+  describe '.user_tzinfo' do
+    fab!(:user) { Fabricate(:user) }
+
+    context 'user with valid timezone given' do
+      before do
+        user.user_option.update(timezone: 'Europe/Paris')
+      end
+
+      it 'returns the expect timezone' do
+        expect(UserOption.user_tzinfo(user.id)).to eq(ActiveSupport::TimeZone.find_tzinfo('Europe/Paris'))
+      end
+    end
+
+    context 'user with invalid timezone given' do
+      before do
+        user.user_option.update(timezone: 'Catopia/Catcity')
+      end
+
+      it 'fallbacks to UTC' do
+        expect(UserOption.user_tzinfo(user.id)).to eq(ActiveSupport::TimeZone.find_tzinfo('UTC'))
+      end
+    end
+  end
 end

GitHub sha: 2bbc97fda54dc4ff8d7e6316a236ca21ed7faed6

This commit appears in #14088 which was approved by eviltrout. It was merged by jjaffeux.