how to iterating days - ruby-on-rails

I have a code for looping days.this to make leaves. I want column signin and signout on attendance will filling automatically start at startdate and end at enddate.
exp I input :
startdate: 2012-11-08 01:30:00
enddate: 2012-11-10 01:30:00
i want output like this:
2012-11-08 01:30:00
2012-11-09 01:30:00
2012-11-010 01:30:00
for i in 0..((#leafe.enddate - #leafe.startdate).to_i)
#attendance = Attendance.new
#attendance.signin = '2012-11-08 01:30:00' #value must chang automatically
#attendance.signout = '2012-11-08 10:30:00'#value must chang automatically
#attendance.user_id = #leafe.user_id
#attendance.save
end
thanks before

If startdate is of type Date, why not just do,
#attendance.signin = #leafe.startdate+i
#attendance.signout = #leafe.startdate+i

Why you using for loop? It looks like javacode.
Use instead block with range like:
(Time.now.beginning_of_day.to_i..Time.now.to_i).step(3600) do |n|#step one hour for example
#attendance = Attendance.new
.......
#attendance.signin = #leafe.startdate
#attendance.signout = #leafe.startdate + n # u can change time interval to any what you want
end

Related

Finding the months between two dates in rails

I can currently set a time range like so:
start_date: "2018-09-11"
end_date: "2018-11-19"
How can I do this for start to end of months? Examples:
time_range = ["2018-09-11".."2018-09-30"]
time_range = ["2018-10-01".."2018-10-31"]
time_range = ["2018-11-01".."2018-11-19"]
I'm not sure what's exactly your desired outcome but, given start date and end date as Date objects, you can perform
(start_date..end_date).to_a.group_by(&:month).values
and at the end what you get is a three element array, and each element contains an array with all the dates in that range for a month
I do not know if I understand very well what you asked, but I'll try to help you.
The Date class has several methods that will help you to work with dates.
Date < Object
Examples
my_date_range_array = [Date.today.beginning_of_year..Date.today.end_of_year]
my_date_time_range_array = [Time.now.beginning_of_year..Time.now.end_of_year]
my_date_range_array = [6.months.ago..Date.today]
YourModel.where date: Date.today.beginning_of_month..Date.today
YourModel.where date: 6.months.ago..Date.today
If you need every single date in the range, you can use something like this:
(Date.today.beginning_of_year..Date.today.end_of_year).map{ |date| date }
I hope that my answer helps you
This is a pure Ruby solution, but I believe (though I don't know Rails) it can be simplified slightly by replacing my methods first_day_of_month and first_day_of_month with Rails methods beginning_of_month and end_of_month, respectively. I designed the method for efficiency over simplicity.
require 'date'
DATE_FMT = "%Y-%m-%d"
def date_ranges(start_date_str, end_date_str)
start_date = Date.strptime(start_date_str, DATE_FMT)
end_date = Date.strptime(end_date_str, DATE_FMT)
return [start_date_str..end_date_str] if
[start_date.year, start_date.month] == [end_date.year, end_date.month]
d = start_date
ranges = [start_date_str..last_day_of_month(d)]
loop do
d = d >> 1
break if [d.year, d.month] == [end_date.year, end_date.month]
ranges << (first_day_of_month(d)..last_day_of_month(d))
end
ranges << (first_day_of_month(d)..end_date_str)
end
def first_day_of_month(d)
(d - d.day + 1).strftime(DATE_FMT)
end
def last_day_of_month(d)
((d >> 1)-d.day).strftime(DATE_FMT)
end
date_ranges("2018-09-11", "2019-02-11")
#=> ["2018-09-11".."2018-09-30", "2018-10-01".."2018-10-31",
# "2018-11-01".."2018-11-30", "2018-12-01".."2018-12-31",
# "2019-01-01".."2019-01-31", "2019-02-01".."2019-02-11"]
date_ranges("2018-09-08", "2018-09-23")
#=> ["2018-09-08".."2018-09-23"]
With the information provided by the OP, this is what I understand he is looking for.
Given a set range for example:
time_range = "2018-09-11".."2018-09-19"
new_range_min = time_range.min.to_date.beginning_of_month
new_range_max = time_range.max.to_date.end_of_month
new_range = new_range_min..new_range_max

How to check if time is in range using Rails

There is the following times:
now = "2014-01-24T15:58:07.169+04:00",
start = "2000-01-01T10:00:00Z",
end = "2000-01-01T16:00:00Z"
I need to check if now is between start and end. I use the following code:
Range.new(start, end).cover?(now)
Unfortunately, this code returns false for my data. What am I doing wrong? How can I fix it? Thanks.
Well, I would use between? method. Because it's faster than cover? and include? variants. Here's an example:
yesterday = Date.yesterday
today = Date.today
tomorrow = Date.tomorrow
today.between?(yesterday, tomorrow) #=> true
Here's a gist with performance tests Include?, Cover? or Between?
Update
According to your recent comment, you want to compare 'only time' without date. If I get you correctly, there's a way to do it - strftime. But before that, to make comparison correctly, you need to convert all your datetimes to a single timezone (for example, using utc). Here's an example:
start_time_with_date = Time.parse('2000-01-01T16:00:00Z').utc
end_time_with_date = Time.parse('2014-01-24T15:58:07.169+04:00').utc
start_time = start_time_with_date.strftime('%I:%M:%S') #=> '04:00:00'
end_time = end_time_with_date.strftime('%I:%M:%S') #=> '11:58:07'
current_time = Time.now.utc.strftime('%I:%M:%S') #=> '01:45:27' (my current time)
current_time.between?(start_time, end_time) #=> false
And yes. Sadly, it's a string comparison.
You can use Range#cover? with time objects.
start = Time.parse('2000-01-01T10:00:00Z')
end_time = Time.parse('2000-01-01T16:00:00Z')
now = Time.parse('2014-01-24T15:58:07.169+04:00')
(start..end_time).cover?(now)
You're currently using strings, Ruby cannot know you're speaking about time.
I see the only variant, to define additional method to Range:
class Range
def time_cover? now
(b,e,n) = [ self.begin.utc.strftime( "%H%M%S%N" ),
self.end.utc.strftime( "%H%M%S%N" ),
now.utc.strftime( "%H%M%S%N" ) ]
if b < e
b <= n && e >= n
else
e <= n && b >= n
end
end
end
now = Time.parse "2014-01-24T15:58:07.169+04:00"
s = Time.parse "2000-01-01T10:00:00Z"
e = Time.parse "2000-01-01T16:00:00Z"
Range.new(s, e).time_cover?(now)
# => true
your date time(now) is not in between start and end time

Rails Iteration by month given range of dates

I'm trying to follow this Railscast and create a morris.js line chart for my Enquiry model.
I've grouped the counts using date_trunc into months, but now I'm not quite sure at how to get the X-axis to iterate over months (e.g Jun 2012, Jul 2013) as opposed to by date as in the railscasts notes.
I've tried the range#step method here, but now the graph displays only one date (2012-07-01) without a count and nothing else. Commenting out the .step(1.month) method from the range variable and the graph works fine but the x-axis iterates by date.
class Enquiry < ActiveRecord::Base
def self.chart_data(start = 1.year.ago)
total_count = total_count_by_month(start)
start = start.to_date.beginning_of_month
today = Date.today.beginning_of_month
range = (start..today).step(1.month)
range.map do |month|
{
created_at: month,
total_enquiries: total_count[] || 0
}
end
end
def self.total_count_by_month(start)
enquiries = unscoped.where(created_at: start.beginning_of_month..Time.now)
enquiries = enquiries.group("date_trunc('month', created_at)")
enquiries = enquiries.select("date_trunc('month', created_at) as created_at, count(*) as count")
enquiries.each_with_object({}) do |enquiry, counts|
counts[enquiry.created_at.to_date] = enquiry.count
end
end
end
How do I get the chart's x-axis to iterate by months (Jun 2013, Jul 2013 ....) instead of by dates?
For anyone else facing the same problem, the solution is outlined below:
def self.chart_data(start = 1.year.ago)
total_count = total_count_by_month(start)
##############################################
start = start.to_date.beginning_of_month
today = Date.today.beginning_of_month
range = (start..today).select {|d| d.day == 1}
##############################################
range.map do |month|
{
created_at: month,
total_enquiries: total_count[] || 0
}
end
end
The chart's x-axis now iterates by month.
The solution is found here.
I'm still looking for solutions on how the chart dates might display (%b %Y) as opposed to the current format of (yyyy-mm-dd).

Formatting Time

This may seem like an extremely basic question but it has been eluding me for quite some time. I am trying to setup, in my controller, a way to display the time for a specific day based on that time. The time value for example I would want to display would be 10:00 AM from the value 10:00:00. I cannot seem to format the time correctly so that it can display it in that form. Here is my current code that the value will pass through:
def dayMap = new JSONArray()
daysofWeek.each{last ->
def testjsonObject = new JSONObject()
c.setTime(last.date)
int test = c.get(Calendar.DAY_OF_WEEK)
testjsonObject.put('dayofweekNumber', test)
testjsonObject.put('start_time', last.start_time)
testjsonObject.put('end_time', last.end_time)
dayMap.add(testjsonObject)
}
def weekStartTimeString = ""
def weekEndTimeString = ""
List finalList = []
dayMap.each{numberDay ->
if(numberDay.dayofweekNumber == Calendar.MONDAY){
if(numberDay.start_time.equals("09:00:00")){
weekStartTimeString += "<option value='09:00:00' selected>9:00 AM</option>"
println(numberDay)
}
else{
weekStartTimeString += "<option value='numberDay.start_time' selected>"
}
}
}
I would like to take the value numberDay.start_time and display it in that format. 10:00:00 to 10:00 AM. What is the best way of doing this as I am currently out of ideas.
Parse the time into a date object, then convert it back to a string in the format you want. For example:
def start_date = '10:00:00'
assert Date.parse('HH:mm:ss', start_date).format('hh:mm aa') == '10:00 AM'
start_date = '23:59:59'
assert Date.parse('HH:mm:ss', start_date).format('hh:mm aa') == '11:59 PM'
The date format strings are the same ones used by the Java SimpleDateFormat class.

Timed script/function in Lua

good morning friends... I am working on with Lua scripting language for a mobile app and have a requirement as follows -
The application's main aim is to schedule appointments for an individual with a Doctor.
So once a user's appointment is scheduled, for e.g. 8th May # 4:30 PM, the user should receive a "reminder alert" before an hour i.e. # 3:30 PM.
am absolutely having a blank mind on how to get this done.
I can get the user's date-time value and use the logic that a function should invoke just before 60 mins of that date-time. And that function contains my "Alert message".
But how to do this?
Can anyone guide me with a clue?
Please let me know if any other inputs are required...
Thanks in advance.
I would take an approach like this:
1.
Store each appointment's details as a .txt file containing JSON or Lua tabular data something like this:
{
date = "14:30 01/07/2013";
dateBooked = "09:30 23/06/2013";
venue = "31 Dentist Street";
appointmentType = "Routine Teeth Cleaning";
}
2.
You can have a timer class like so
Timer = {}
Timer_mt = { __index = Timer; __add = function(a,b) a:tickBy(b) end ; }
function Timer:new(delayTime,callBack)
local timer = {callBack=callBack}
timer.initTime = os.date() --MM/DD/YY HH:MM:SS
--delayTime = HH:MM:SS
_,_,hour,minute,second = string.find(delayTime,"(%d%d):(%d%d):(%d%d)")
timer.delay = {hour=hour,minute=minute,second=second}
--time the timer started
_,_,hour,minute,second = string.find(timer.initTime,"(%d%d):(%d%d):(%d%d)")
timer.startTime = {hour=hour,minute=minute,second=second}
--time the timer started
timer.initTime = os.date() --MM/DD/YY HH:MM:SS
print(timer.initTime)
_,_,hour,minute,second = string.find(timer.initTime,"(%d%d):(%d%d):(%d%d)")
timer.currentTime = {hour=hour,minute=minute,second=second}
return setmetatable(timer,Timer_mt)
end
function Timer:tick() --returns true if time expired
currTime = os.date() --MM/DD/YY HH:MM:SS
_,_,chour,cminute,csecond = string.find(currTime,"(%d%d):(%d%d):(%d%d)")
if chour - self.startTime.hour >= tonumber(self.delay.hour) and cminute - self.startTime.minute >= tonumber(self.delay.minute) and csecond - self.startTime.second > tonumber(self.delay.second) then
self:callBack()
self.startTime.hour,self.startTime.minute, self.startTime.second = chour,cminute,csecond
--return true
end
--return false
end
t = Timer:new("00:00:02",function () print("DONE") end)
print(t.currentTime.hour,t.currentTime.minute,t.currentTime.second)
while t:tick() or true do
io.read()
end
(I just made this up so I advice you test it but it seems to work for me).
3.
On start-up, or when a new appointment is added create a new timer, and then tick() each one at some point during the main execution, you could even have a timer which is the only one you tick() and it's callback ticks() the others... Anyway set the callback for each timer to display an alarm

Resources