All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rbmhtechnology.vind.api.query.datemath.DateMathParser Maven / Gradle / Ivy

There is a newer version: 3.2.0
Show newest version
package com.rbmhtechnology.vind.api.query.datemath;

import com.rbmhtechnology.vind.SearchServerException;
import org.apache.commons.lang3.math.NumberUtils;

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
import java.util.regex.Pattern;

public class DateMathParser {
    public static final TimeZone UTC = TimeZone.getTimeZone("UTC");
    public static final TimeZone DEFAULT_MATH_TZ;
    public static final DateTimeFormatter PARSER;
    public static final DateTimeFormatter STRING_DATE_PARSER;
    public static final Map CALENDAR_UNITS;
    private TimeZone zone;
    private Locale loc;
    private Date now;
    private static Pattern splitter;
    private DateValidator dateValidator =
            new DateValidator(Arrays.asList(
                    DateTimeFormatter.BASIC_ISO_DATE,
                    DateTimeFormatter.ISO_LOCAL_DATE,
                    DateTimeFormatter.ofPattern("dd/MM/yyyy"),
                    DateTimeFormatter.ofPattern("dd/MM/yy"),
                    DateTimeFormatter.ofPattern("dd.MM.yyyy"),
                    DateTimeFormatter.ofPattern("dd.MM.yy"),
                    DateTimeFormatter.ofPattern("dd-MM-yyyy"),
                    DateTimeFormatter.ofPattern("dd-MM-yy")
                    ));

    private static Map makeUnitsMap() {
        Map units = new HashMap(13);
        units.put("YEAR", ChronoUnit.YEARS);
        units.put("YEARS", ChronoUnit.YEARS);
        units.put("MONTH", ChronoUnit.MONTHS);
        units.put("MONTHS", ChronoUnit.MONTHS);
        units.put("DAY", ChronoUnit.DAYS);
        units.put("DAYS", ChronoUnit.DAYS);
        units.put("DATE", ChronoUnit.DAYS);
        units.put("HOUR", ChronoUnit.HOURS);
        units.put("HOURS", ChronoUnit.HOURS);
        units.put("MINUTE", ChronoUnit.MINUTES);
        units.put("MINUTES", ChronoUnit.MINUTES);
        units.put("SECOND", ChronoUnit.SECONDS);
        units.put("SECONDS", ChronoUnit.SECONDS);
        units.put("MILLI", ChronoUnit.MILLIS);
        units.put("MILLIS", ChronoUnit.MILLIS);
        units.put("MILLISECOND", ChronoUnit.MILLIS);
        units.put("MILLISECONDS", ChronoUnit.MILLIS);
        return units;
    }

    private static DateMathExpression add(DateMathExpression expression, int val, String unit) {
        ChronoUnit uu = (ChronoUnit)CALENDAR_UNITS.get(unit);
        if (null == uu) {
            throw new IllegalArgumentException("Adding Unit not recognized: " + unit);
        } else {
            expression.add(val, DateMathExpression.TimeUnit.valueOf(unit));
            return expression;
        }
    }
    private static DateMathExpression sub(DateMathExpression expression, int val, String unit) {
        ChronoUnit uu = (ChronoUnit)CALENDAR_UNITS.get(unit);
        if (null == uu) {
            throw new IllegalArgumentException("Adding Unit not recognized: " + unit);
        } else {
            expression.sub(val, DateMathExpression.TimeUnit.valueOf(unit));
            return expression;
        }
    }

    private static DateMathExpression round(DateMathExpression expression, String unit) {
        ChronoUnit uu = (ChronoUnit)CALENDAR_UNITS.get(unit);
        if (null == uu) {
            throw new SearchServerException("Rounding Unit not recognized: " + unit);
        } else {
            expression.setUnit(DateMathExpression.TimeUnit.valueOf(unit));
            return expression;
        }
    }

    private static ZonedDateTime parseNoMath(String val) {
       try {
           final Instant instant = PARSER.parse(val, Instant::from);
           return  ZonedDateTime.ofInstant(instant, ZoneId.of(UTC.getID()));
       } catch (Exception e) {
           final LocalDate date = LocalDate.parse(val, STRING_DATE_PARSER);
           return date.atStartOfDay(ZoneOffset.UTC);
       }

    }

    public TimeZone getTimeZone() {
        return Optional.ofNullable(this.zone).orElse(UTC);
    }

    public void setNow(Date n) {
        this.now = n;
    }

    public Date getNow() {
        if (this.now == null) {
            this.now = new Date();
        }
        return (Date)this.now.clone();
    }

    public DateMathExpression parseMath(String math) {
        if (0 == math.length()) {
            return new DateMathExpression();
        } else {
            String[] ops = splitter.split(math);
            int pos = 0;

            DateMathExpression expression = new DateMathExpression();
            if (ops[0].length() > 1 ) {
                if (!ops[0].equals("NOW") ) {
                    final String possibleDate = ops[0] + ops[1] + ops[2] + ops[3] + ops[4];
                    if(dateValidator.isValid(possibleDate)){
                        expression = new DateMathExpression(dateValidator.parseDate(possibleDate));
                        pos = 4;
                    } else {
                        expression = new DateMathExpression(parseNoMath(ops[0]));

                    }
                }
                pos++;
                if (pos0) || !(day<32)) {
                    return false;
                }
            } else {
                return false;
            }

            if(NumberUtils.isDigits(ops[pos+2])) {
                final Number day = NumberUtils.createNumber(ops[pos+2]);
                if (!(day.intValue()>0) || !(day.intValue()<13)) {
                    return false;
                }
            } else {
                return false;
            }

            if(!NumberUtils.isDigits(ops[pos+2])) {
                return false;
            }
            return true;
        }
        return false;
    }
    static public class DateValidator {
        private List dateFormatters;

        public DateValidator( List dateFormatters) {
            this.dateFormatters = dateFormatters;
        }

        public DateValidator addDateFormater(DateTimeFormatter dateFormatter) {
            this.dateFormatters.add(dateFormatter);
            return this;
        }

        public boolean isValid(String dateStr) {
            return this.dateFormatters.stream()
                    .anyMatch( formatter -> {
                        try {
                            LocalDate.parse(dateStr, formatter);
                            return true;
                        } catch (DateTimeParseException e) {
                            return false;
                        }
                    }
                    );
        }
        public ZonedDateTime parseDate(String dateStr) {
            if(isValid(dateStr)){
               return this.dateFormatters.stream()
                        .filter(formatter -> {
                            try {
                                LocalDate.parse(dateStr, formatter);
                                return true;
                            } catch (DateTimeParseException e) {
                                return false;
                            }
                        })
                        .map(formatter ->
                                LocalDate.parse(dateStr, formatter)
                                        .atStartOfDay(ZoneId.of("UTC")))
                       .findFirst().orElseThrow(() -> new SearchServerException("Error parsing date "+dateStr+": Date format not supported"));
            }
            throw new SearchServerException("Error parsing date "+dateStr+": Date format not supported");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy