com.facebook.util.TimeIntervalType.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.util.TimeIntervalType.java

Source

/*
 * Copyright (C) 2012 Facebook, Inc.
 *
 * Licensed 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
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 com.facebook.util;

import org.joda.time.DateTime;
import org.joda.time.DateTimeField;
import org.joda.time.DateTimeFieldType;
import org.joda.time.DateTimeZone;
import org.joda.time.DurationField;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.joda.time.chrono.ISOChronology;
import org.joda.time.field.FieldUtils;

/**
 * Represents a time interval type when specifying a time period. Instances of
 * this class provide means to calculate the start instant of the interval
 * containing a given time instant.
 * 
 * <p>
 * Each interval type computes the time interval assuming that they start 
 * from it's minimum value. For example, MINUTE represents the time interval 
 * starting from the 0th minute in the containing hour. So given a time instant
 * 2011-10-09T13:11:49, and a time interval type of MINUTE and length 3, the
 * start instant of the time interval containing that instant will be
 * 2011-10-09T13:09:00.
 * </p>
 */
public enum TimeIntervalType {
    MILLIS(PeriodType.millis(), DateTimeFieldType.millisOfSecond(), null) {
        @Override
        public Period toPeriod(int length) {
            return Period.millis(length);
        }
    },
    SECOND(PeriodType.seconds(), DateTimeFieldType.secondOfMinute(), MILLIS) {
        @Override
        public Period toPeriod(int length) {
            return Period.seconds(length);
        }
    },
    MINUTE(PeriodType.minutes(), DateTimeFieldType.minuteOfHour(), SECOND) {
        @Override
        public Period toPeriod(int length) {
            return Period.minutes(length);
        }
    },
    HOUR(PeriodType.hours(), DateTimeFieldType.hourOfDay(), MINUTE) {
        @Override
        public Period toPeriod(int length) {
            return Period.hours(length);
        }
    },
    DAY(PeriodType.days(), DateTimeFieldType.dayOfMonth(), HOUR) {
        @Override
        public Period toPeriod(int length) {
            return Period.days(length);
        }
    },
    /**
     * Week interval is currently non-intuitive. It assumes that the weeks
     * start on the same day as the first day of the year. Don't use weeks
     * as a time interval type, until we can have the weeks starting on the
     * correct day (Sunday/Monday) per the locale.
     */
    WEEK(PeriodType.weeks(), DateTimeFieldType.weekOfWeekyear(), DAY) {
        @Override
        public Period toPeriod(int length) {
            return Period.weeks(length);
        }
    },
    MONTH(PeriodType.months(), DateTimeFieldType.monthOfYear(), DAY) {
        @Override
        public Period toPeriod(int length) {
            return Period.months(length);
        }
    },
    YEAR(PeriodType.years(), DateTimeFieldType.yearOfCentury(), MONTH) {
        @Override
        public Period toPeriod(int length) {
            return Period.years(length);
        }
    };

    private final PeriodType periodType;
    private final DateTimeFieldType fieldType;
    private final TimeIntervalType subType;

    /**
     * Creates an instance.
     * 
     * @param type The field type corresponding to this interval type.
     * @param subType The subtype for this type.
     */
    private TimeIntervalType(PeriodType periodType, DateTimeFieldType type, TimeIntervalType subType) {
        this.periodType = periodType;
        this.fieldType = type;
        this.subType = subType;
    }

    /**
     * Returns a period representing this interval type.
     * 
     * @param length the multiple of the base period unit
     * @return the period value
     */
    public abstract Period toPeriod(int length);

    /**
     * Validates that the specified interval value is valid for this 
     * interval type in the supplied time zone.
     * 
     * @param timeZone the time zone
     * @param intervalLength the interval length
     */
    public void validateValue(DateTimeZone timeZone, long intervalLength) {
        final DateTimeField field = fieldType.getField(TimeUtil.getChronology(timeZone.getID()));
        if (intervalLength < 1 || intervalLength > field.getMaximumValue()) {
            throw new IllegalArgumentException(
                    "Supplied value " + intervalLength + " is out of bounds for " + name());
        }
    }

    /**
     * Gets the start instant given the event instant, interval length 
     * and the time zone for this interval type.
     * 
     * @param instant the event time instant.
     * @param length the interval length
     * 
     * @return the start instant of the interval of given length that contains 
     * the supplied time instant in the supplied time zone 
     */
    public DateTime getTimeIntervalStart(DateTime instant, long length) {
        validateValue(instant.getZone(), length);
        // Get the time in the specified timezone
        DateTime periodStart = instant;
        // Clear all the fields for this intervalType and its subtypes
        TimeIntervalType timeIntervalType = this;
        while (timeIntervalType != null) {
            periodStart = timeIntervalType.clearField(periodStart);
            timeIntervalType = timeIntervalType.subType;
        }
        // figure out the which time interval does the instant lie in
        Period period = new Period(periodStart, instant, periodType);
        DurationField durationField = fieldType.getField(instant.getChronology()).getDurationField();
        int diff = period.get(durationField.getType());
        long startDelta = (diff / length) * length;
        return periodStart.withFieldAdded(durationField.getType(), FieldUtils.safeToInt(startDelta));
    }

    /**
     * Returns the number of milliseconds per unit of this interval type.
     * 
     * @return the number of milliseconds per unit of this interval type.
     */
    public long toDurationMillis() {
        return fieldType.getDurationType().getField(
                // Assume that durations are always in UTC
                ISOChronology.getInstance(DateTimeZone.UTC)).getUnitMillis();
    }

    protected DateTime clearField(DateTime value) {
        return value.withField(fieldType, fieldType.getField(value.getChronology()).getMinimumValue());
    }
}