On my activeadmin, i have to give hours of opening and closing to each shop.
For example, when a shop is open from 09 pm to 04 am, it's recorded as the same date.
But my algorithm has a malfunction
My algorithm is:
def opened?
today_day = Date.today.wday
yesterday_day = today_day == 0 ? 6 : (today_day - 1)
opening = self.openings.where(day: [today_day, yesterday_day]).first
if opening
opening_day = (Time.now).day
if opening.closes_at < opening.opens_at
opening_day = yesterday_day
end
# binding.pry
today_opens_at = Time.new((Time.now).year, (Time.now).month, opening_day, opening.opens_at.hour, opening.opens_at.min)
today_closes_at = Time.new((Time.now).year, (Time.now).month, (Time.now).day, opening.closes_at.hour, opening.closes_at.min)
if today_opens_at < (Time.now) && (Time.now) < today_closes_at
true
else
false
end
else
false
end
end
I try to add gem activesupport for '1.day' but i have an error 'argument out of range'
I don't find the solution, can you help me quickly please?
yerderday_day has to be a day of the month (0..30)
today_day_of_week = Date.today.wday
yesterday_day_of_week = today_day_of_week == 0 ? 6 : (today_day_of_week - 1)
opening = self.openings.where(day: [today_day_of_week, yesterday_day_of_week]).first
yesterday_day = Date.today.prev_day.day
or just replace this block:
if opening.closes_at < opening.opens_at
opening_day = Date.today.prev_day.day
end
Related
I'm trying to build a trial period checker and I'm trying to test whether a user was created inside the 14 day period. So if its outside 14 days then I get a false. Thoughts?
if #user.trial_period === true
trial_users = User.where(created_at:14.days.ago..Time.current.end_of_day)
#trial_check_user = trial_users.where('id = ?', current_user.id)
if #trial_check_user.first.present?
#user_in_trial = true
puts "!!!!!!! USER STILL IN TRIAL WINDOW !!!!!!!".red
else
#user_in_trial = false
puts "!!!!!!! NOT IN TRIAL NEED SUBCRIPTION !!!!!!!".red
redirect_to new_subscription_path
end
if current_user.created_at > 14.days.ago
# Still in trial
#trial_check_users = User.where('created_at > ?', 14.days.ago).count
else
#trial_check = false
redirect_to new_subscription_path
end
currently i am getting values from database with a query
created_ats = Snapshot.connection.select_all("SELECT created_at from snapshots WHERE snapshot_id >= '#{camera_id}_#{from_date}' AND snapshot_id <= '#{camera_id}_#{to_date}'")
This query is giving me all created_ats according to conditions.
i want to filter all these created_ats according to some inputs which users have been passed to database which are
days and times
"{"Monday":["3:0-7:0","15:0-17:30"],"Tuesday":[],"Wednesday":["11:0-16:0"],"Thursday":["5:0-10:0"],"Friday":["15:30-22:30"],"Saturday":[],"Sunday":[]}"
its just an example days and times are can be totally filled or partially.
there is a field named as INTERVAL. which is being considered as MINUTES.
Now what is the whole scenario, from query i am getting created_at which is general timestamps in ruby on rails.
i want to filter those created_at with the giving Days and timings provided along with everyday in info above. + adding X(interval) to that created at as well.
such as after refining between days and timings. we will have a list of created_ats so after that starting from first created_at will add x.minutes in that created at and will assure that (created_at+x.minutes) is also present in created_ats(which we got after days and hours refining), is YESS then save it else leave it.
what i have tried so far is this and its not working as i want it to work according to me it seems no error in that but still dont give me specific value
class SnapshotExtractor < ActiveRecord::Base
establish_connection "evercam_db_#{Rails.env}".to_sym
belongs_to :camera
require "rmega"
require "aws-sdk-v1"
require 'open-uri'
def self.connect_mega
storage = Rmega.login("#{ENV['MEGA_EMAIL']}", "#{ENV['MEGA_PASSWORD']}")
storage
end
def self.connect_bucket
access_key_id = "#{ENV['AWS_ACCESS_KEY']}"
secret_access_key = "#{ENV['AWS_SECRET_KEY']}"
s3 = AWS::S3.new(
access_key_id: access_key_id,
secret_access_key: secret_access_key,
)
bucket = s3.buckets["evercam-camera-assets"]
bucket
end
# def self.test
# snapshot_bucket = connect_bucket
# storage = connect_mega
# folder = storage.root.create_folder("dongi")
# s3_object = snapshot_bucket.objects["gpo-cam/snapshots/1452136326.jpg"]
# snap_url = s3_object.url_for(:get, {expires: 1.years.from_now, secure: true}).to_s
# File.open("formula.txt", 'w') { |file| file.write(snap_url) }
# open('image.jpg', 'wb') do |file|
# file << open(snap_url).read
# end
# folder.upload("image.jpg")
# end
def self.extract_snapshots
running = SnapshotExtractor.where(status: 1).any?
unless running
#snapshot_request = SnapshotExtractor.where(status: 0).first
#snapshot_request.update_attribute(:status, 1)
camera_id = #snapshot_request.camera_id
exid = Camera.find(camera_id).exid
mega_id = #snapshot_request.id
from_date = #snapshot_request.from_date.strftime("%Y%m%d")
to_date = #snapshot_request.to_date.strftime("%Y%m%d")
interval = #snapshot_request.interval
#days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
set_days = []
set_timings = []
index = 0
#days.each do |day|
if #snapshot_request.schedule[day].present?
set_days[index] = day
set_timings[index] = #snapshot_request.schedule[day]
index += 1
end
end
begin
created_ats = Snapshot.connection.select_all("SELECT created_at from snapshots WHERE snapshot_id >= '#{camera_id}_#{from_date}' AND snapshot_id <= '#{camera_id}_#{to_date}'")
created_at_spdays = refine_days(created_ats, set_days)
created_at_sptime = refine_times(created_at_spdays, set_timings, set_days)
created_at = refine_intervals(created_at_sptime, interval)
File.open("test.txt", 'w') { |file| file.write(created_at) }
storage = connect_mega
creatp = storage.root.create_folder("created_at")
creatp.upload("test.txt")
rescue => error
notify_airbrake(error)
end
begin
storage = connect_mega
snapshot_bucket = connect_bucket
new_folder = storage.root.create_folder("#{exid}")
folder = storage.nodes.find do |node|
node.type == :folder and node.name == "#{exid}"
end
folder.create_folder("#{mega_id}")
created_at.each do |snap|
snap_i = DateTime.parse(snap).to_i
s3_object = snapshot_bucket.objects["#{exid}/snapshots/#{snap_i}.jpg"]
if s3_object.exists?
snap_url = s3_object.url_for(:get, {expires: 1.years.from_now, secure: true}).to_s
File.open("formula_#{snap_i}.txt", 'w') { |file| file.write(snap_url) }
open('#{snap_i}.jpg', 'wb') do |file|
file << open(snap_url).read
end
folder.upload('#{snap_i}.jpg')
end
end
#snapshot_request.update_attribute(:status, 3)
rescue => error
error
end
end
# created_at
end
private
def self.refine_days(created_ats, days)
created_at = []
index = 0
created_ats.each do |single|
days.each do |day|
if day == Date.parse(single["created_at"]).strftime("%A")
created_at[index] = single["created_at"]
index += 1
end
end
end
created_at
end
def self.refine_times(created_ats, timings, days)
created_at = []
index = 0
day_index = 0
days_times = days.zip(timings.flatten)
one = 1
zero = 0
created_ats.each do |single|
days_times.each do |day_time|
if Date.parse(single).strftime("%A") == day_time[day_index]
start_time = DateTime.parse(day_time[one].split("-")[zero]).strftime("%H:%M")
end_time = DateTime.parse(day_time[one].split("-")[one]).strftime("%H:%M")
created_at_time = DateTime.parse(single).strftime("%H:%M")
if created_at_time >= start_time && created_at_time <= end_time
created_at[index] = single
index += 1
end
end
end
end
created_at
end
def self.refine_intervals(created_ats, interval)
created_at = [created_ats.first]
last_created_at = DateTime.parse(created_ats.last)
index = 1
index_for_dt = 0
length = created_ats.length
(1..length).each do |single|
if (DateTime.parse(created_at[index_for_dt]) + interval.minutes) <= last_created_at
temp = DateTime.parse(created_at[index_for_dt]) + interval.minutes
created_at[index] = temp.to_s
index_for_dt += 1
index += 1
end
end
created_at
end
end
I am making a payments arrangement, for an order, where a client can choose the day of the month to pay. And can also change it afterwards. For this I used the advance method for date, and it works correctly when creating, but fails when updating. Here is my code:
Creating, if day is 31, it properly changes to last day of month if the month doesn't have a day 31.
months = params[:payment][:months].to_i
pay_day = params[:payment][:pay_day].to_i
today = Date.today
first_date = today.change(months: 1).change(day: pay_day)
months_between = (today.year * 12 + today.month) - (first_date.year * 12 + first_date.month)
quota = (invoice_total)/months
payment_number = 1
months.times do |i|
payment = Payment.new(invoice: current_invoice, payment_type: PaymentType.find(params[:payment][:payment_type_id]), payment_number: payment_number, value: quota, max_payment_date: first_date.advance(months: +(months_between+i+1)))
payment.save
payment_number = payment_number + 1
end
Update code, it fails in, for example, February with "invalid date", but updates january correctly.
pay_day = params[:payment][:pay_day].to_i
#invoice.payments.each do |payment|
if payment.actual_payment_date.nil?
reference_month = payment.max_payment_date.change(months: 1).change(day: pay_day)
months_between = (payment.max_payment_date.year * 12 + payment.max_payment_date.month) - (reference_month.year * 12 + reference_month.month)
payment.update_attributes(max_payment_date: reference_month.advance(months: +(months_between)))
payment.save
end
end
It is basically the same code, does anyone know why in the first part it works correctly, but not the second part?
Thanks
ActiveSupport to the rescue:
def correct_day(day, date = Date.today)
end_of_month = date.end_of_month.day
day < end_of_month ? day : end_of_month
end
Lets test it with [timecop:
Timecop.freeze(Date.new(2000, 02)) do
correct_day(32) # => 29 - 2000 was a leap year.
correct_day(15) # => 15
end
Timecop.freeze(Date.new(2015, 10, 11)) do
correct_day(32) # => 31
correct_day(15) # => 15
end
This is how you would implement it in a model:
class Invoice < ActiveRecord::Base
has_many :payments
# Creates a payment for each month
# #param [Integer] months
# #param [Ingeger] preferred_day - defaults to the last day of the month
def split_payments(months = 12, preferred_day = 31)
(1..months).map do |i|
payments.create(
pay_day: calculate_payment_date(created_at + i.months, preferred_day),
payment_number: i
# ... More attributes
)
end
end
def change_payment_date(preferred_day)
payments.sort_by(:payment_number).map do |payment|
date = created_at + payment.payment_number.months
payment.update_attributes(
pay_day: calculate_payment_date(date, preferred_day)
)
end
end
private
def calculate_payment_date(date, preferred_day)
end_of_month = date.end_of_month
pref = date.beginning_of_month + (preferred_day - 1).days
pref < end_of_month ? pref : end_of_month
end
end
I'm currently working on an Appointment system and building it with Ruby on Rails. I have an Appointment model and appointments controller where on the index, I want to show a list of appointments for that day, separated by 30 minute chunks.
I have a basic working version and I've got a ruby method that adds a class on the table row which shows the if the current 30 minute chunk is the current time or not.
The issue is, it sets the row class as "current_time" when the time is anywhere between the start and end of the hour which isn't what I want.
def date_class(time)
now = DateTime.now.utc
if (now.beginning_of_hour..(now.end_of_hour - 0.5.hours)).cover?(time)
"current_time"
elsif ((now.beginning_of_hour + 0.5.hours)..now.end_of_hour).cover?(time)
"current_time"
elsif (now.beginning_of_day..now.end_of_hour).cover?(time)
"past"
else
"future"
end
end
Any ideas?
The screenshot below and shows that the code works fine and shows true or false correctly.
http://s.deanpcmad.com/2014/uifGf.png
Although it has only been tested with instances of class Time for now, the time_frame gem could be an alternative solution for this kind of problem:
require 'time_frame'
def date_class(time)
now = Time.now.utc
frame = TimeFrame.new(min: now.beginning_of_hour, duration: 29.minutes + 59.seconds)
frame = frame.shift_by(30.minutes) if now.min >= 30
return 'past' if frame.deviation_of(time) < 0.minutes
return 'current_time' if frame.cover?(time)
'future'
end
# Demo: Building 30.minutes interval blocks and print out the date class used by each block:
frame = TimeFrame.new(
min: (Time.now.utc - 2.hours).beginning_of_hour,
max: (Time.now.utc + 2.hours).beginning_of_hour
)
frame.split_by_interval(30.minutes).each do |interval|
puts "#{interval.min} -> #{date_class(interval.min)}"
end
Wouldn't this work for you?
def date_class(time)
now = DateTime.now.utc
return "past" if time < now.beginning_of_hour
return "current_time" if now.hour == time.hour && now.min < 30 && time.min < 30
return "current_time" if now.hour == time.hour && now.min >= 30 && time.min >= 30
return "future"
end
I am sure there is a better way, but this would also work I think
I am having a bit of trouble with comparing times in Rails. I want to check to see if an event lies within a window, if it does, then find which, the event or window starts last and which ends first. My code is as follows.
startingTime = 0
endingTime = 0
time = 0
eventTimeStart = Time.parse(event.start.to_s) #Need to convert DateTime to just Time
windowTimeStart = Time.parse(application.reportStart.to_s)
eventTimeEnd = Time.parse(event.end.to_s) #Need to convert DateTime to just Time
windowTimeEnd = Time.parse(application.reportEnd.to_s)
days = 0
if((windowTimeStart > eventTimeStart) || !(eventTimeStart < windowTimeEnd))
startingTime = windowTimeStart
if((eventTimeStart > windowTimeEnd))
days -= 1
end
else
startingTime = eventTimeStart
end
if((windowTimeEnd > eventTimeEnd) && (eventTimeEnd > windowTimeStart))
endingTime = eventTimeEnd
else
if((eventTimeEnd < windowTimeStart))
days -= 1
end
endingTime = windowTimeEnd
end
I have handwritten out each case, however at runtime it seems to run different from expected. It seems as if I always get into the windowed times. Does Rails use a different approach to Times than what I'm thinking? Can you even compare times in this manner?
If you are trying to see whether intervals overlap or not, this simple check will do:
overlaps = interval_1_start < interval_2_end && interval_1_end > interval_2_start
I don't understand the rest of the question, but I just hope that you don't have two big loops for event and application around the code you have pasted above.
Thanks for your suggestion Mladen.
In order to get this working, I passed all of the time objects into a method I made that converted them into minutes.
def self.getMin(time)
return((time.hour*60) + time.min)
end
I called that on all of my checks and now it seems to work.
if((getMin(windowTimeStart) > getMin(eventTimeStart)) || !(getMin(eventTimeStart) < getMin(windowTimeEnd)))
startingTime = windowTimeStart
if((getMin(eventTimeStart) > getMin(windowTimeEnd)))
days -= 1
end
else
startingTime = eventTimeStart
end
I'm sure there is a better way to check, however it does work now.