Расчеты за парковку Java - PullRequest
0 голосов
/ 21 марта 2019

Похоже, я не смог найти ответ для своей проблемы, поэтому я здесь, сначала о Stackoverflow :)

Дерево операторов If, которое будет упомянуто:

buttonSzamol.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {

            //Változók

                int StartHour = 18;
                int StartMin = 50;
                int StopHour = 20;
                int StopMin = 49;
                int DayTimeIntervalStart = 6;
                int DayTimeIntervalStop = 17;
                int NightTimeIntervalLateStart = 18;
                int NightTimeIntervalLateStop = 23;
                int NightTimeIntervalEarlyStart = 0;
                int NightTimeIntervalEarlyStop = 5;
              int DayHoursTotal = 0;
                int NightHoursTotal = 0;
                int DayTimePricePerHour = Integer.parseInt(NappaliOraDij.getText());
                int NightTimePricePerHour = Integer.parseInt(EjszakaiOraDij.getText());

                int StartDay = Integer.parseInt((DatumStart.getText()).replace(".", ""));
                int StopDay = Integer.parseInt((DatumStart.getText()).replace(".", ""));

                //1 started hour
                if( (StartDay == StopDay) && ( ( (StartHour == StopHour) && (StartMin < StopMin) ) || ( ((StartHour + 1) == StopHour) && (StartMin >= StopMin) ) ) ) {
                    if((DayTimeIntervalStart <= StartHour) && (StopHour <= DayTimeIntervalStop)) {
                        DayHoursTotal++;
                    }
                    if((NightTimeIntervalLateStart <= StartHour) && (StopHour <= NightTimeIntervalLateStop)) {
                        NightHoursTotal++;
                    }
                } else/*More hours*/if( (StartDay == StopDay) && ( ( (StartHour < StopHour) && (StartMin <= StopMin) ) || ( (StartHour < StopHour) && (StartMin > StopMin) ) ) ) {
                    if( (StartHour < StopHour) && (StartMin < StopMin) ) {
                        if((DayTimeIntervalStart <= StartHour) && (StopHour <= DayTimeIntervalStop)) {
                            DayHoursTotal = DayHoursTotal + (StopHour - StartHour);
                            DayHoursTotal++;
                        }
                        if((NightTimeIntervalLateStart <= StartHour) && (StopHour <= NightTimeIntervalLateStop)) {
                            NightHoursTotal = NightHoursTotal + (StopHour - StartHour);
                            NightHoursTotal++;
                        }
                    }else if(( (StartHour < StopHour) && (StartMin >= StopMin) )) {
                        if((DayTimeIntervalStart <= StartHour) && (StopHour <= DayTimeIntervalStop)) {
                            DayHoursTotal = DayHoursTotal + (StopHour - StartHour);
                            if(StartMin != StopMin) {
                                DayHoursTotal--;
                            }
                        }
                        if((NightTimeIntervalLateStart <= StartHour) && (StopHour <= NightTimeIntervalLateStop)) {
                            NightHoursTotal = NightHoursTotal + (StopHour - StartHour);
                            if(StartMin != StopMin) {
                                NightHoursTotal--;
                            }
                        }
                    }
                }

            NappaliOrak.setText(Integer.toString(DayHoursTotal));
            EjszakaiOrak.setText(Integer.toString(NightHoursTotal));
            OrakOsszesen.setText(Integer.toString(DayHoursTotal + NightHoursTotal));
            NappaliOsszeg.setText(Integer.toString(DayHoursTotal * DayTimePricePerHour));
            EjszakaiOsszeg.setText(Integer.toString(NightHoursTotal * NightTimePricePerHour));
            VegOsszeg.setText(Integer.toString((DayHoursTotal * DayTimePricePerHour) + (NightHoursTotal * NightTimePricePerHour)));
        }
    });

