0

看来,我找不到我的问题的答案,所以我在这里,首先是 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 语句来做这件事,我只是纠结了。在包含的 pastebin 中,有开始时间 18:50 和停止时间 20:49。如果我们输入这个数据,输出应该是 2 个开始日的小时数。现在,如果分钟相同,则不算作开始小时。但如果我们将输入更改为 20:51,那么它又开始了一个小时,因此 DayHoursTotal 应该等于 3。

预先感谢您的任何帮助。如果您对我的代码或想法有更多疑问,请询问。

4

4 回答 4

2

看来您不仅要计算两次之间的开始时间,而且还要计算不同日期之间的开始时间。

为此,最好使用java.time包,更具体地说是使用LocalDateTime类。

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

LocalDateTimes结合between()Java 8ChronoUnit类中的方法可以得到你所需要的。

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

PS:您不需要那么多“区间”变量。
只需白天( 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

于 2019-03-21T10:20:28.580 回答
0

首先,您需要以不同的方式解析整数。您的方法很危险,例如丢失信息。另外,您需要使代码失效,以防有人试图输入不起作用的值。参考这个问题:How do I convert a String to an int in Java?

除此之外,只用几分钟和几小时工作总是很困难的。我建议使用以毫秒为单位的绝对时间,这使得计算变得容易得多。参考这个问题:两个日历对象的小时差

于 2019-03-21T07:05:24.417 回答
0

分而治之

把大逻辑切小块更容易实现

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
******

可能需要更多测试以确保它在所有条件下都很好,但对您来说应该是一个有用的起点

于 2019-03-21T10:22:53.133 回答
0

时区

您的代码和其他答案未能考虑时区异常。如果您要跟踪人们实际停车的实际时刻,而不是理论上的 24 小时全天,那么您必须考虑诸如夏令时 (DST) 之类的异常情况。世界各地的政客都表现出重新定义其管辖范围内的时区的倾向。所以天可以是任意长度,例如 25 小时、23 小时、23.5 小时、24.25 或其他。

时区是过去、现在和未来对特定地区人民使用的UTC 偏移量变化的历史记录。

该类LocalDateTime正是用于此目的的错误类。该类故意没有时区或与 UTC 偏移的概念。您可以将它用作代码中的构建块,但必须为其分配 aZoneId以通过类确定实际时刻ZonedDateTime

ZoneId

指定您的时区。

如果未指定时区,JVM 会隐式应用其当前默认时区。该默认值可能会在运行时(!)期间随时更改,因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。如果很重要,请与您的用户确认该区域。

以、或等格式指定适当的时区名称。永远不要使用 2-4 个字母的缩写,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。Continent/RegionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST

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 ) ;

➥ Note that in this example, we may have a span of time of exactly 2 hours, but maybe not. It might be 3 hours or some other length of time, depending on anomalies scheduled for that date at that time in that zone.

Elapsed time

To calculate elapsed time it terms of days (24-hour chunks of time, unrelated to the calendar), hours, minutes, and seconds, use Duration. (For year-months-days, use Period.)

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

Interrogate for entire span-of-time in terms of whole hours.

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

Half-Open

In the included pastebin, there is starting time 18:50 and stop time 20:49. If we input this data, the output should be 2 started day hours. Now if the minute is the same, it does not count as a started hour. But if we change the input to 20:51, then it started an another hour, so the DayHoursTotal should be equal to 3.

This approach is know as Half-Open, when the beginning is inclusive, while the ending is exclusive. This is commonly used in date-time handling. The Duration and Period classes apply this approach.

But be careful about matching the minute number alone. Your date-time objects might be holding seconds and/or a fractional second, which would throw off your algorithm. As a habit, truncate your date-time objects explicitly if there is any possibility of smaller granularity than you want. For example, ZonedDateTime.truncatedTo.

Rate changes

Obviously, rate changes complicate matters. The other Answers seem to have covered this, so I'll not repeat. But I can add a big tip: See the ThreeTen-Extra for its classes Interval and LocalDateRange that may be of help to you. They include handy comparison methods for overlaps, contains, abuts, and so on.

于 2019-03-24T22:08:15.133 回答