Codrin
Codrin

Reputation: 19

How to remove elements from array of dates between hours ranges Rails?

My array is generated by the

   start_date = (Date.today + 10.hours + 30.minutes).to_datetime       
   end_date = (Date.today + 1.day + 18.hours).to_datetime
   period = 0.5/24 
   array = start_date.step(end_date, period).to_a

this is the result (but this result is going to cover max 62 days)

array = 
  [Sat, 25 Feb 2023 10:30:00 +0000, Sat, 25 Feb 2023 11:00:00 +0000, Sat, 25 Feb 2023 11:30:00 +0000, 
  Sat, 25 Feb 2023 12:00:00 +0000, Sat, 25 Feb 2023 12:30:00 +0000, Sat, 25 Feb 2023 13:00:00 +0000,
  Sat, 25 Feb 2023 13:30:00 +0000, Sat, 25 Feb 2023 14:00:00 +0000, Sat, 25 Feb 2023 14:30:00 +0000, 
  Sat, 25 Feb 2023 15:00:00 +0000, Sat, 25 Feb 2023 15:30:00 +0000, Sat, 25 Feb 2023 16:00:00 +0000, 
  Sat, 25 Feb 2023 16:30:00 +0000, Sat, 25 Feb 2023 17:00:00 +0000, Sat, 25 Feb 2023 17:30:00 +0000, 
  Sat, 25 Feb 2023 18:00:00 +0000, Sat, 25 Feb 2023 18:30:00 +0000, Sat, 25 Feb 2023 19:00:00 +0000, 
  Sat, 25 Feb 2023 19:30:00 +0000, Sat, 25 Feb 2023 20:00:00 +0000, Sat, 25 Feb 2023 20:30:00 +0000, 
  Sat, 25 Feb 2023 21:00:00 +0000, Sat, 25 Feb 2023 21:30:00 +0000, Sat, 25 Feb 2023 22:00:00 +0000, 
  Sat, 25 Feb 2023 22:30:00 +0000, Sat, 25 Feb 2023 23:00:00 +0000, Sat, 25 Feb 2023 23:30:00 +0000, 
  Sun, 26 Feb 2023 00:00:00 +0000, Sun, 26 Feb 2023 00:30:00 +0000, Sun, 26 Feb 2023 01:00:00 +0000, 
  Sun, 26 Feb 2023 01:30:00 +0000, Sun, 26 Feb 2023 02:00:00 +0000, Sun, 26 Feb 2023 02:30:00 +0000, 
  Sun, 26 Feb 2023 03:00:00 +0000, Sun, 26 Feb 2023 03:30:00 +0000, Sun, 26 Feb 2023 04:00:00 +0000, 
  Sun, 26 Feb 2023 04:30:00 +0000, Sun, 26 Feb 2023 05:00:00 +0000, Sun, 26 Feb 2023 05:30:00 +0000, 
  Sun, 26 Feb 2023 06:00:00 +0000, Sun, 26 Feb 2023 06:30:00 +0000, Sun, 26 Feb 2023 07:00:00 +0000, 
  Sun, 26 Feb 2023 07:30:00 +0000, Sun, 26 Feb 2023 08:00:00 +0000, Sun, 26 Feb 2023 08:30:00 +0000, 
  Sun, 26 Feb 2023 09:00:00 +0000, Sun, 26 Feb 2023 09:30:00 +0000, Sun, 26 Feb 2023 10:00:00 +0000, 
  Sun, 26 Feb 2023 10:30:00 +0000, Sun, 26 Feb 2023 11:00:00 +0000, Sun, 26 Feb 2023 11:30:00 +0000, 
  Sun, 26 Feb 2023 12:00:00 +0000, Sun, 26 Feb 2023 12:30:00 +0000, Sun, 26 Feb 2023 13:00:00 +0000, 
  Sun, 26 Feb 2023 13:30:00 +0000, Sun, 26 Feb 2023 14:00:00 +0000, Sun, 26 Feb 2023 14:30:00 +0000, 
  Sun, 26 Feb 2023 15:00:00 +0000, Sun, 26 Feb 2023 15:30:00 +0000, Sun, 26 Feb 2023 16:00:00 +0000, 
  Sun, 26 Feb 2023 16:30:00 +0000, Sun, 26 Feb 2023 17:00:00 +0000, Sun, 26 Feb 2023 17:30:00 +0000, 
  Sun, 26 Feb 2023 18:00:00 +0000]

From this array I want to remove all the datetimes that are between beginning of each day till 10:29 o'clock and after 18:00 o'clock till the end of each the day.

Desired result:

