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

net.named_data.jndn.encrypt.RepetitiveInterval Maven / Gradle / Ivy

/**
 * Copyright (C) 2015-2019 Regents of the University of California.
 * @author: Jeff Thompson 
 * @author: From ndn-group-encrypt src/repetitive-interval https://github.com/named-data/ndn-group-encrypt
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 * A copy of the GNU Lesser General Public License is in the file COPYING.
 */

package net.named_data.jndn.encrypt;

import java.util.Calendar;
import java.util.TimeZone;

/**
 * A RepetitiveInterval is an advanced interval which can repeat and can be used
 * to find a simple Interval that a time point falls in.
 * @note This class is an experimental feature. The API may change.
 */
public class RepetitiveInterval implements Comparable {
  public enum RepeatUnit {
    NONE, DAY, MONTH, YEAR
  }

  /**
   * Get the numeric value associated with the repeatUnit. This is a separate
   * method for portability.
   * @param repeatUnit The RepeatUnit.
   * @return The numeric value for repeatUnit.
   */
  public static final int
  getRepeatUnitNumericType(RepeatUnit repeatUnit)
  {
    if (repeatUnit == RepeatUnit.DAY)
      return 1;
    else if (repeatUnit == RepeatUnit.MONTH)
      return 2;
    else if (repeatUnit == RepeatUnit.YEAR)
      return 3;
    else
      return 0;
  }

  public static class Result {
    public Result(boolean isPositive, Interval interval)
    {
      this.isPositive = isPositive;
      this.interval = interval;
    }

    public boolean isPositive;
    public Interval interval;
  }

  /**
   * Create a default RepetitiveInterval with one day duration, non-repeating.
   */
  public RepetitiveInterval()
  {
    startDate_ = -Double.MAX_VALUE;
    endDate_ = -Double.MAX_VALUE;
    intervalStartHour_ = 0;
    intervalEndHour_ = 24;
    nRepeats_ = 0;
    repeatUnit_ = RepeatUnit.NONE;
  }

  /**
   * Create a RepetitiveInterval with the given values. startDate must be
   * earlier than or same as endDate. intervalStartHour must be less than
   * intervalEndHour.
   * @param startDate The start date as milliseconds since Jan 1, 1970 UTC.
   * @param endDate The end date as milliseconds since Jan 1, 1970 UTC.
   * @param intervalStartHour The start hour in the day, from 0 to 23.
   * @param intervalEndHour The end hour in the day from 1 to 24.
   * @param nRepeats Repeat the interval nRepeats repetitions, every unit, until
   * endDate.
   * @param repeatUnit The unit of the repetition. If this is NONE, then
   * startDate must equal endDate.
   * @throws Error if the above conditions are not met.
   */
  public RepetitiveInterval
    (double startDate, double endDate, int intervalStartHour,
     int intervalEndHour, int nRepeats, RepeatUnit repeatUnit)
  {
    startDate_ = toDateOnlyMilliseconds(startDate);
    endDate_ = toDateOnlyMilliseconds(endDate);
    intervalStartHour_ = intervalStartHour;
    intervalEndHour_ = intervalEndHour;
    nRepeats_ = nRepeats;
    repeatUnit_ = repeatUnit;

    validate();
  }

  /**
   * Create a RepetitiveInterval with the given values, and no repetition.
   * Because there is no repetition, startDate must equal endDate.
   * intervalStartHour must be less than intervalEndHour.
   * @param startDate The start date as milliseconds since Jan 1, 1970 UTC.
   * @param endDate The end date as milliseconds since Jan 1, 1970 UTC.
   * @param intervalStartHour The start hour in the day, from 0 to 23.
   * @param intervalEndHour The end hour in the day from 1 to 24.
   * @throws Error if the above conditions are not met.
   */
  public RepetitiveInterval
    (double startDate, double endDate, int intervalStartHour,
     int intervalEndHour)
  {
    startDate_ = toDateOnlyMilliseconds(startDate);
    endDate_ = toDateOnlyMilliseconds(endDate);
    intervalStartHour_ = intervalStartHour;
    intervalEndHour_ = intervalEndHour;
    nRepeats_ = 0;
    repeatUnit_ = RepeatUnit.NONE;

    validate();
  }

  /**
   * Create a RepetitiveInterval, copying values from the given repetitiveInterval.
   * @param repetitiveInterval The RepetitiveInterval to copy values from.
   */
  public RepetitiveInterval(RepetitiveInterval repetitiveInterval)
  {
    startDate_ = repetitiveInterval.startDate_;
    endDate_ = repetitiveInterval.endDate_;
    intervalStartHour_ = repetitiveInterval.intervalStartHour_;
    intervalEndHour_ = repetitiveInterval.intervalEndHour_;
    nRepeats_ = repetitiveInterval.nRepeats_;
    repeatUnit_ = repetitiveInterval.repeatUnit_;
  }

