working_hours Ruby Gem

repository·master·Indexed 19 days ago

https://github.com/intrepidd/working_hours

A Ruby gem for performing time calculations based on custom working hours, holidays, and time zones. It provides tools to calculate working days and durations, advance or retreat through working schedules, and validate if a specific time falls within business operations. The library offers both core extensions for Numeric, Date, and Time classes for intuitive syntax, as well as a standalone module and Duration class to avoid monkey patching.

Tokens
4.5K
Snippets
21
Records
22
Agent score
68%

What's inside working_hours

  1. Use working_hours without monkey patching

    master

    If you prefer not to modify core Ruby classes, you can use the WorkingHours::Duration class and the WorkingHours module directly. This is safer for libraries or projects that want to avoid side effects.

    require 'working_hours/module'
    
    # Use Duration objects
    WorkingHours::Duration.new(1, :days).from_now
    WorkingHours::Duration.new(8, :days).since(Date.new(2014, 12, 31))
    WorkingHours::Duration.new(4, :hours).until(Time.utc(2014, 8, 4, 8, 32))
    
    # Use WorkingHours module methods
    WorkingHours.working_days_between(friday, monday)
    WorkingHours.working_time_between(from, to)
    WorkingHours.working_day?(Date.new(2014, 12, 28))
    WorkingHours.in_working_hours?(Time.utc(2014, 8, 4, 7, 16))
  2. Use working_hours with core extensions (Monkey Patching)

    master

    By default, working_hours extends core Ruby classes like Numeric, Date, and Time to allow for intuitive syntax. This is the easiest way to perform time calculations using natural language-like methods.

    require 'working_hours'
    
    # Move forward/backward
    1.working.day.from_now
    2.working.hours.ago
    15.working.minutes.from_now
    
    # Start from custom Date or Time
    Date.new(2014, 12, 31) + 8.working.days
    Time.utc(2014, 8, 4, 8, 32) - 4.working.hours
    
    # Compute working days between two dates
    friday.working_days_until(monday)
    
    # Compute working duration (in seconds) between two times
    from.working_time_until(to)
    
    # Check if a day or time is a working one
    Date.new(2014, 12, 28).working_day?
    Time.utc(2014, 8, 4, 7, 16).in_working_hours?
  3. Configure working hours and holidays

    master

    The configuration defines working periods for each day, the time zone, and holidays. It is thread-safe. You can set it globally (e.g., in a Rails initializer) or temporarily using a block.

    # Global configuration
    WorkingHours::Config.working_hours = {
      :tue => {'09:00' => '12:00', '13:00' => '17:00'},
      :wed => {'09:00' => '12:00', '13:00' => '17:00'},
      :thu => {'09:00' => '12:00', '13:00' => '17:00'},
      :fri => {'09:00' => '12:00', '13:00' => '17:05:30'},
      :sat => {'19:00' => '24:00'}
    }
    
    # Set timezone (defaults to UTC)
    WorkingHours::Config.time_zone = 'Paris'
    
    # Set holidays
    WorkingHours::Config.holidays = [Date.new(2014, 12, 31)]
    
    # Temporary configuration for a block
    WorkingHours::Config.with_config(working_hours: {mon:{'09:00' => '18:00'}}, holidays: [], time_zone: 'Paris') do
      # Intense calculations with this specific config
    end
  4. Configure holiday hours (overrides)

    master

    To handle special working hours for specific calendar days (like Christmas Eve), use holiday_hours. If any hours are set for a day in holiday_hours, the standard working_hours for that day are ignored.

    # Configure specific hours for a specific date
    WorkingHours::Config.holiday_hours = {Date.new(2020, 12, 24) => {'09:00' => '12:00', '13:00' => '15:00'}}
  5. Configure working hours, holidays, and time zone

    master

    The WorkingHours::Config class allows you to define the schedule and holiday rules for your application. You can set these globally or within a scoped block.

    Configuration Keys

    • working_hours: A Hash mapping day symbols (:sun, :mon, :tue, :wed, :thu, :fri, :sat) to a Hash of time ranges. Time ranges are defined as {'HH:MM' => 'HH:MM'} or {'HH:MM:SS' => 'HH:MM:SS'}.
    • holidays: An Array (or any object responding to to_a) containing Date objects representing non-working days.
    • holiday_hours: A Hash mapping specific Date objects to working hour ranges (overriding standard working hours for that specific date).
    • time_zone: A String (representing a valid ActiveSupport time zone name) or an ActiveSupport::TimeZone object.

    Scoped Configuration

    Use with_config to temporarily apply a configuration for a specific block of code. This is useful for testing or handling different schedules in the same process without affecting the global state.

    WorkingHours::Config.working_hours = {
      mon: { '09:00' => '17:00' },
      tue: { '09:00' => '17:00' }
    }
    
    WorkingHours::Config.with_config(time_zone: 'America/New_York') do
      # Code here uses New York time zone
    end
  6. Handle WorkingHours::InvalidConfiguration errors

    master

    If the configuration is invalid, the gem raises WorkingHours::InvalidConfiguration. You can inspect the error_code to implement custom error handling.

    rescue WorkingHours::InvalidConfiguration => e
      if e.error_code == :empty
        raise StandardError.new "Config is required"
      end
      raise e
    end
  7. Include WorkingHours in a class or module

    master

    If you want to use the computation methods (without monkey patching core classes) inside your own class, include WorkingHours.

    require 'working_hours/module'
    
    class Order
      include WorkingHours
    
      def shipping_date_estimate
        # Uses Duration and working_days_since/until logic
        Duration.new(2, :days).since(payment_received_at)
      end
    
      def payment_delay
        # Uses working_days_between logic
        working_days_between(created_at, payment_received_at)
      end
    end
  8. Advance to next working time or closing time

    master

    The WorkingHours module provides methods to jump to specific points in the working schedule based on a given time.

    # Advance to the next available working moment
    WorkingHours.next_working_time(sunday)
    
    # Advance to the next closing time of the day
    WorkingHours.advance_to_closing_time(time)
    
    # Advance to the next available working moment (alternative syntax)
    WorkingHours.advance_to_working_time(time)
    
    # Return to the previous working moment
    WorkingHours.return_to_working_time(time)
  9. Extend Date, Time, and TimeWithZone with working hours methods

    master

    The working_hours gem extends Ruby's native Date, Time, and ActiveSupport::TimeWithZone classes by including the WorkingHours::CoreExt::DateAndTime module. This adds several convenience methods to these objects for calculating working days, working durations, and checking working status.

    Available methods include:

    • working_days_until(other): Returns the number of working days between the current object and other using WorkingHours.working_days_between.
    • working_time_until(other): Returns the working duration between the current object and other using WorkingHours.working_time_between.
    • working_day?: Returns true if the current date/time is considered a working day.
    • in_working_hours?: Returns true if the current time falls within defined working hours.
    • + and - (overloaded): When adding or subtracting a WorkingHours::Duration object, the methods use plus_with_working_hours and minus_with_working_hours to calculate the resulting time based on working hours logic rather than absolute elapsed time.
    # Example usage of extended methods
    require 'working_hours'
    
    # Check if a date is a working day
    Date.today.working_day?
    
    # Calculate working days until another date
    Date.today.working_days_until(Date.today + 7)
    
    # Check if a time is within working hours
    Time.now.in_working_hours?