array = 
  [Sat, 25 Feb 2023 10:30:00 +0000, Sat, 25 Feb 2023 11:00:00 +0000, ....... Sat, 25 Feb 2023 18:00:00 +0000,
  Sun, 26 Feb 2023 10:30:00 +0000, Sun, 26 Feb 2023 11:00:00 +0000, ....... Sun, 26 Feb 2023 18:00:00 +0000]

I'ved tried

 w_start_time = (start_date + 8.hours + 1.minute).strftime('%k:%M:%S')
 w_end_time = (start_date - 1.minute).strftime('%k:%M:%S')
        
 hours = array_of_datestimes.reject! { |n| n.strftime('%k:%M:%S').between?(w_start_time, w_end_time) }

this returns nil

Can someone help me?

Thank you

Upvotes: 0

Views: 70

Answers (3)

Cary Swoveland
Cary Swoveland

Reputation: 110675

Here are two ways.

Convert to minutes.

array.accept! { |date| (630..1080).cover?(60*date.hour + date.min) }

where 630 = 60*10+30 and 1080 = 60*18. See Range#cover?, which only uses range end points, making it very efficient.

Count to determine which elements to keep

We see that on the first day we wish to keep the first

(18.0 - 10.5)/0.5 + 1 = 16

elements. As there are 48 30-minute intervals per day, we wish to remove the next

48 - 16 = 32

elements. We therefore may create an enumerator that generates false 16 times, then true 32 times, then repeats, where an element of array is to be removed if the corresponding value of the enumerator equals true. We can use Array#cycle to create this enumerator.

reject = ([false]*16 + [true]*32).cycle
  #=> #<Enumerator: [false, false, false, false, false, false, false,
  #     false, false, false, false, false, false, false, false, false,
  #     true, true, true, true, true, true, true, true, true, true,
  #     true, true, true, true, true, true, true, true, true, true,
  #     true, true, true, true, true, true, true, true, true, true,
  #     true, true]:cycle>

We then simply write

array.reject! { reject.next }

To illustrate this calculation suppose array held an array of strings corresponding to the DateTime elements of the given array.

array = [
  "Sat, 25 Feb 2023 10:30:00 +0000", "Sat, 25 Feb 2023 11:00:00 +0000", 
  "Sat, 25 Feb 2023 11:30:00 +0000", "Sat, 25 Feb 2023 12:00:00 +0000", 
  "Sat, 25 Feb 2023 12:30:00 +0000", "Sat, 25 Feb 2023 13:00:00 +0000",
  "Sat, 25 Feb 2023 13:30:00 +0000", "Sat, 25 Feb 2023 14:00:00 +0000",
  "Sat, 25 Feb 2023 14:30:00 +0000", "Sat, 25 Feb 2023 15:00:00 +0000",
  "Sat, 25 Feb 2023 15:30:00 +0000", "Sat, 25 Feb 2023 16:00:00 +0000", 
  "Sat, 25 Feb 2023 16:30:00 +0000", "Sat, 25 Feb 2023 17:00:00 +0000",
  "Sat, 25 Feb 2023 17:30:00 +0000", "Sat, 25 Feb 2023 18:00:00 +0000",
  "Sat, 25 Feb 2023 18:30:00 +0000", "Sat, 25 Feb 2023 19:00:00 +0000",
  "Sat, 25 Feb 2023 19:30:00 +0000", "Sat, 25 Feb 2023 20:00:00 +0000",
  "Sat, 25 Feb 2023 20:30:00 +0000", "Sat, 25 Feb 2023 21:00:00 +0000",
  "Sat, 25 Feb 2023 21:30:00 +0000", "Sat, 25 Feb 2023 22:00:00 +0000",
  "Sat, 25 Feb 2023 22:30:00 +0000", "Sat, 25 Feb 2023 23:00:00 +0000",
  "Sat, 25 Feb 2023 23:30:00 +0000", "Sun, 26 Feb 2023 00:00:00 +0000",
  "Sun, 26 Feb 2023 00:30:00 +0000", "Sun, 26 Feb 2023 01:00:00 +0000",
  "Sun, 26 Feb 2023 01:30:00 +0000", "Sun, 26 Feb 2023 02:00:00 +0000",
  "Sun, 26 Feb 2023 02:30:00 +0000", "Sun, 26 Feb 2023 03:00:00 +0000",
  "Sun, 26 Feb 2023 03:30:00 +0000", "Sun, 26 Feb 2023 04:00:00 +0000",
  "Sun, 26 Feb 2023 04:30:00 +0000", "Sun, 26 Feb 2023 05:00:00 +0000",
  "Sun, 26 Feb 2023 05:30:00 +0000", "Sun, 26 Feb 2023 06:00:00 +0000",
  "Sun, 26 Feb 2023 06:30:00 +0000", "Sun, 26 Feb 2023 07:00:00 +0000",
  "Sun, 26 Feb 2023 07:30:00 +0000", "Sun, 26 Feb 2023 08:00:00 +0000",
  "Sun, 26 Feb 2023 08:30:00 +0000", "Sun, 26 Feb 2023 09:00:00 +0000",
  "Sun, 26 Feb 2023 09:30:00 +0000", "Sun, 26 Feb 2023 10:00:00 +0000",
  "Sun, 26 Feb 2023 10:30:00 +0000", "Sun, 26 Feb 2023 11:00:00 +0000",
  "Sun, 26 Feb 2023 11:30:00 +0000", "Sun, 26 Feb 2023 12:00:00 +0000",
  "Sun, 26 Feb 2023 12:30:00 +0000", "Sun, 26 Feb 2023 13:00:00 +0000",
  "Sun, 26 Feb 2023 13:30:00 +0000", "Sun, 26 Feb 2023 14:00:00 +0000",
  "Sun, 26 Feb 2023 14:30:00 +0000", "Sun, 26 Feb 2023 15:00:00 +0000",
  "Sun, 26 Feb 2023 15:30:00 +0000", "Sun, 26 Feb 2023 16:00:00 +0000", 
  "Sun, 26 Feb 2023 16:30:00 +0000", "Sun, 26 Feb 2023 17:00:00 +0000",
  "Sun, 26 Feb 2023 17:30:00 +0000", "Sun, 26 Feb 2023 18:00:00 +0000"
]

Then

array.reject! { reject.next }
  #=> ["Sat, 25 Feb 2023 10:30:00 +0000", "Sat, 25 Feb 2023 11:00:00 +0000",
  #    "Sat, 25 Feb 2023 11:30:00 +0000", "Sat, 25 Feb 2023 12:00:00 +0000",
  #    "Sat, 25 Feb 2023 12:30:00 +0000", "Sat, 25 Feb 2023 13:00:00 +0000",
  #    "Sat, 25 Feb 2023 13:30:00 +0000", "Sat, 25 Feb 2023 14:00:00 +0000",
  #    "Sat, 25 Feb 2023 14:30:00 +0000", "Sat, 25 Feb 2023 15:00:00 +0000",
  #    "Sat, 25 Feb 2023 15:30:00 +0000", "Sat, 25 Feb 2023 16:00:00 +0000",
  #    "Sat, 25 Feb 2023 16:30:00 +0000", "Sat, 25 Feb 2023 17:00:00 +0000",
  #    "Sat, 25 Feb 2023 17:30:00 +0000", "Sat, 25 Feb 2023 18:00:00 +0000",
  #    "Sun, 26 Feb 2023 10:30:00 +0000", "Sun, 26 Feb 2023 11:00:00 +0000",
  #    "Sun, 26 Feb 2023 11:30:00 +0000", "Sun, 26 Feb 2023 12:00:00 +0000",
  #    "Sun, 26 Feb 2023 12:30:00 +0000", "Sun, 26 Feb 2023 13:00:00 +0000",
  #    "Sun, 26 Feb 2023 13:30:00 +0000", "Sun, 26 Feb 2023 14:00:00 +0000",
  #    "Sun, 26 Feb 2023 14:30:00 +0000", "Sun, 26 Feb 2023 15:00:00 +0000",
  #    "Sun, 26 Feb 2023 15:30:00 +0000", "Sun, 26 Feb 2023 16:00:00 +0000",
  #    "Sun, 26 Feb 2023 16:30:00 +0000", "Sun, 26 Feb 2023 17:00:00 +0000",
  #    "Sun, 26 Feb 2023 17:30:00 +0000", "Sun, 26 Feb 2023 18:00:00 +0000"]

This clearly works for any number of days provided the first element of the array corresponds to 10:30 on the first day. The time associated with the last element of the array is not required to be 18:00.

This calculation will be relatively fast as it does require that each DateTime element be broken down into hours and minutes.

Upvotes: 2

maya_nk99
maya_nk99

Reputation: 502

This worked for me

 w_start_time = (start_date - 1.minute).strftime('%k:%M:%S')
 w_end_time = (start_date + 8.hours - 1.minute).strftime('%k:%M:%S')

 hours = array.filter { |n| n.strftime('%k:%M:%S').between?(w_start_time, w_end_time) }


Upvotes: 0

Vit Ruve
Vit Ruve

Reputation: 57

Maybe you should try this :

array = array.reject { |date| 
  (date.hour < 10 || (date.hour == 10 && date.min < 30)) || 
  (date.hour >= 18) 
}

Upvotes: 0

Related Questions