Итак, проблема в двух словах.Я пытался создать калькулятор платы за парковку для моего коллеги на работе.Основная идея заключается в том, что он должен рассчитать, сколько дневных и ночных часов клиент запустил, и ему нужно рассчитать цену этих часов.Я изменил поля StartHour / Min-StopHour / Min на прямые целые числа, чтобы быть более понятными.Я не знаю, есть ли модуль для этого, но я начал делать это с большим количеством операторов If, где я только что запутался.Во включенном пастбине есть время запуска 18:50 и время остановки 20:49.Если мы введем эти данные, на выходе должно быть 2 начальных дня.Теперь, если минута совпадает, она не считается начальным часом.Но если мы изменим ввод на 20:51, то начнется еще один час, поэтому DayHoursTotal должен быть равен 3.

Заранее спасибо за любую помощь.Если у вас есть еще вопросы по поводу моего кода или идеи, просто спросите.

Ответы [ 4 ]

2 голосов
/ 21 марта 2019

Похоже, что вы пытаетесь рассчитать начатое часов не только между 2 раз , но и между различными датами .

Для этого лучше всего использовать пакет java.time, а точнее класс LocalDateTime.

LocalDateTime.of(startYear, startMonth, startDay, startHour, startMinute) 

LocalDateTimes в сочетании с методом between() из класса Java 8 ChronoUnit получает именно то, что вам нужно.

ChronoUnit.MINUTES.between(Temporal t1, Temporal t2)

PS: Вам не нужно столько переменных ' interval '.
Только час начала дня (dayTimeIntervalStart) и ночи (nightTimeIntervalLateStart) достаточно.
Показатели часов до и после могут быть получены из этих двух интервалов.

Спойлер !!Отойди, если хочешь исследовать дальше сам!;)

Вот пример запускаемого кода, который показывает логику парковки для> 1 дня:
(я пропустил разбор / логику пользовательского ввода, потому что это зависит от вашей реализации)

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public class ParkingFee {

    private static long hoursDifference(LocalDateTime ldt1, LocalDateTime ldt2) {
        long minutesDiff = ChronoUnit.MINUTES.between(ldt1, ldt2);
        long hoursDiff = Math.round(Math.ceil(minutesDiff/60.0));
        return hoursDiff;
    }

    public static long hoursDifference(
                                int startDay, int startMonth, int startYear, int startHour, int startMinute, 
                                int endDay, int endMonth, int endYear, int endHour, int endMinute) {
        return hoursDifference(
                    LocalDateTime.of(startYear, startMonth, startDay, startHour, startMinute), 
                    LocalDateTime.of(endYear, endMonth, endDay, endHour, endMinute));
    }

    public static int determineDayCycle(int dayTimeIntervalStart, int nightTimeIntervalLateStart) {
        return nightTimeIntervalLateStart - dayTimeIntervalStart;
    }

    public static void main(String[] args) {
        // Hourly rates
        int dayTimePricePerHour = 5;
        int nightTimePricePerHour = 10;

        // Rate intervals
        int dayTimeIntervalStart = 6;
        int nightTimeIntervalLateStart = 18;

        // Counted hours per rate
        int dayHoursTotal = 0;
        int nightHoursTotal = 0;

        // Start date and time
        int startYear = 2019;
        int startMonth = 1;
        int startDay = 1;
        int startHour = 20;
        int startMinute = 50;

        // End date and time
        int endYear = 2019;
        int endMonth = 1;
        int endDay = 3;
        int endHour = 2;
        int endMinute = 49;

        // Calculate the hours difference
        long hourDiff = hoursDifference(
                startDay, startMonth, startYear, startHour, startMinute, 
                endDay, endMonth, endYear, endHour, endMinute);
        System.out.println("Hour difference found: "+ hourDiff);

        // Handle parking for full days
        if (hourDiff > 24) {
            int dayCycle = determineDayCycle(dayTimeIntervalStart, nightTimeIntervalLateStart);
            long fullDays = hourDiff / 24;
            nightHoursTotal += (24-dayCycle)*fullDays;
            dayHoursTotal += dayCycle*fullDays;
            hourDiff = hourDiff % 24;
        }

        // Handle the parking for less than full day
        while (hourDiff > 0) {
            if (startHour < dayTimeIntervalStart) { // Before the day interval -> night
                nightHoursTotal++;
            } else if(startHour < nightTimeIntervalLateStart) { // Before the night interval -> day
                dayHoursTotal++;
            } else { // After the day interval -> night
                nightHoursTotal++;
            }
            startHour++;
            if (startHour > 23) // At midnight reset the hour to 0
                startHour = 0;
            hourDiff--;
        }

        System.out.println("Day hours: "+ dayHoursTotal);
        System.out.println("Night hours: "+ nightHoursTotal);
        System.out.println("Total hours: "+ (dayHoursTotal + nightHoursTotal));
        System.out.println("Day rate charged at "+ dayTimePricePerHour +": "+ (dayHoursTotal * dayTimePricePerHour));
        System.out.println("Night rate charged at "+ nightTimePricePerHour +": "+ (nightHoursTotal * nightTimePricePerHour));
        System.out.println("Total rate charged: "+ ((dayHoursTotal * dayTimePricePerHour) + (nightHoursTotal * nightTimePricePerHour)));
    }
}

