Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking dates if it is in a range

My Java FX app handles hours worked. I have work start and end time in 2 date fields. I succeeded in calculating the differences between 2 datesTime; but now how could I check if the result is in a night or day range???? The day begin at 6 and ends at 22h. For example someone who worked between 3Am till 11Pm. Here is below how I did to have the total number of hours worked.

public void CalculNbreJourTravaille() {
    SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyy HH:mm");

    try {
        Date ddtt = format.parse(ddt.getText());
        Date dftt = format.parse(dft.getText());
        long diff = dftt.getTime() - ddtt.getTime();
        long diffhours = diff / (60*60*1000)%24;
        long diffdays = diff/(24*60*60*1000);
        long total = diffhours + (diffdays*24);
        result.setText(total + " Hours");   
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

We have workers who can work beyond 10PM, and the pay would not be the same. If they work after 10pm, they will have a special pay. We pay at the end of the work. They could would work only 10 days or more.

like image 611
DJIBFX Avatar asked Jan 03 '23 11:01

DJIBFX


2 Answers

You should use the new DateTimeFormatter class to give you a LocalDateTime object, which you can pull the hour from.

DateTimeFormatter format = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
LocalDateTime localDateTimeFrom = format.parse(dateFrom.getText(), LocalDateTime::from);
LocalDateTime localDateTimeTo = format.parse(dateTo.getText(), LocalDateTime::from);

int hoursFrom = localDateTimeFrom.getHour();
int hoursTo = localDateTimeTo.getHour();

boolean workedNight = hoursFrom < 6 || hoursTo > 22;
like image 159
Dawood ibn Kareem Avatar answered Jan 04 '23 23:01

Dawood ibn Kareem


Here’s my attempt to cover all of your requirements. I wrote the code before reading that you don’t require that summer time (DST) is taken into account, so I am using ZonedDateTime to get correct hours also across summer time transitions. For the same reason I need to iterate over each day. For each date I calculate the hours worked at night time and the hours worked at day time.

If you want to make sure that summer time is not taken into account, use LocalDateTime instead of ZonedDateTime. In this case there may also be a possible performance gain in calculating the whole work days in one lump rather than one day at a time.

The code below uses 28/03/2018 03:00 and 29/03/2018 23:30 as example start and end time. Expected total hours worked are 44.5 since one day is 24 hours and there are 20.5 hours from 03:00 to 23:30. The expected day time hours are 32 since there are 16 daytime hours each of the two days. This leaves 12.5 hours as night time. And indeed the code prints

Day 32.0 hours; night 12.5 hours

The program follows. Please fill in the correct time zone where I put America/Monterey.

static ZoneId zone = ZoneId.of("America/Monterrey");
static LocalTime dayStart = LocalTime.of(6, 0);
static LocalTime dayEnd = LocalTime.of(22, 0);
static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/uuuu H:mm");

public static void main(String[] args) {

    String workStartString = "28/03/2018 03:00";
    String workEndString = "29/03/2018 23:30";
    calculateWorkingHours(workStartString, workEndString);
}

public static void calculateWorkingHours(String workStartString, String workEndString) {
    ZonedDateTime workStart
            = LocalDateTime.parse(workStartString, formatter).atZone(zone);
    ZonedDateTime workEnd
            = LocalDateTime.parse(workEndString, formatter).atZone(zone);

    if (workEnd.isBefore(workStart)) {
        throw new IllegalArgumentException("Work end must not be before work start");
    }

    LocalDate workStartDate = workStart.toLocalDate();
    LocalDate workEndDate = workEnd.toLocalDate();

    Duration workedDaytime = Duration.ZERO;
    // first calculate work at nighttime before the start date, that is, work before 06:00
    Duration workedNighttime 
            = calculateNightTime(workStartDate.minusDays(1), workStart, workEnd);

    for (LocalDate d = workStartDate; ! d.isAfter(workEndDate); d = d.plusDays(1)) {
        workedDaytime = workedDaytime.plus(calculateDayTime(d, workStart, workEnd));
        workedNighttime = workedNighttime.plus(calculateNightTime(d, workStart, workEnd));
    }

    double dayHours = workedDaytime.toMinutes() / (double) TimeUnit.HOURS.toMinutes(1);
    double nightHours = workedNighttime.toMinutes() / (double) TimeUnit.HOURS.toMinutes(1);

    System.out.println("Day " + dayHours + " hours; night " + nightHours + " hours");

}

/**
 * Calculates amount of work in daytime on d,
 * that is between 06:00 and 22:00 on d.
 * Only time that falls with in workStart to workAnd
 * and also falls within 06:00 to 22:00 on d is included.
 * 
 * @param d The date for which to calculate day work
 * @param workStart
 * @param workEnd
 * @return Amount of daytime work on the said day
 */
private static Duration calculateDayTime(LocalDate d, ZonedDateTime workStart, ZonedDateTime workEnd) {
    ZonedDateTime dayStartToday = d.atTime(dayStart).atZone(zone);
    ZonedDateTime dayEndToday = d.atTime(dayEnd).atZone(zone);
    if (workStart.isAfter(dayEndToday) || workEnd.isBefore(dayStartToday)) {
        return Duration.ZERO;
    }

    // restrict calculation to daytime on d
    if (workStart.isBefore(dayStartToday)) {
        workStart = dayStartToday;
    }
    if (workEnd.isAfter(dayEndToday)) {
        workEnd = dayEndToday;
    }

    return Duration.between(workStart, workEnd);
}

/**
 * Calculates amount of night work in the night after d,
 * that is from 22:00 on d until 06:00 the next morning.
 * 
 * @param d The date for which to calculate night work
 * @param workStart
 * @param workEnd
 * @return Amount of nighttime work in said night
 */
private static Duration calculateNightTime(LocalDate d, ZonedDateTime workStart, ZonedDateTime workEnd) {
    assert ! workEnd.isBefore(workStart);

    ZonedDateTime nightStart = d.atTime(dayEnd).atZone(zone);
    ZonedDateTime nightEnd = d.plusDays(1).atTime(dayStart).atZone(zone);

    if (workEnd.isBefore(nightStart) || workStart.isAfter(nightEnd)) {
        return Duration.ZERO;
    }

    // restrict calculation to the night after d
    if (workStart.isBefore(nightStart)) {
        workStart = nightStart;
    }
    if (workEnd.isAfter(nightEnd)) {
        workEnd = nightEnd;
    }

    return Duration.between(workStart, workEnd);
}
like image 39
Ole V.V. Avatar answered Jan 04 '23 23:01

Ole V.V.