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
039     *                 or expression: 2d, 3h, 5w, 2M, 3y
040     *                 or a number of ms: 1234
041     * @throws IllegalArgumentException if the duration can not be parsed
042     * @return a new datetime
043     */
044    public static DateTime plusDuration(DateTime origin, String duration) {
045        if (duration.matches("[a-zA-Z]+")) {
046            return plusDurationAsNoun(origin, duration);
047        }
048        if (duration.matches("[0-9]+")) {
049            return origin.plusMillis(Integer.valueOf(duration));
050        }
051        return plusDurationAsExpression(origin, duration);
052    }
053
054    private static DateTime plusDurationAsExpression(DateTime origin, String duration) {
055        int k = getFactor(duration);
056        switch (duration.substring(duration.length() - 1, duration.length())) {
057            case "s":
058                return origin.plusSeconds(k);
059            case "m":
060                return origin.plusMinutes(k);
061            case "h":
062                return origin.plusHours(k);
063            case "d":
064                return origin.plusDays(k);
065            case "w":
066                return origin.plusWeeks(k);
067            case "M":
068                return origin.plusMonths(k);
069            case "y":
070                return origin.plusYears(k);
071        }
072        return invalid(duration);
073    }
074
075    private static int getFactor(String duration) {
076        try {
077            return Integer.valueOf(duration.substring(0, duration.length() - 1));
078        } catch (NumberFormatException | StringIndexOutOfBoundsException e) {
079            invalid(duration);
080        }
081        return 1;
082    }
083
084    private static DateTime plusDurationAsNoun(DateTime origin, String duration) {
085        switch (duration.toLowerCase()) {
086            case "second":
087                return origin.plusSeconds(1);
088            case "minute":
089                return origin.plusMinutes(1);
090            case "hour":
091                return origin.plusHours(1);
092            case "day":
093                return origin.plusDays(1);
094            case "week":
095                return origin.plusWeeks(1);
096            case "month":
097                return origin.plusMonths(1);
098            case "quarter":
099                return origin.plusMonths(3);
100            case "year":
101                return origin.plusYears(1);
102        }
103        return invalid(duration);
104    }
105
106    private static DateTime invalid(String msg) {
107        throw new IllegalArgumentException("Invalid duration: " + msg);
108    }
109
110}