/**
* 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);
}
}