Это выводит:

Найденная разница в часах: 30
Дневные часы: 12
Ночные часы: 18
Всего часов: 30
Дневная стоимость 5: 60
Ночная плата 10: 180
Общая стоимость: 240

0 голосов
/ 25 марта 2019

Часовой пояс

Ваш код и другие ответы не учитывают часовой пояс аномалий.Если вы отслеживаете фактические моменты, когда люди фактически припарковались, в отличие от теоретических 24-часовых дней, вы должны учитывать такие аномалии, как летнее время (DST).Политики всего мира продемонстрировали склонность к пересмотру часового пояса в своей юрисдикции.Таким образом, дни могут быть любой длины, например, 25 часов, 23 часа, 23,5 часа, 24,25 или другие.

Часовой пояс - это история прошлых, настоящих и будущих изменений в offset-from-UTC , используемых людьми определенного региона.

Класс LocalDateTime совершенно не подходит для этой цели.Этот класс намеренно не имеет понятия о часовом поясе или смещении от UTC.Вы можете использовать его как часть строительного блока в своем коде, но ему нужно присвоить ZoneId для определения фактического момента с помощью класса ZonedDateTime.

ZoneId

Укажитеваш часовой пояс.

Если часовой пояс не указан, JVM неявно применяет свой текущий часовой пояс по умолчанию.Это значение по умолчанию может измениться в любой момент во время выполнения (!), Поэтому ваши результаты могут отличаться.Лучше явно указать желаемый / ожидаемый часовой пояс в качестве аргумента.Если критично, подтвердите зону с вашим пользователем.

Укажите правильное имя часового пояса в формате Continent/Region, например America/Montreal, Africa/Casablanca или Pacific/Auckland,Никогда не используйте 2-4 буквенные сокращения, такие как EST или IST, так как они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;  

Если вы хотите использовать текущий часовой пояс JVM по умолчанию, запросите его и передайте в качестве аргумента.Если опущен, код становится неоднозначным для чтения, поскольку мы точно не знаем, намеревались ли вы использовать значение по умолчанию или если вы, как и многие программисты, не знали о проблеме.

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

Дата сборки, время и зона для определения момента

Соберите дату и время суток.

LocalDate startDate = LocalDate.of( 2019 , 1 , 23 ) ;  // 23rd of January in 2019.
LocalTime startTime = LocalTime.of( 18 , 50 ) ;  // 6:50 PM.
ZonedDateTime startMoment = ZonedDateTime.of( startDate , startTime , z ) ;

LocalDate stopDate = LocalDate.of( 2019 , 1 , 23 ) ;  // 23rd of January in 2019.
LocalTime stopTime = LocalTime.of( 20 , 50 ) ;  // Two hours later, exactly — maybe! Depends on any anomalies at that time in that zone.
ZonedDateTime stopMoment = ZonedDateTime.of( stopDate , stopTime , z ) ;

