38

I need to write a method that will check if Time.now is in between the open hours and the close hours of a shop.

The open and close hours are saved as a Time object but I can't compare it corectly because the shop saved its hours at 2012/2/2 so the open hours will be something like:

2012-02-02 02:30:00 UTC

and Time.now will be:

07:23 +0200

How can I compare just the time part without the date part?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
user1666543
  • 665
  • 1
  • 10
  • 19
  • How about you try to extract the time from the date first? http://stackoverflow.com/a/280464/1004274 – oldergod Jan 15 '13 at 00:24
  • has any answer been helpful? – Малъ Скрылевъ Feb 01 '14 at 19:21
  • I don't believe that any of the answers to date (June 18, 2018) are correct because they don't consider the case where the shop is open at midnight. See [this](https://stackoverflow.com/questions/50733988/find-out-if-current-time-is-between-two-times/50735709#50735709) SO question. – Cary Swoveland Jun 07 '18 at 18:51
  • @CarySwoveland the time is 0 in that case, what is else? – Малъ Скрылевъ Jun 23 '20 at 14:30
  • @МалъСкрылевъ, my memory is not great at the best of times, but I have no recollection of this two-year-old question. To answer your question I would have to familiarize myself with the question and all the answers, which would take too much time. All I can say is that my comment probably had to do with closing times preceding opening times on a 24-hour clock. For example, opening at 20:00 and closing at 04:00 (the next day). – Cary Swoveland Jun 23 '20 at 16:31
  • @CarySwoveland this should be taken into account with additional condition check ) when end < begin – Малъ Скрылевъ Jun 25 '20 at 10:53

8 Answers8

42

You can compare the Time without a date part, for example, as follows:

time1.utc.strftime( "%H%M%S%N" ) <= time2.utc.strftime( "%H%M%S%N" )
Малъ Скрылевъ
  • 16,187
  • 5
  • 56
  • 69
  • if open time is 08 AM and close time is 01 AM. does it work ? – Vishal Mar 22 '18 at 08:44
  • 1
    @Vishal but how do you wish for the code to work to? – Малъ Скрылевъ Mar 22 '18 at 20:21
  • @МалъСкрылевъ I use postgres as db. i have two fields open_at, close_at , Datatype is time. In my case, store's open time is 8 AM and close time is 1:00 AM, it means store will close tomorrow's 1 AM. so my query fail because ,`open_at <= close_at` becomes false. can you help me to overcome this issue ? – Vishal Mar 23 '18 at 04:15
  • @Vishal if type of the fields in ruby are strings, you can't compare them is such way, class of the variables in ruby must be only Time or DateTime to the that kind of comparison – Малъ Скрылевъ Mar 23 '18 at 08:06
  • Yes it is Time Class. and it is storing in this format "2000-01-01 08:00:00" – Vishal Mar 23 '18 at 09:44
  • @МалъСкрылевъ when opening time is 8 AM and closing time is 1 AM. it is storing in this format ,open at "2000-01-01 08:00:00" , close_at "2000-01-01 01:00:00" – Vishal Mar 23 '18 at 09:52
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/167413/discussion-between-vishal-and--). – Vishal Mar 23 '18 at 10:31
5

There is a nice library https://github.com/bokmann/business_time which will do this and more for you.

BusinessTime::Config.with(beginning_of_workday: "8:30 am", end_of_workday: "5:30 pm") do
  Time.now.during_business_hours?
end

It will do much more for you, like rolling a time to next or previous opening time, counting business hours between two timestamps, etc.

rewritten
  • 16,280
  • 2
  • 47
  • 50
4

You can strip the Time into its hours, minutes and seconds.

As described in Time Class:

t = Time.now
hour = t.hour
minute = t.min
seconds = t.sec

Since you need to just compare whether it's within 2 hours you can check it as below.

if hour > openingHour and hour < closingHour
Althaf Hameez
  • 1,511
  • 1
  • 10
  • 18
4

You can compare only time in rails without date part like:--- Here post_review is table and we are getting only these record of post_review which are created_at between 10 am ---5pm in any date

