Как узнать, находится ли вторая рука часов в большей области или меньше

Мне дано время в формате: hh:mm:ss

Мне нужно найти, если в течение заданного времени вторая рука лежит в большей или меньшей области, образованной часовыми и минутными стрелками?

Я знаю, что часовая стрелка движется со скоростью 0,5 градуса в минуту, минутная стрелка перемещается со скоростью 6 градусов в минуту, а вторая рука заканчивается на 360 градусов в минуту.

Но я не могу узнать, в какой области находится вторая рука. Итак, как я могу это сделать?

Second hand within angle between hour and minute hands:
10:15:00
04:40:30

Second hand in reflex angle:
12:01:30

Ответ 1

Проблема заинтриговала меня, поэтому я пошел вперед и написал тестовый проект в C#. Насколько я могу сказать, он работает, вам придется протестировать его, чтобы убедиться, что.

Это код:

string strTime = "10:15:00";

DateTime dt = DateTime.ParseExact(strTime, "HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);

int nHourDegrees = (360 / 12) * dt.Hour;
int nMinuteDegrees = (360 / 60) * dt.Minute;
int nSecondDegrees = (360 / 60) * dt.Second;

if (nHourDegrees > nMinuteDegrees)
{
    int nArea1 = nHourDegrees - nMinuteDegrees;
    int nArea2 = 360 - nArea1;

    bool bArea1IsBigger = (nArea1 >= nArea2);
    if (nSecondDegrees <= nHourDegrees && nSecondDegrees >= nMinuteDegrees)
    {
        //Second hand lies in area1
        if (bArea1IsBigger)
        {
            Console.WriteLine("Second hand is in the larger area");
        }
        else
        {
            Console.WriteLine("Second hand is in the smaller area");
        }
    }
    else
    {
        if (bArea1IsBigger)
        {
            Console.WriteLine("Second hand is in the smaller area");
        }
        else
        {
            Console.WriteLine("Second hand is in the larger area");
        }
    }
}
else if (nMinuteDegrees > nHourDegrees)
{
    int nArea1 = nMinuteDegrees - nHourDegrees;
    int nArea2 = 360 - nArea1;

    bool bArea1IsBigger = (nArea1 >= nArea2);
    if (nSecondDegrees <= nMinuteDegrees && nSecondDegrees >= nHourDegrees)
    {
        //Second hand lies in area1
        if (bArea1IsBigger)
        {
            Console.WriteLine("Second hand is in the larger area");
        }
        else
        {
            Console.WriteLine("Second hand is in the smaller area");
        }
    }
    else
    {
        if (bArea1IsBigger)
        {
            Console.WriteLine("Second hand is in the smaller area");
        }
        else
        {
            Console.WriteLine("Second hand is in the larger area");
        }
    }
}
else
{
    if (nSecondDegrees == nHourDegrees)
    {
        Console.WriteLine("Second hand is on both of the other hands");
    }
    else
    {
        Console.WriteLine("Second hand is in the ONLY area");
    }
}

Идея состоит в том, что мы находим области между часами и минутами. Затем проверьте, находится ли вторая рука внутри этой области. Мы также сравниваем эту область с другой, и тогда мы можем легко вывести, если вторая рука находится в меньшей или большей из двух.

Примечание. Некоторые улучшения могут быть внесены в код:

  • Это может быть значительно короче - я этого не делал, потому что это было главным образом испытание/доказательство того, как это можно сделать.
  • Если перерыв часов (т.е. 24 часа, а не 12), потребуется внести изменения. то есть минус 12
  • Если время идет до 12/60/60 и не возвращается к 0, это нужно сделать вручную
  • Константы могут быть добавлены для устранения необходимости в магических числах
  • Подобно приведенным выше, но общие вычисления, такие как 360 / 12, могут быть перемещены в константы
  • Его можно разбить на отдельные методы для улучшения удобочитаемости.
  • Можно переместить в вспомогательный метод, т.е. bool IsInLargerArea(string timeString)
  • Нужно добавить случай, когда области имеют одинаковый размер, на данный момент я просто предполагаю, что Area1 будет больше, если они равны. i.e >= (больше или равно)
  • Добавьте проверки, чтобы убедиться, что в массив straTimes есть только 3 части
  • И, возможно, еще несколько вещей, о которых я не думал о

Ответ 2

Я бы пошел с методом, который выглядит так. Вы должны идентифицировать, если меньшая область проходит через 0 градусов или нет, а затем на основе этого вы можете сказать решение.

int minDegree;
int maxDegree;
bool over360;

if (Math.abs(hourHandDegree - minuteHandDegree) < 180){
   minDegree = Math.min(hourHandDegree, minuteHandDegree);
   maxDegree = Math.max(hourHandDegree, minuteHandDegree);
   over360 = false;
} else {
   minDegree = Math.min(hourHandDegree, minuteHandDegree);
   maxDegree = Math.max(hourHandDegree, minuteHandDegree);
   over360 = true;
}

if (over360){
    if ((secondHandDegree < minDegree) && (secondHandDegree > maxDegree)){
        return true;
    } else {
        return false;
    }
} else {
    if ((secondHandDegree > minDegree) && (secondHandDegree < maxDegree)){
        return true;
    } else {
        return false;
    }
}

Ответ 3

Это решение является кратким, понятным и позволяет использовать 12-часовой или 24-часовой ввод.

Легче визуализировать, когда вы используете радианы.

Ниже приведено R, но, надеюсь, достаточно легко читать. Примечание %% является модульным оператором.

which_region <- function(s){

  # number of seconds elapsed in day (i.e., since midnight)
  sec <- as.numeric(as.POSIXct(s, tz = "GMT", format = "%H:%M:%S")) %% (12*60*60)

  # angle of each hand, clockwise from vertical, in radians
  hour_ang <- 2*pi * (sec / (12*60*60)) # hour makes a circuit every 12*60*60 sec
  min_ang  <- 2*pi * ((sec / 60^2) %% 1) # min makes a circuit every 60*60 sec 
  sec_ang  <- 2*pi * ((sec / 60) %% 1) # sec makes a circuit every 60 sec

  hour_to_min_ang <- (2*pi + min_ang - hour_ang) %% (2*pi)
  min_to_hr_ang <- (2*pi + hour_ang - min_ang) %% (2*pi)

  if(hour_to_min_ang < min_to_hr_ang){
    return(ifelse(sec_ang > hour_ang & sec_ang < min_ang,
           "Smaller Area","Larger Area") )
  } else if(min_to_hr_ang < hour_to_min_ang){
    return(ifelse(sec_ang > min_ang & sec_ang < hour_ang,
           "Smaller Area","Larger Area") )
  } else return("Equal")
}  

which_region("06:00:00") # Equal
which_region("01:10:00") # Larger Area
which_region("01:20:15") # Smaller Area
which_region("05:10:20") # Smaller Area
which_region("12:00:00") # Equal
which_region("21:55:50") # Smaller Area
which_region("10:55:15 PM") # Larger Area