➥ Обратите внимание, что в этом примере мы можем иметьпромежуток времени ровно 2 часа, но может и не .Это может быть 3 часа или какой-то другой промежуток времени, в зависимости от аномалий, запланированных на эту дату в это время в этой зоне.

Истекшее время

Чтобы рассчитать истекшее время, это сроки дней (24-часы времени, не связанные с календарем), часы, минуты и секунды, используйте Duration.(Для года-месяца-дня используйте Period.)

Duration d = Duration.between( startMoment , stopMoment ) ;

Опрос за весь промежуток времени в единицах целых часов.

long hours = d.toHours() ;  // Entire duration as count of whole hours.

Half-Open

Во включенном пастбине время запуска 18:50 и время окончания 20:49.Если мы введем эти данные, на выходе должно быть 2 начальных дня.Теперь, если минута совпадает, она не считается начальным часом.Но если мы изменим ввод на 20:51, то начнется еще один час, поэтому DayHoursTotal должен быть равен 3.

Этот подход известен как Half-Open , когда начало включительно , а окончание эксклюзивно .Это обычно используется при обработке даты и времени.Классы Duration и Period применяют этот подход.

Но будьте осторожны, сопоставляя только номер минуты.Ваши объекты даты и времени могут содержать секунды и / или доли секунды, что отбросит ваш алгоритм.Как правило, обрезайте ваши объекты даты и времени явно, если есть какая-либо вероятность меньшей детализации, чем вы хотите.Например, ZonedDateTime.truncatedTo.

Изменение курса

Очевидно, что изменение курса усложняет ситуацию.Другие ответы, кажется, охватили это, поэтому я не буду повторяться.Но я могу добавить большой совет: см. ThreeTen-Extra для его классов Interval и LocalDateRange, которые могут быть вам полезны.Они включают удобные методы сравнения перекрытий, содержаний, примыканий и т. Д.

0 голосов
/ 21 марта 2019

разделяй и властвуй

Сокращение большой логики в маленьких блоках облегчает достижение

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;

class Scratch {
    static int StartHour = 18;
    static int StartMin = 50;
    static int StopHour = 20;
    static int StopMin = 48;
    static int DayTimeIntervalStart = 6;
    static int DayTimeIntervalStop = 17;
    static int NightTimeIntervalLateStart = 18;
    static int NightTimeIntervalLateStop = 23;
    static int NightTimeIntervalEarlyStart = 0;
    static int NightTimeIntervalEarlyStop = 5;
    static int DayTimePricePerHour = 10;
    static int NightTimePricePerHour = 5;
    static LocalTime dayStart = LocalTime.of(DayTimeIntervalStart, 0);
    static LocalTime dayStop = LocalTime.of(DayTimeIntervalStop, 0);
    static LocalTime nightEarlyStart = LocalTime.of(NightTimeIntervalEarlyStart, 0);
    static LocalTime nightEarlyStop = LocalTime.of(NightTimeIntervalEarlyStop, 0);
    static LocalTime nightLateStart = LocalTime.of(NightTimeIntervalLateStart, 0);
    static LocalTime nightLateStop = LocalTime.of(NightTimeIntervalLateStop, 0);


    public static void main(String[] args) {
        LocalDateTime start = LocalDateTime.of(2019, 1, 1, StartHour, StartMin);
        LocalDateTime stop = LocalDateTime.of(2019, 1, 1, StopHour, StopMin);

        for(int i = 0; i < 3; i++){
            stop = stop.plusMinutes(1L);
            System.out.println(process(start, stop));
            System.out.println("******");
        }

        stop = stop.plusDays(1L);
        System.out.println(process(start, stop));
        System.out.println("******");

    }