  private void
  validate()
  {
    if (!(intervalStartHour_ < intervalEndHour_))
      throw new Error("ReptitiveInterval: startHour must be less than endHour");
    if (!(startDate_ <= endDate_))
      throw new Error
        ("ReptitiveInterval: startDate must be earlier than or same as endDate");
    if (!(intervalStartHour_ >= 0))
      throw new Error("ReptitiveInterval: intervalStartHour must be non-negative");
    if (!(intervalEndHour_ >= 1 && intervalEndHour_ <= 24))
      throw new Error("ReptitiveInterval: intervalEndHour must be from 1 to 24");
    if (repeatUnit_ == RepeatUnit.NONE) {
      if (!(startDate_ == endDate_))
        throw new Error
          ("ReptitiveInterval: With RepeatUnit.NONE, startDate must equal endDate");
    }
  }

  /**
   * Get an interval that covers the time point. If there is no interval
   * covering the time point, this returns false for isPositive and returns a
   * negative interval.
   * @param timePoint The time point as milliseconds since Jan 1, 1970 UTC.
   * @return An object with fields (isPositive, interval) where isPositive is
   * true if the returned interval is positive or false if negative, and
   * interval is the Interval covering the time point or a negative interval if
   * not found.
   */
  public final Result
  getInterval(double timePoint)
  {
    boolean isPositive;
    double startTime;
    double endTime;

    if (!hasIntervalOnDate(timePoint)) {
      // There is no interval on the date of timePoint.
      startTime = toDateOnlyMilliseconds(timePoint);
      endTime = toDateOnlyMilliseconds(timePoint) + 24 * MILLISECONDS_IN_HOUR;
      isPositive = false;
    }
    else {
      // There is an interval on the date of timePoint.
      startTime =
        toDateOnlyMilliseconds(timePoint) + intervalStartHour_ * MILLISECONDS_IN_HOUR;
      endTime =
        toDateOnlyMilliseconds(timePoint) + intervalEndHour_ * MILLISECONDS_IN_HOUR;

      // check if in the time duration
      if (timePoint < startTime) {
        endTime = startTime;
        startTime = toDateOnlyMilliseconds(timePoint);
        isPositive = false;
      }
      else if (timePoint > endTime) {
        startTime = endTime;
        endTime = toDateOnlyMilliseconds(timePoint) + MILLISECONDS_IN_DAY;
        isPositive = false;
      }
      else
        isPositive = true;
    }

    return new Result(isPositive, new Interval(startTime, endTime));
  }

  /**
   * Compare this to the other RepetitiveInterval.
   * @param other The other RepetitiveInterval to compare to.
   * @return -1 if this is less than the other, 1 if greater and 0 if equal.
   */
  public final int
  compare(RepetitiveInterval other)
  {
    if (startDate_ < other.startDate_)
      return -1;
    if (startDate_ > other.startDate_)
      return 1;

    if (endDate_ < other.endDate_)
      return -1;
    if (endDate_ > other.endDate_)
      return 1;

    if (intervalStartHour_ < other.intervalStartHour_)
      return -1;
    if (intervalStartHour_ > other.intervalStartHour_)
      return 1;

    if (intervalEndHour_ < other.intervalEndHour_)
      return -1;
    if (intervalEndHour_ > other.intervalEndHour_)
      return 1;

    if (nRepeats_ < other.nRepeats_)
      return -1;
    if (nRepeats_ > other.nRepeats_)
      return 1;

    // Lastly, compare the repeat units.
    // Compare without using Integer.compare so it works in older Java compilers.
    if (getRepeatUnitNumericType(repeatUnit_) <
        getRepeatUnitNumericType(other.repeatUnit_))
      return -1;
    else if (getRepeatUnitNumericType(repeatUnit_) ==
             getRepeatUnitNumericType(other.repeatUnit_))
      return 0;
    else
      return 1;
  }

  public int
  compareTo(Object other) { return compare((RepetitiveInterval)other); }

  // Also include this version for portability.
  public int
  CompareTo(Object other) { return compare((RepetitiveInterval)other); }

  public boolean equals(Object other)
  {
    if (!(other instanceof RepetitiveInterval))
      return false;

    return compare((RepetitiveInterval)other) == 0;
  }

