meteo-core/src/main/java/no/api/meteo/service/locationforecast/extras/MeteoForecastIndexer.java
Optional<PeriodForecast> getBestFitPeriodForecast(ZonedDateTime from, ZonedDateTime to) {
        if (from == null || to == null) {
            return Optional.empty();
        }

        // Making sure that we remove minutes, seconds and milliseconds from the request timestamps
        ZonedDateTime requestFrom = toZeroMSN(from);
        ZonedDateTime requestTo = toZeroMSN(to);

        //  Get list of period forecasts for the requested day. Return empty if date isn't present
        List<PeriodForecast> forecastsList = dayIndex.get(new DayIndexKey(requestFrom));
        if (forecastsList == null) {
            return Optional.empty();
        }

        PeriodForecast chosenForecast = null;
        long score = 0;
        long tmpScore = 0;

        for (PeriodForecast forecast : forecastsList) {
            ZonedDateTime actualFrom = cloneZonedDateTime(forecast.getFrom());

            ZonedDateTime actualTo = cloneZonedDateTime(forecast.getTo());

            if (requestFrom.equals(actualFrom) && requestTo.equals(actualTo)) {
                return Optional.of(forecast);
            } else if (
                    (requestFrom.isBefore(actualFrom) && requestTo.isBefore(actualFrom)) ||
                            (requestFrom.isAfter(actualTo) && requestTo.isAfter(actualTo)) ||
                            actualTo.isEqual(actualFrom)) {
                continue; // this period is outside the requested period or this is a point forecast.
            } else if (requestFrom.isBefore(actualFrom) && requestTo.isBefore(actualTo)) {
                tmpScore = hoursBetween(requestTo, actualFrom);
            } else if ((actualFrom.isBefore(requestFrom) || actualFrom.isEqual(requestFrom)) &&
                    actualTo.isBefore(requestTo)) {
                tmpScore = hoursBetween(actualTo, requestFrom);
            } else if (actualFrom.isAfter(requestFrom) &&
                    (actualTo.isBefore(requestTo) || actualTo.isEqual(requestTo))) {
                tmpScore = hoursBetween(actualTo, actualFrom);
            } else if (actualFrom.isBefore(requestFrom) && actualTo.isAfter(requestTo)) {
                tmpScore = hoursBetween(requestTo, requestFrom);
            } else {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd:HH:mm");
                log.warn("Unhandled forecast Requested period:" + requestFrom.format(formatter) + "--" +
                                 requestTo.format(formatter) + ", Actual period: " +
                                 actualFrom.format(formatter) + "--" + actualTo.format(formatter));
            }

            tmpScore = Math.abs(tmpScore);

            if ((score == 0 && tmpScore > 0) || tmpScore > score) {
                score = tmpScore;
                chosenForecast = forecast;
            }
        }

        return Optional.ofNullable(chosenForecast);
    }
Optional<PeriodForecast> getBestFitPeriodForecast(ZonedDateTime from, ZonedDateTime to) {
        if (from == null || to == null) {
            return Optional.empty();
        }

        // Making sure that we remove minutes, seconds and milliseconds from the request timestamps
        ZonedDateTime requestFrom = toZeroMSN(from);
        ZonedDateTime requestTo = toZeroMSN(to);

        //  Get list of period forecasts for the requested day. Return empty if date isn't present
        List<PeriodForecast> forecastsList = dayIndex.get(new DayIndexKey(requestFrom));
        if (forecastsList == null) {
            return Optional.empty();
        }

        PeriodForecast chosenForecast = null;
        long score = 0;
        long tmpScore = 0;

        for (PeriodForecast forecast : forecastsList) {
            ZonedDateTime actualFrom = cloneZonedDateTime(forecast.getFrom());

            ZonedDateTime actualTo = cloneZonedDateTime(forecast.getTo());

            if (requestFrom.equals(actualFrom) && requestTo.equals(actualTo)) {
                return Optional.of(forecast);
            } else if (
                    (requestFrom.isBefore(actualFrom) && requestTo.isBefore(actualFrom)) ||
                            (requestFrom.isAfter(actualTo) && requestTo.isAfter(actualTo)) ||
                            actualTo.isEqual(actualFrom)) {
                continue; // this period is outside the requested period or this is a point forecast.
            } else if (requestFrom.isBefore(actualFrom) && requestTo.isBefore(actualTo)) {
                tmpScore = hoursBetween(requestTo, actualFrom);
            } else if ((actualFrom.isBefore(requestFrom) || actualFrom.isEqual(requestFrom)) &&
                    actualTo.isBefore(requestTo)) {
                tmpScore = hoursBetween(actualTo, requestFrom);
            } else if (actualFrom.isAfter(requestFrom) &&
                    (actualTo.isBefore(requestTo) || actualTo.isEqual(requestTo))) {
                tmpScore = hoursBetween(actualTo, actualFrom);
            } else if (actualFrom.isBefore(requestFrom) && actualTo.isAfter(requestTo)) {
                tmpScore = hoursBetween(requestTo, requestFrom);
            } else {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd:HH:mm");
                log.warn("Unhandled forecast Requested period:" + requestFrom.format(formatter) + "--" +
                                 requestTo.format(formatter) + ", Actual period: " +
                                 actualFrom.format(formatter) + "--" + actualTo.format(formatter));
            }

            tmpScore = Math.abs(tmpScore);

            if ((score == 0 && tmpScore > 0) || tmpScore > score) {
                score = tmpScore;
                chosenForecast = forecast;
            }
        }

        return Optional.ofNullable(chosenForecast);
    }
Find the period forecast that has the best fitted forecast for a given period.

This means a forecast covering the requested period, with to and from time closest possible to that period. If
this function only can find a period forecast that covers parts of the requested period, then the forecast
covering the most will be used.