    public static int process(LocalDateTime start, LocalDateTime stop){
        System.out.println(String.format("checking between %s and %s", start, stop));
        if(stop.toLocalDate().isAfter(start.toLocalDate())){
            // start and stop not on the same date
            // split the computation, first currentDay then the rest
            LocalDateTime endOfDay = LocalDateTime.of(start.toLocalDate(), LocalTime.MAX);
            int resultForCurrentDay = process(start, endOfDay);

            // not for the rest
            LocalDateTime startOfNextDay = LocalDateTime.of(start.toLocalDate().plusDays(1L), LocalTime.MIN);
            int resultForRest = process(startOfNextDay, stop);
            return resultForCurrentDay + resultForRest;
        }else{
            // start and stop on the same date
            return processIntraDay(start, stop);
        }
    }

    private static int processIntraDay(LocalDateTime start, LocalDateTime stop) {
        int result = 0;
        LocalTime startTime = start.toLocalTime();
        LocalTime stopTime = stop.toLocalTime();

        // step 1: check early morning
        result += checkBoundaries(startTime, stopTime, nightEarlyStart, nightEarlyStop, NightTimePricePerHour);

        // step 2: check day time
        result += checkBoundaries(startTime, stopTime, dayStart, dayStop, DayTimePricePerHour);


        // step 3: check late night
        result += checkBoundaries(startTime, stopTime, nightLateStart, nightLateStop, NightTimePricePerHour);

        return result;
    }

    private static int checkBoundaries(LocalTime startTime, LocalTime stopTime, LocalTime lowerBoundary, LocalTime upperBoundary, int priceRatePerHour) {
        // check if the period [start;stop] is crossing the period [lowerBoundary;upperBoundary]
        if(stopTime.isAfter(lowerBoundary) && startTime.isBefore(upperBoundary)){
            // truncate start time to not be before lowerBoundary
            LocalTime actualStart = (startTime.isBefore(lowerBoundary))?lowerBoundary:startTime;

            // symetrically, truncate stop to not be after upperBounday
            LocalTime actualStop = (stopTime.isAfter(upperBoundary))?upperBoundary:stopTime;

            // now that we have the proper start and stop of the period, let's compute the price of it
            return compute(actualStart, actualStop, priceRatePerHour);
        }else{
            return 0;
        }
    }

    private static int compute(LocalTime startTime, LocalTime stopTime, int pricePerHour) {
        Duration duration = Duration.between(startTime, stopTime);
        int hours = (int) duration.toHours();
        long minutes = duration.toMinutes();
        if(minutes % 60 > 0L){
            // hour started, increasing the number
            hours++;
        }
        int result = hours * pricePerHour;
        System.out.println(String.format("%d hours at %d price/h => %d", hours, pricePerHour, result));
        return result;
    }
}

Отправился непосредственно для расчета окончательной цены.Обновление для хранения общего количества дневных и ночных часов должно быть большой проблемой

Результат моего примера:

checking between 2019-01-01T18:50 and 2019-01-01T20:49
2 hours at 5 price/h => 10
10
******
checking between 2019-01-01T18:50 and 2019-01-01T20:50
2 hours at 5 price/h => 10
10
******
checking between 2019-01-01T18:50 and 2019-01-01T20:51
3 hours at 5 price/h => 15
15
******
checking between 2019-01-01T18:50 and 2019-01-02T20:51
checking between 2019-01-01T18:50 and 2019-01-01T23:59:59.999999999
5 hours at 5 price/h => 25
checking between 2019-01-02T00:00 and 2019-01-02T20:51
5 hours at 5 price/h => 25
11 hours at 10 price/h => 110
3 hours at 5 price/h => 15
175
******

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

0 голосов
/ 21 марта 2019

Во-первых, вам нужно проанализировать целые числа по-разному.Ваш метод опасен, например, теряет информацию.Кроме того, вам нужно сделать код отказоустойчивым на случай, если кто-то попытается ввести значения, которые не будут работать.Обратитесь к этому вопросу: Как мне преобразовать String в int в Java?

Кроме того, работа с минутами и часами всегда трудна.Я предлагаю использовать абсолютное время в миллисекундах, что значительно упрощает вычисления.Обратитесь к этому вопросу: Разница в часах двух объектов Календаря

...