  public int hashCode() 
  {
    long longStartDate = Double.doubleToLongBits(startDate_);
    long longEndDate = Double.doubleToLongBits(endDate_);
    int hash = 3;
    hash = 73 * hash + (int)(longStartDate ^ (longStartDate >>> 32));
    hash = 73 * hash + (int)(longEndDate ^ (longEndDate >>> 32));
    hash = 73 * hash + intervalStartHour_;
    hash = 73 * hash + intervalEndHour_;
    hash = 73 * hash + nRepeats_;
    hash = 73 * hash + getRepeatUnitNumericType(repeatUnit_);
    return hash;
  }

  /**
   * Get the start date.
   * @return The start date as milliseconds since Jan 1, 1970 UTC.
   */
  public final double
  getStartDate() { return startDate_; }

  /**
   * Get the end date.
   * @return The end date as milliseconds since Jan 1, 1970 UTC.
   */
  public final double
  getEndDate() { return endDate_; }

  /**
   * Get the interval start hour.
   * @return The interval start hour.
   */
  public final int
  getIntervalStartHour() { return intervalStartHour_; }

  /**
   * Get the interval end hour.
   * @return The interval end hour.
   */
  public final int
  getIntervalEndHour() { return intervalEndHour_; }

  /**
   * Get the number of repeats.
   * @return The number of repeats.
   */
  public final int
  getNRepeats() { return nRepeats_; }

  /**
   * Get the repeat unit.
   * @return The repeat unit.
   */
  public final RepeatUnit
  getRepeatUnit() { return repeatUnit_; }

  /**
   * Check if the date of the time point is in any interval.
   * @param timePoint The time point as milliseconds since Jan 1, 1970 UTC.
   * @return True if the date of the time point is in any interval.
   */
  private boolean
  hasIntervalOnDate(double timePoint)
  {
    double timePointDateMilliseconds = toDateOnlyMilliseconds(timePoint);

    if (timePointDateMilliseconds < startDate_ ||
        timePointDateMilliseconds > endDate_)
      return false;

    if (repeatUnit_ == RepeatUnit.NONE)
      return true;
    else if (repeatUnit_ == RepeatUnit.DAY) {
      long durationDays = (long)(timePointDateMilliseconds - startDate_) /
                          MILLISECONDS_IN_DAY;
      if (durationDays % nRepeats_ == 0)
        return true;
    }
    else {
      Calendar timePointDate = toCalendar(timePointDateMilliseconds);
      Calendar startDate = toCalendar(startDate_);

      if (repeatUnit_ == RepeatUnit.MONTH &&
               timePointDate.get(Calendar.DAY_OF_MONTH) ==
               startDate.get(Calendar.DAY_OF_MONTH)) {
        int yearDifference =
          timePointDate.get(Calendar.YEAR) - startDate.get(Calendar.YEAR);
        int monthDifference = 12 * yearDifference +
          timePointDate.get(Calendar.MONTH) - startDate.get(Calendar.MONTH);
        if (monthDifference % nRepeats_ == 0)
          return true;
      }
      else if (repeatUnit_ == RepeatUnit.YEAR &&
               timePointDate.get(Calendar.DAY_OF_MONTH) ==
                 startDate.get(Calendar.DAY_OF_MONTH) &&
               timePointDate.get(Calendar.MONTH) ==
                 startDate.get(Calendar.MONTH)) {
        int difference = timePointDate.get(Calendar.YEAR) -
          startDate.get(Calendar.YEAR);
        if (difference % nRepeats_ == 0)
          return true;
      }
    }

    return false;
  }

  /**
   * Return a time point on the beginning of the date (without hours, minutes, etc.)
   * @param timePoint The time point as milliseconds since Jan 1, 1970 UTC.
   * @return A time point as milliseconds since Jan 1, 1970 UTC.
   */
  public static double
  toDateOnlyMilliseconds(double timePoint)
  {
    long result = (long)Math.round(timePoint);
    result -= result % MILLISECONDS_IN_DAY;
    return result;
  }

  /**
   * Return a Calendar for the time point.
   * @param timePoint The time point as milliseconds since Jan 1, 1970 UTC.
   * @return The Calendar.
   */
  private static Calendar
  toCalendar(double timePoint)
  {
    Calendar result = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    result.setTimeInMillis((long)timePoint);
    return result;
  }

  private static final long MILLISECONDS_IN_HOUR = 3600 * 1000;
  private static final long MILLISECONDS_IN_DAY = 24 * 3600 * 1000;
  private final double startDate_; // MillisecondsSince1970 UTC
  private final double endDate_;   // MillisecondsSince1970 UTC
  private final int intervalStartHour_;
  private final int intervalEndHour_;
  private final int nRepeats_;
  private final RepeatUnit repeatUnit_;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy