Open Source Repository

Home /jodd/jodd-3.3.2 | Repository Home



jodd/datetime/JulianDateStamp.java
// Copyright (c) 2003-2012, Jodd Team (jodd.org). All Rights Reserved.

package jodd.datetime;

import jodd.util.HashCode;
import static jodd.util.HashCode.hash;

import java.math.BigDecimal;
import java.io.Serializable;

/**
 * Julian Date stamp, for high precision calculations. Julian date is a real
 * number and it basically consist of two parts: integer and fraction. Integer
 * part carries date information, fraction carries time information.
 *
 <p>
 * The Julian day or Julian day number (JDN) is the (integer) number of days that
 * have elapsed since Monday, January 1, 4713 BC in the proleptic Julian calendar 1.
 * That day is counted as Julian day zero. Thus the multiples of 7 are Mondays.
 * Negative values can also be used.
 *
 <p>
 * The Julian Date (JD) is the number of days (with decimal fraction of the day) that
 * have elapsed since 12 noon Greenwich Mean Time (UT or TT) of that day.
 * Rounding to the nearest integer gives the Julian day number.
 *
 *
 * For calculations that will have time precision of 1e-3 seconds, both
 * fraction and integer part must have enough numerics in it. The problem is
 * that integer part is big and, on the other hand fractional is small, and
 * since final julian date is a sum of this two values, some fraction
 * numerals may be lost. Therefore, for higher precision both
 * fractional and intger part of julian date real number has to be
 * preserved.
 *
 @see TimeUtil
 @see JDateTime
 @see DateTimeStamp
 *
 */
public class JulianDateStamp implements Serializable, Cloneable {

  /**
   * Integer part of the Julian Date (JD).
   */
  protected int integer;

  public int getInteger() {
    return integer;
  }

  /**
   * Fraction part of the Julian Date (JD).
   * Should be always in [0.0, 1.0) range.
   */
  protected double fraction;

  public double getFraction() {
    return fraction;
  }

  /**
   * Returns JDN. Note that JDN is not equal to {@link #integer}. It is calculated by
   * rounding to the nearest integer.
   */
  public int getJulianDayNumber() {
    if (fraction >= 0.5) {
      return integer + 1;
    }
    return integer;
  }


  // ---------------------------------------------------------------- ctors

  /**
   * Default empty constructor.
   */
  public JulianDateStamp() {
  }

  /**
   * Creates JD from a <code>double</code>.
   */
  public JulianDateStamp(double jd) {
    set(jd);
  }

  /**
   * Creates JD from both integer and fractional part using normalization.
   * Normalization occurs when fractional part is out of range. 
   *
   @see #set(int, double)
   *
   @param i      integer part
   @param f      fractional part should be in range [0.0, 1.0)
   */
  public JulianDateStamp(int i, double f) {
    set(i, f);
  }

  /**
   * Creates JD from <code>BigDecimal</code>.
   */
  public JulianDateStamp(BigDecimal bd) {
    double d = bd.doubleValue();
    integer = (intd;
    bd = bd.subtract(new BigDecimal(integer));
    fraction = bd.doubleValue();
  }


  // ---------------------------------------------------------------- conversion
  

  /**
   * Returns <code>double</code> value of JD.
   <b>CAUTION</b>: double values may not be suit for precision math due to
   * loss of precision.
   */
  public double doubleValue() {
    return (double)integer + fraction;
  }

  /**
   * Returns <code>BigDecimal</code> value of JD.
   */
  @SuppressWarnings({"UnpredictableBigDecimalConstructorCall"})
  public BigDecimal toBigDecimal() {
    BigDecimal bd = new BigDecimal(integer);
    return bd.add(new BigDecimal(fraction));
  }

  /**
   * Returns string representation of JD.
   *
   @return julian integer as string
   */
  @Override
  public String toString() {
    String s = Double.toString(fraction);
    int i = s.indexOf('.');
    s = s.substring(i);
    return integer + s;
  }


  // ---------------------------------------------------------------- math

  /**
   * Adds a JD to current instance.
   */
  public JulianDateStamp add(JulianDateStamp jds) {
    int i = this.integer + jds.integer;
    double f = this.fraction + jds.fraction;
    set(i, f);
    return this;
  }

  /**
   * Adds a double to current instance.
   */
  public JulianDateStamp add(double delta) {
    set(this.integer, this.fraction + delta);
    return this;
  }


  /**
   * Subtracts a JD from current instance.
   */
  public JulianDateStamp sub(JulianDateStamp jds) {
    int i = this.integer - jds.integer;
    double f = this.fraction -jds.fraction;
    set(i, f);
    return this;
  }

  /**
   * Subtracts a double from current instance.
   */
  public JulianDateStamp sub(double delta) {
    set(this.integer, this.fraction - delta);
    return this;
  }

  /**
   * Sets integer and fractional part with normalization.
   * Normalization means that if double is out of range,
   * values will be correctly fixed. 
   */
  public void set(int i, double f) {
    integer = i;
    int fi = (intf;
    f -= fi;
    integer += fi;
    if (f < 0) {
      f += 1;
      integer--;
    }
    this.fraction = f;
  }

  public void set(double jd) {
    integer = (int)jd;
    fraction = jd - (double)integer;
  }


  // ---------------------------------------------------------------- between

  /**
   * Calculates the number of days between two dates. Returned value is always positive.
   */
  public int daysBetween(JulianDateStamp otherDate) {
    int difference = daysSpan(otherDate);
    return difference >= ? difference : -difference;
  }

  /**
   * Returns span between two days. Returned value may be positive (when this date
   * is after the provided one) or negative (when comparing to future date).
   */
  public int daysSpan(JulianDateStamp otherDate) {
    int now = getJulianDayNumber();
    int then = otherDate.getJulianDayNumber();
    return now - then;
  }

  // ---------------------------------------------------------------- equals & hashCode

  @Override
  public boolean equals(Object object) {
    if (this == object) {
      return true;
    }
    if (!(object instanceof JulianDateStamp)) {
      return false;
    }
    JulianDateStamp stamp = (JulianDateStampobject;
    return  (stamp.integer == this.integer&&
        (Double.compare(stamp.fraction, this.fraction== 0);
  }

  @Override
  public int hashCode() {
    int result = HashCode.SEED;
    result = hash(result, integer);
    result = hash(result, fraction);
    return result;
  }

  // ---------------------------------------------------------------- clone

  @Override
  protected JulianDateStamp clone() {
    return new JulianDateStamp(this.integer, this.fraction);
  }

  // ---------------------------------------------------------------- conversion

  public JulianDateStamp getReducedJulianDate() {
    return new JulianDateStamp(integer - 2400000, fraction);
  }

  public void setReducedJulianDate(double rjd) {
    set(rjd + 2400000);
  }

  public JulianDateStamp getModifiedJulianDate() {
    return new JulianDateStamp(integer - 2400000, fraction - 0.5);
  }

  public void setModifiedJulianDate(double mjd) {
    set(mjd + 2400000.5);
  }

  public JulianDateStamp getTruncatedJulianDate() {
    return new JulianDateStamp(integer - 2440000, fraction - 0.5);
  }

  public void setTruncatedJulianDate(double tjd) {
    set(tjd + 2440000.5);
  }
}