Ответ 1
Это было связано с недавним RubyLearning задача - может быть полезно:)
Я создаю приложение Rails, которое будет хранить часы открытия и закрытия для бизнеса. Первоначально я думал просто использовать текстовый тип данных и позволить ему быть свободным:
"Monday to Friday 9am to 5pm
Saturday 11am to 4pm
Closed Sundays"
Но требования изменились, и мне нужно проверить часы на текущую дату и время и отобразить "Открыть" или "Закрыто" в представлении. Что-то вроде:
class Business < ActiveRecord::Base
def open?
# Something like ...
Time.now > open_time && Time.now < close_time
end
end
Итак, что было бы лучшим способом справиться с этим с точки зрения хранения часов для каждого дня недели? Должен ли бизнес просто has_many: open_blocks (или что-то еще), имеющее открытые и закрытые времена? Должен ли я просто хранить этот день в виде строки?
Это было связано с недавним RubyLearning задача - может быть полезно:)
В настоящее время я настраиваю список каталогов для клиента, и мы хотим предоставить пользователю большую гибкость. Итак: пусть пользователь настраивает блоки в течение нескольких дней:
У нас есть день (целое число 1-7), открывается (время), закрывается (время), а некоторые магазины или достопримечательности лето и зима, или они делают отпуск. Согласно schema.org, вы должны добавить valid_from (datetime) и valid_through (datetime).
С помощью этой настройки пользователь может создать все, что захочет:
# migration
class CreateOpeningHours < ActiveRecord::Migration
def change
create_table :opening_hours do |t|
t.integer :entry_id # your model reference
t.integer :day
t.time :closes
t.time :opens
t.datetime :valid_from
t.datetime :valid_through
end
end
end
Пример для модели:
class OpeningHour < ActiveRecord::Base
belongs_to :entry
validates_presence_of :day, :closes, :opens, :entry_id
validates_inclusion_of :day, :in => 1..7
validate :opens_before_closes
validate :valid_from_before_valid_through
# sample validation for better user feedback
validates_uniqueness_of :opens, scope: [:entry_id, :day]
validates_uniqueness_of :closes, scope: [:entry_id, :day]
protected
def opens_before_closes
errors.add(:closes, I18n.t('errors.opens_before_closes')) if opens && closes && opens >= closes
end
def valid_from_before_valid_through
errors.add(:valid_through, I18n.t('errors.valid_from_before_valid_through')) if valid_from && valid_through && valid_from >= valid_through
end
end
С помощью этой установки вы можете легко создать is_open? метод в вашей модели. В настоящее время я не настроил is_open? метод, но если кому-то нужно, дайте мне хит! Думаю, я закончу его в ближайшие дни.
В этом случае я, вероятно, сделаю что-то реляционное, возможно, с ИППП, если вы хотите иметь определенные дни, когда бизнес закрыт (например, разовые закрытия). Вот пример базового ИППП:
class Business < ActiveRecord::Base
has_many :open_time_blocks
has_many :closed_time_blocks
def open?(time)
# false if time is "inside" any of the closed_time_blocks
# else is true if inside any of the open_time_blocks
# else is false
end
def closed?(time)
!open?
end
end
# == Schema Information
#
# Table name: time_blocks
#
# id :integer not null, primary key
# business_id :integer
# type :string(255)
# start_at :datetime
# end_at :datetime
# created_at :datetime
# updated_at :datetime
class TimeBlock < ActiveRecord::Base
belongs_to :business
end
class OpenTimeBlock < TimeBlock; end
class ClosedTimeBlock < TimeBlock; end
Я бы сказал, что рабочие часы принадлежат партовому адресу и должны быть представлены RFC 5455 RRULE и необязательно EXRULE или EXDATE s.
Скажем, у вас есть партия:
"Acme, Inc."
У них есть один физический адрес:
"123 Main Street, Ванкувер"
Их адрес выполняет две роли:
"Продажи" и "Сервис"
Продажи открыты Mo-Sa 10-8, а сервис открыт Mo-Fr 9-5
Это RRULES:
(продажи)
startTime:'10:00:00'
endTime:'20:00:00'
RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR,SA
(Сервис)
startTime:'09:00:00'
endTime:'17:00:00'
RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR
Оформить заказ эти библиотеки для обработки повторяющихся дат.
Как только рекурсия устанавливается в объекте say office_hours
, в ice_cube
вы можете запросить его как:
office_hours.occurring_at?(Time.now)
Итак, я только что узнал, что ice_cube
может обрабатывать повторяющиеся длительности:
> schedule = IceCube::Schedule.new(Time.now, :duration => 3600)
> schedule.add_recurrence_rule Rule.daily
> schedule.occurs_at?(Time.now + 1000)
true
> schedule.occurs_at?(Time.now + 1.day + 1000)
true
> schedule.occurs_at?(Time.now + 4000)
false
Я подозреваю, что вы можете обрабатывать множество разных ситуаций, используя ice_cube
таким образом.
Кстати, я реализую аналогичный открытый/закрытый график работы. Мне было бы интересно узнать, как вы это сделали, и если у вас есть репозиторий github, мы можем сотрудничать вместе.