3

Let's say I have two datetimes, 30-11-2015 10:00 and 02-12-2015 15:00. I also have two times, 07:00 and 22:00. How could I calculate the amount of time passed between the two date/times that was within the second times? Using Calendar object? It seems simple but its boggling my mind.

0ne_Up
  • 471
  • 3
  • 9
  • 24
  • so for all the days in the first interval, you want to know how much of those days had an 07-22 time interval? – Marc B Dec 01 '15 at 21:02
  • What have you tried so far? This doesn't seem to be a java problem so much as a problem solving issue. Think about what those pieces of information represent, how the ranges might overlap, etc. It might help to draw a few pictures to get yourself started. – bstockwell Dec 01 '15 at 21:03
  • `was within the second times` <- not sure what that means, can you clarify please? – Taylor Dec 01 '15 at 21:04
  • Possible duplicate of [Calculating the difference between two Java date instances](http://stackoverflow.com/questions/1555262/calculating-the-difference-between-two-java-date-instances) – JFPicard Dec 01 '15 at 21:04
  • 2
    I'd suggest computing the number of days between your start and end dates, inclusive, multiplying by the the size of your 07:00 - 22:00 time window, and subtracting off the part of the window that precedes the start time of your interval on the first date and the part that follows the end time on the last date. Yes, you can use `Calendar`s to help with that. – John Bollinger Dec 01 '15 at 21:08
  • How much time was within 7-22 that was within the datetimes. In this case the result would be 35 hours. – 0ne_Up Dec 01 '15 at 21:12

2 Answers2

1

Since none of the other answers include runnable code, I can't tell if they solve the problem or not.

To calculate the duration of a time range within a date range, you have to:

  • Split the date range into multiple date ranges, each spanning no more than one day.
  • Calculate the time range within each day date range

Taking the example date range from the question. 30-11-2015 10:00 and 02-12-2015 15:00, we generate the following split day date ranges:

30-11-2015 10:00 - 30-11-2015 24:00
01-12-2015 00:00 - 01-12-2015 24:00
02-12-2015 00:00 - 02-12-2015 15:00

Now, we can apply the time range of 7:00 - 22:00 to each of the split day date ranges.

30-11-2015 10:00 - 30-11-2015 24:00 -> 12 hours
01-12-2015 00:00 - 01-12-2015 24:00 -> 15 hours
02-12-2015 00:00 - 02-12-2015 15:00 ->  8 hours

For a total of 35 hours. The actual calculation would probably be in minutes instead of hours.

Edited to add: I created a Time and a TimeRange class to hold the time and a day time range, respectively. I used the java.util.Date, although I had to create my own increment a day method.

I put all of the classes together so I could post this easier. The classes should be put in separate files.

package com.ggl.testing;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class TimeRangeTest {

    private static final SimpleDateFormat inputDateFormat = new SimpleDateFormat(
            "dd-MM-yyyy");

    public static void main(String[] args) {
        TimeRangeTest test = new TimeRangeTest();
        int minutes = test.calculateTotalMinutes("30-11-2015 10:00",
                "02-12-2015 15:00", "07:00", "22:00");
        System.out.println(minutes + " minutes, " + (minutes / 60) + " hours");
    }

    public int calculateTotalMinutes(String startDateTimeString,
            String endDateTimeString, String startTimeString,
            String endTimeString) {
        try {
            List<TimeRange> timeRanges = generateTimeRanges(
                    startDateTimeString, endDateTimeString);
            return calculateTimeRange(timeRanges, startTimeString,
                    endTimeString);
        } catch (ParseException e) {
            e.printStackTrace();
            return 0;
        }
    }

    private List<TimeRange> generateTimeRanges(String startDateTimeString,
            String endDateTimeString) throws ParseException {
        Date startDate = inputDateFormat.parse(startDateTimeString.substring(0,
                10));
        Time startTime = new Time(startDateTimeString.substring(11));
        Date endDate = inputDateFormat
                .parse(endDateTimeString.substring(0, 10));
        Time endTime = new Time(endDateTimeString.substring(11));

        List<TimeRange> timeRanges = new ArrayList<>();

        Date currentDate = new Date(startDate.getTime());
        Time currentTime = new Time(startTime);
        Time eodTime = new Time("24:00");

        while (currentDate.compareTo(endDate) < 0) {
            TimeRange timeRange = new TimeRange(currentDate, currentTime,
                    eodTime);
            timeRanges.add(timeRange);
            currentTime = new Time("00:00");
            currentDate = new Date(currentDate.getTime() + 24L * 60L * 60L
                    * 1000L);
        }

        TimeRange timeRange = new TimeRange(currentDate, currentTime, endTime);
        timeRanges.add(timeRange);

        return timeRanges;
    }

    private int calculateTimeRange(List<TimeRange> timeRanges,
            String startTimeString, String endTimeString) {
        int count = 0;

        Time startTime = new Time(startTimeString);
        Time endTime = new Time(endTimeString);

        for (TimeRange timeRange : timeRanges) {
            Time sodTime = new Time(timeRange.getStartTime());
            Time eodTime = new Time(timeRange.getEndTime());
            Time sTime = startTime.max(sodTime);
            Time eTime = endTime.min(eodTime);

            count += eTime.difference(sTime);
        }

        return count;
    }

    public class TimeRange {

        private final SimpleDateFormat inputDateFormat = new SimpleDateFormat(
                "dd-MM-yyyy");

        private final Date date;

        private final Time startTime;
        private final Time endTime;

        public TimeRange(Date date, Time startTime, Time endTime) {
            this.date = date;
            this.startTime = startTime;
            this.endTime = endTime;
        }

        public Date getDate() {
            return date;
        }

        public Time getStartTime() {
            return startTime;
        }

        public Time getEndTime() {
            return endTime;
        }

        @Override
        public String toString() {
            return inputDateFormat.format(getDate()) + " "
                    + startTime.toString() + " -> " + endTime.toString();
        }

    }

    public class Time {

        private final int minutesPastMidnight;

        public Time(String timeString) {
            int hours = Integer.valueOf(timeString.substring(0, 2));
            int minutes = Integer.valueOf(timeString.substring(3, 5));
            this.minutesPastMidnight = hours * 60 + minutes;
        }

        public Time(Time time) {
            this.minutesPastMidnight = time.getMinutesPastMidnight();
        }

        private int getMinutesPastMidnight() {
            return minutesPastMidnight;
        }

        public int difference(Time time) {
            return this.getMinutesPastMidnight()
                    - time.getMinutesPastMidnight();
        }

        public Time min(Time time) {
            return (difference(time) > 0) ? time : this;
        }

        public Time max(Time time) {
            return (difference(time) > 0) ? this : time;
        }

        @Override
        public String toString() {
            int hours = minutesPastMidnight / 60;
            int minutes = minutesPastMidnight - (hours * 60);
            return String.format("%02d:%02d", hours, minutes);
        }
    }

}
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
  • "Split the date range into multiple date ranges, each spanning no more than one day." and "Calculate the time range within each day date range". That's it! thanks! – 0ne_Up Dec 02 '15 at 06:16
0

If you use java8, you can use LocalDateTime. Then your code could looks like this:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTimeStart = LocalDateTime.parse("2015-10-01 10:00", formatter);
LocalDateTime dateTimeEnd = LocalDateTime.parse("2015-10-02 10:00", formatter);

long seconds = Duration.between(dateTimeStart, dateTimeEnd).getSeconds();

Or LocalTime if you have only time. Then it could looks like this:

LocalTime timeStart = LocalTime.parse("07:00");
LocalTime timeEnd = LocalTime.parse("22:00");

long seconds = Duration.between(timeStart, timeEnd).getSeconds();

If you can't use java8, you can get the number of milliseconds since 1970-01-01 00:00:00 to your date using getTime() method and do simple subtraction operation, like this:

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Date dateStart = simpleDateFormat.parse("2015-10-01 10:00");
Date dateEnd = simpleDateFormat.parse("2015-10-02 10:00");

long milliseconds = dateEnd.getTime() - dateStart.getTime();
long seconds = resultInMillisecond / 1000;
Mateusz Korwel
  • 1,118
  • 1
  • 8
  • 14