Class: Periodoxical::Core

Inherits:
Object
  • Object
show all
Includes:
Helpers, Validation
Defined in:
lib/periodoxical.rb

Constant Summary

Constants included from Validation

Validation::VALID_DAYS_OF_WEEK

Instance Method Summary collapse

Methods included from Helpers

#date_object_from, #day_of_week_long_to_short, #deep_symbolize_keys, #overlap?

Methods included from Validation

#validate!

Constructor Details

#initialize(starting_from:, ending_at: nil, time_blocks: nil, day_of_week_time_blocks: nil, limit: nil, exclusion_dates: nil, exclusion_times: nil, time_zone: 'Etc/UTC', days_of_week: nil, nth_day_of_week_in_month: nil, days_of_month: nil, duration: nil, months: nil, ambiguous_time: :raise, gap_strategy: :raise, gap_shift_minutes: 60) ⇒ Core

Returns a new instance of Core.

Parameters:

  • time_zone (String) (defaults to: 'Etc/UTC')

    Ex: ‘America/Los_Angeles’, ‘America/Chicago’, TZInfo::DataTimezone#name from the tzinfo gem (github.com/tzinfo/tzinfo)

  • starting_from (Date, String)
  • ending_at (Date, String) (defaults to: nil)
  • time_blocks (Array<Hash>) (defaults to: nil)

    Ex: [

    {
      start_time: '9:00AM',
      end_time: '10:30PM'
    },
    {
      start_time: '2:00PM',
      end_time: '2:30PM'
    }
    

    ]

  • days_of_week (Array<String>, nil) (defaults to: nil)

    Days of the week to generate the times for, if nil, then times are generated for every day. Ex: %w(mon tue wed sat)

  • days_of_month (Array<Integer>, nil) (defaults to: nil)

    Days of month to generate times for. Ex: %w(5 10) - The 5th and 10th days of every month

  • months (Array<Integer>, nil) (defaults to: nil)

    Months as integers, where 1 = Jan, 12 = Dec

  • limit (Integer) (defaults to: nil)

    How many date times to generate. To be used when ‘ending_at` is nil.

  • exclusion_dates (Aray<String>) (defaults to: nil)

    Dates to be excluded when generating the time blocks Ex: [‘2024-06-10’, ‘2024-06-14’]

  • exclusion_times (Aray<Hash>) (defaults to: nil)

    Timeblocks to be excluded when generating the time blocks if there is conflict (ie. overlap) Ex: [

      {
        start: '2024-06-10T10:30:00-07:00',
        end: '2024-06-10T11:30:00-07:00'
      },
      {
        start: '2024-06-10T14:30:00-07:00',
        end: '2024-06-10T15:30:00-07:00'
      },
    ]
    
  • day_of_week_time_blocks (Hash<Array<Hash>>) (defaults to: nil)

    To be used when hours are different between days of the week Ex: {

    mon: [{ start_time: '10:15AM', end_time: '11:35AM' }, { start_time: '9:00AM' }, {end_time: '4:30PM'} ],
    tue: { start_time: '11:30PM', end_time: '12:00AM' },
    fri: { start_time: '7:00PM', end_time: '9:00PM' },
    

    }

  • duration (Integer) (defaults to: nil)

    Splits the time_blocks into this duration (in minutes). For example, if time_block is 9:00AM - 10:00AM, and duration is 20 minutes. It creates 3 timeblocks of:

    - 9:00AM - 9:20AM
    - 9:20AM - 9:40AM
    - 9:40AM - 10:00AM
    
  • ambiguous_time (Symbol) (defaults to: :raise)

    How to resolve DST fall-back ambiguous local times (e.g. 01:30 occurs twice). Allowed: :first (daylight time), :last (standard time), :raise (default).

  • gap_strategy (Symbol) (defaults to: :raise)

    How to handle DST spring-forward missing local times (e.g. 02:30 does not exist). Allowed: :advance (shift forward), :skip (omit block), :raise (default).

  • gap_shift_minutes (Integer) (defaults to: 60)

    Minutes to advance when gap_strategy is :advance. Default: 60.



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/periodoxical.rb', line 82

def initialize(
  starting_from:,
  ending_at: nil,
  time_blocks: nil,
  day_of_week_time_blocks: nil,
  limit: nil,
  exclusion_dates: nil,
  exclusion_times: nil,
  time_zone: 'Etc/UTC',
  days_of_week: nil,
  nth_day_of_week_in_month: nil,
  days_of_month: nil,
  duration: nil,
  months: nil,
  ambiguous_time: :raise,
  gap_strategy: :raise,
  gap_shift_minutes: 60
)

  @time_zone = TZInfo::Timezone.get(time_zone)
  @ambiguous_time = ambiguous_time
  @gap_strategy = gap_strategy
  @gap_shift_minutes = gap_shift_minutes
  if days_of_week.is_a?(Array)
    @days_of_week = deep_symbolize_keys(days_of_week)
  elsif days_of_week.is_a?(Hash)
    @days_of_week_with_alternations = deep_symbolize_keys(days_of_week)
  end
  @nth_day_of_week_in_month = deep_symbolize_keys(nth_day_of_week_in_month)
  @days_of_month = days_of_month
  @months = months
  @time_blocks = deep_symbolize_keys(time_blocks)
  @day_of_week_time_blocks = deep_symbolize_keys(day_of_week_time_blocks)
  @starting_from = date_object_from(starting_from)
  @ending_at = date_object_from(ending_at)
  @limit = limit

  if duration
    unless duration.is_a?(Integer)
      raise "duration must be an integer"
    else
      @duration = duration
    end
  end
  @exclusion_dates = if exclusion_dates && !exclusion_dates.empty?
                       exclusion_dates.map { |ed| Date.parse(ed) }
                     end
  @exclusion_times = if exclusion_times
                       deep_symbolize_keys(exclusion_times).map do |et|
                         { start: DateTime.parse(et[:start]), end: DateTime.parse(et[:end]) }
                       end
                     end
  validate!
end

Instance Method Details

#generateArray<Hash<DateTime>>

Returns Ex: [

{
  start: #<DateTime>,
  end: #<DateTime>,
},
{
  start: #<DateTime>,
  end: #<DateTime>,
},

].

Returns:

  • (Array<Hash<DateTime>>)

    Ex: [

    {
      start: #<DateTime>,
      end: #<DateTime>,
    },
    {
      start: #<DateTime>,
      end: #<DateTime>,
    },
    

    ]



148
149
150
151
152
153
154
155
156
157
# File 'lib/periodoxical.rb', line 148

def generate
  initialize_looping_variables!
  while @keep_generating
    if should_add_time_blocks_from_current_date?
      add_time_blocks_from_current_date!
    end
    advance_current_date_and_check_if_reached_end_date
  end
  @output
end