/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the License at the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package org.apereo.portal.events.aggr; import org.joda.time.Chronology; import org.joda.time.DateTime; import org.joda.time.DateTimeFieldType; import org.joda.time.DateTimeUtils; import org.joda.time.DurationFieldType; import org.joda.time.ReadableInstant; /** * Enumeration of all time intervals the event aggregation can handle. All of the example ranges are * inclusive on both ends * */ public enum AggregationInterval { /** * 1 Minute * * @see DateTimeFieldType#minuteOfHour() */ MINUTE(DateTimeFieldType.minuteOfHour(), true), /** 5 Minutes (0-4,5-9,...,55-59) */ FIVE_MINUTE(null, true), /** * 1 Hour * * @see DateTimeFieldType#hourOfDay() */ HOUR(DateTimeFieldType.hourOfDay(), true), /** * 1 Day * * @see DateTimeFieldType#dayOfMonth() */ DAY(DateTimeFieldType.dayOfMonth(), false), /** * 1 Week * * @see DateTimeFieldType#weekOfWeekyear() */ WEEK(DateTimeFieldType.weekOfWeekyear(), false), /** * 1 Calendar month * * @see DateTimeFieldType#monthOfYear() */ MONTH(DateTimeFieldType.monthOfYear(), false), /** * As defined by the deployer, divides the calendar into 4 sections. Default configuration is: 3 * Calendar months (Jan 1 - Mar 31, Apr 1 - Jun 30, Jul 1 - Sep 30, Oct 1 - Dec 31) */ CALENDAR_QUARTER(null, false), /** As defined by the deployer, unusable unless term boundaries have been configured. */ ACADEMIC_TERM(null, false), /** * 1 Year * * @see DateTimeFieldType#year() */ YEAR(DateTimeFieldType.year(), false); private final DateTimeFieldType dateTimeFieldType; private final boolean hasTimePart; /** @param dateTimeFieldType */ private AggregationInterval(DateTimeFieldType dateTimeFieldType, boolean hasTimePart) { this.dateTimeFieldType = dateTimeFieldType; this.hasTimePart = hasTimePart; } /** @return true if the interval has a time part, false if the interval is date only */ public boolean isHasTimePart() { return hasTimePart; } /** * @return the {@link DateTimeFieldType} for the {@link AggregationInterval}, null if there is * no mapping */ public DateTimeFieldType getDateTimeFieldType() { return this.dateTimeFieldType; } /** * @return If the {@link #determineEnd(DateTime)} and {@link #determineStart(DateTime)} methods * work on this interval */ public boolean isSupportsDetermination() { return this.dateTimeFieldType != null || this == FIVE_MINUTE; } /** * Determine the number of intervals between the start and end dates * * @param start Start, inclusive * @param end End, exclusive * @return Number of intervals between start and end */ public int determineIntervalsBetween(ReadableInstant start, ReadableInstant end) { if (!this.isSupportsDetermination()) { throw new IllegalArgumentException( "Cannot compute intervals between for " + this + " please use " + AggregationIntervalHelper.class); } final DateTimeFieldType dtft; final double ratio; switch (this) { case FIVE_MINUTE: { dtft = MINUTE.getDateTimeFieldType(); ratio = 5; break; } default: { dtft = dateTimeFieldType; ratio = 1; } } final DurationFieldType durationType = dtft.getDurationType(); final Chronology chrono = DateTimeUtils.getInstantChronology(start); return (int) Math.round( durationType .getField(chrono) .getDifference(end.getMillis(), start.getMillis()) / ratio); } /** * Determine the starting DateTime (inclusive) of an interval based on an instant in time * * @param instant The instant in time to get the interval starting value for * @return The start of this interval in relation to the provided instant */ public DateTime determineStart(DateTime instant) { if (this.dateTimeFieldType != null) { return instant.property(this.dateTimeFieldType).roundFloorCopy(); } if (this == AggregationInterval.FIVE_MINUTE) { return instant.hourOfDay() .roundFloorCopy() .plusMinutes((instant.getMinuteOfHour() / 5) * 5); } throw new IllegalArgumentException( "Cannot compute interval start time for " + this + " please use " + AggregationIntervalHelper.class); } /** * Determine the ending DateTime (exclusive) of an interval based on an instant in time * * @param instant The start of an instant * @return */ public DateTime determineEnd(DateTime instant) { if (this.dateTimeFieldType != null) { final DateTime start = instant.property(this.dateTimeFieldType).roundFloorCopy(); return start.property(this.dateTimeFieldType).addToCopy(1); } if (this == AggregationInterval.FIVE_MINUTE) { final DateTime start = instant.hourOfDay() .roundFloorCopy() .plusMinutes((instant.getMinuteOfHour() / 5) * 5); return start.plusMinutes(5); } throw new IllegalArgumentException( "Cannot compute interval end time for " + this + " please use " + AggregationIntervalHelper.class); } }