post_review.where("(created_at::time >= :start_time) AND (created_at::time <= :end_time)", 
    start_time: Time.parse("10 am").strftime("%r"),
    end_time:   Time.parse("5 pm").strftime("%r")
 )
knut
  • 27,320
  • 6
  • 84
  • 112
Ganesh Shrivas
  • 157
  • 1
  • 2
3

Instead of trying to compare the point of time directly, you can compare their offsets from a common reference (e.g. midnight). You might need to make sure all times are using the same time zone, depending on your use case.

In Rails, this can be done easily with one of the helpers such as #seconds_since_midnight:

#given
opening_hour = DateTime.new(2012,2,2,2,30,0)

#compare
now = DateTime.now.in_time_zone('UTC')
opening_hour_since_midnight = opening_hour.seconds_since_midnight
now_since_midnight = now.seconds_since_midnight
p 'shop opened' if now_since_midnight > opening_hour_since_midnight
EJAg
  • 3,210
  • 2
  • 14
  • 22
2

Try converting the Time into a number and strip off the days. Since the Time is represented as a number of seconds since the UNIX Epoch with the decimal being a fraction of the second, you can convert this number to a number of days with the fraction being a fraction of a day.

Day based number = Ruby Time Number / 60 / 60 / 24

You can then use the modulus operator to strip the day portion so all you have left to compare is the time. So you want something like this:

def is_open?(time)
  open_h=Time.parse('2012-02-02 02:30:00 UTC')
  close_h=Time.parse('2012-02-02 10:00:00 UTC')
  (((time.to_r / 60 / 60 / 24) % 1) >= ((open_h.to_r / 60 / 60 / 24) % 1)) && (((time.to_r / 60 / 60 / 24) % 1) <= ((close_h.to_r / 60 / 60 / 24) % 1))
end

is_open? (Time.parse('2013-01-01 09:58:00 UTC'))
=> true
is_open? (Time.parse('2013-01-01 12:58:00 UTC'))
=> false
Winston Kotzan
  • 1,979
  • 20
  • 25
-1
close_or_open_time_object.to_a.first(3).reverse <=> Time.now.to_a.first(3).reverse
sawa
  • 165,429
  • 45
  • 277
  • 381
-6

This will work only for time being in 24 hour format and when start hour is less than end hour.

Time start = DateUtil.convertStringToTime(Object.getStartTime());
Time mid = DateUtil.convertStringToTime(time);
Time end = DateUtil.convertStringToTime(Object.getEndTime());

    if(mid.getHours()>start.getHours() && mid.getHours()< end.getHours())
    {
        flag=true;
    }
    else if(mid.getHours() == start.getHours() && mid.getHours() < end.getHours())
    {
        if(mid.getMinutes() > start.getMinutes())
        {               
            flag=true;              
        }
        else if(mid.getMinutes() == start.getMinutes())
        {               
            if(mid.getSeconds() >= start.getSeconds())
            {
                flag=true;
            }
        }
    }
    else if(mid.getHours() > start.getHours() && mid.getHours() == end.getHours())
    {
        if(mid.getMinutes() < end.getMinutes())
        {
            flag=true;
        }
        else if(mid.getMinutes() == end.getMinutes())
        {
            if(mid.getSeconds() <= end.getSeconds())
            {
                flag=true;
            }
        }
    }
    else if(mid.getHours() == start.getHours() && mid.getHours() == end.getHours())
    {
        if(mid.getMinutes() > start.getMinutes() && mid.getMinutes() < end.getMinutes())
        {
            flag=true;
        }           
        else if(mid.getMinutes() == start.getMinutes() && mid.getMinutes() < end.getMinutes())
        {
            if(mid.getSeconds() > start.getSeconds())
            {
                flag=true;
            }
        }
        else if(mid.getMinutes() > start.getMinutes() && mid.getMinutes() == end.getMinutes())
        {
            if(mid.getSeconds() < end.getSeconds())
            {
                flag=true;
            }
        }
        else if(mid.getMinutes() == start.getMinutes() && mid.getMinutes() == end.getMinutes())
        {
            if(mid.getSeconds() > start.getSeconds() && mid.getSeconds() < end.getSeconds())
            {
                flag=true;
            }
        }
    }