Ruby on Rails Tutorials

Time Zones in Rails: A Junior Dev's Survival Guide

Time Zones in Rails: A Junior Dev's Survival Guide

One of the most confusing aspects for new Rails developers is handling time zones properly. Let's break it down into simple, practical examples.

The Basics: Setting Up Time Zones

# config/application.rb
class Application < Rails::Application
  # ❌ Bad: Using default time zone
  # This will use UTC and cause confusion

  # ✅ Good: Setting application time zone
  config.time_zone = 'Eastern Time (US & Canada)'

  # This is crucial! It converts DB times to UTC automatically
  config.active_record.default_timezone = :utc
end

Common Time Zone Mistakes and Fixes

1. Creating Events or Appointments

# ❌ Bad: Ignoring time zones
class Event < ApplicationRecord
  def schedule_for(date_string)
    update(start_time: Time.parse(date_string))
  end
end

# ✅ Good: Using Time.zone
class Event < ApplicationRecord
  def schedule_for(date_string)
    update(start_time: Time.zone.parse(date_string))
  end
end

2. Displaying Times

# app/helpers/application_helper.rb
module ApplicationHelper
  # ❌ Bad: Using strftime directly
  def format_time(time)
    time.strftime("%B %d, %Y at %I:%M %p")
  end

  # ✅ Good: Using I18n with time zones
  def format_time(time)
    I18n.l(time.in_time_zone(current_user.time_zone), 
           format: :long)
  end
end

3. Date/Time Comparisons

# ❌ Bad: Comparing times without zones
def today_appointments
  appointments.where('DATE(start_time) = ?', Date.today)
end

# ✅ Good: Using time zones properly
def today_appointments
  appointments.where(
    start_time: Time.zone.now.beginning_of_day..Time.zone.now.end_of_day
  )
end

Pro Tips for Time Zones

Testing Different Time Zones

# spec/models/event_spec.rb
describe Event do
  it "creates events in user's time zone" do
    Time.use_zone('Pacific Time (US & Canada)') do
      event = Event.create!(start_time: Time.zone.parse('2024-01-01 14:00'))
      expect(event.start_time.zone).to eq('UTC')
      expect(event.start_time.in_time_zone('Pacific Time (US & Canada)').hour).to eq(14)
    end
  end
end

User-Specific Time Zones

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  around_action :set_time_zone, if: :current_user

  private

  def set_time_zone
    Time.use_zone(current_user.time_zone) { yield }
  end
end