001/*
002 * (C) Copyright 2016 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     bdelbosc
018 */
019package org.nuxeo.elasticsearch.aggregate;
020
021import org.joda.time.DateTime;
022
023/**
024 * Helper to add duration to a date with the same format as ES Date histogram interval
025 *
026 * @since 8.4
027 */
028public final class DateHelper {
029
030    private DateHelper() {
031
032    }
033
034    /**
035     * Returns a new datetime plus the specified duration.
036     *
037     * @param origin the initial datetime
038     * @param duration can be expressed with a noun: hour, day, month, quarter, year or expression: 2d, 3h, 5w, 2M, 3y
039     *            or a number of ms: 1234
040     * @throws IllegalArgumentException if the duration cannot be parsed
041     * @return a new datetime
042     */
043    public static DateTime plusDuration(DateTime origin, String duration) {
044        if (duration.matches("[a-zA-Z]+")) {
045            return plusDurationAsNoun(origin, duration);
046        }
047        if (duration.matches("[0-9]+")) {
048            return origin.plusMillis(Integer.valueOf(duration));
049        }
050        return plusDurationAsExpression(origin, duration);
051    }
052
053    private static DateTime plusDurationAsExpression(DateTime origin, String duration) {
054        int k = getFactor(duration);
055        switch (duration.substring(duration.length() - 1, duration.length())) {
056        case "s":
057            return origin.plusSeconds(k);
058        case "m":
059            return origin.plusMinutes(k);
060        case "h":
061            return origin.plusHours(k);
062        case "d":
063            return origin.plusDays(k);
064        case "w":
065            return origin.plusWeeks(k);
066        case "M":
067            return origin.plusMonths(k);
068        case "y":
069            return origin.plusYears(k);
070        }
071        return invalid(duration);
072    }
073
074    private static int getFactor(String duration) {
075        try {
076            return Integer.valueOf(duration.substring(0, duration.length() - 1));
077        } catch (NumberFormatException | StringIndexOutOfBoundsException e) {
078            invalid(duration);
079        }
080        return 1;
081    }
082
083    private static DateTime plusDurationAsNoun(DateTime origin, String duration) {
084        switch (duration.toLowerCase()) {
085        case "second":
086            return origin.plusSeconds(1);
087        case "minute":
088            return origin.plusMinutes(1);
089        case "hour":
090            return origin.plusHours(1);
091        case "day":
092            return origin.plusDays(1);
093        case "week":
094            return origin.plusWeeks(1);
095        case "month":
096            return origin.plusMonths(1);
097        case "quarter":
098            return origin.plusMonths(3);
099        case "year":
100            return origin.plusYears(1);
101        }
102        return invalid(duration);
103    }
104
105    private static DateTime invalid(String msg) {
106        throw new IllegalArgumentException("Invalid duration: " + msg);
107    }
108
109}