AWRA banner
Advancing Water Resources Research and Management

Symposium on Water Resources and the World Wide Web
Seattle, Washington, December 5-9, 1999
import java.util.*;

/* Adapted by Bill Moninger from ...
 * Gary Cornell and Cay S. Horstmann, Core Java (Book/CD-ROM)
 * Published By SunSoft Press/Prentice-Hall
 * Copyright (C) 1996 Sun Microsystems Inc.
 * All Rights Reserved. ISBN 0-13-565755-5
 */

/**
 * Store dates and perform date arithmetic
 * (another Date class, but more useful that
 * java.util.Date)
 * @version 1.1, 18-May-99
 * @author Bill Moninger
 *
 * revision history
 * 17-May-99 - shortString made Y2K compliant (previous version returned
 *             year = 100 in year 2000, now returns year = 0.
 * earlier   - added a constructor to get the Date from a day-of-year
 *             (in range 1-366)
 *           - added public variables MIN and MAX.
 */


public class UTCDate implements Cloneable
{  /**
    *  Constructs today's date
    */

   private static int JULIAN_1970 = 2440588; //Julian day of 1/1/1970
   private static int JGREG = 2299161; //Julian day of adoption of Gregorian cal.
   private static String[] month_name =
      {"Jan","Feb","Mar","Apr","May","Jun",
       "Jul","Aug","Sep","Oct","Nov","Dec"};
   private static int[][] daytab = {
     {0,31,28,31,30,31,30,31,31,30,31,30,31},
     {0,31,29,31,30,31,30,31,31,30,31,30,31}
   };
   public static UTCDate MIN = new UTCDate(0,1,1);
   public static UTCDate MAX = new UTCDate(2222,1,1);

   private int sec_of_day;  //0 - 86399
   private int julian_day; //2440000 = May 23, 1968

   /**
    * test interface
    */
   public static void main(String args[]) {
        UTCDate d = new UTCDate();
        System.out.println("todays date is "+d);
        UTCDate d1 = new UTCDate(900950400);
        boolean before = d.isBefore(d1);
        System.out.println(""+d+" is before "+d1+"? "+before);

        System.out.println("julian day is "+d.getJulian());
     for(int i=0;i<12;i++) {
         d.addMonths(-1);
        System.out.println("1 month earlier is "+d);
         int j=0;
        while (j < 1.e7) {  //this adds about 1.8 seconds on my 166 MHz pc.
            j++;
        }
     }
     /* //loop forever so the dos window doesn't disappear until I hit ^c
     while(true) {
        int k = 1;
     }*/
   }

   /**
    * Constructs the current date (uses java.util.Date class)
    */
   public UTCDate() {
     java.util.Date today = new java.util.Date();
   int ymdhms[] = new int[6];
      ymdhms[0] = today.getYear() + 1900;
      ymdhms[1] = today.getMonth() + 1;
      ymdhms[2] = today.getDate();  //day of month
      ymdhms[3]= today.getHours();
      ymdhms[4]= today.getMinutes();
      ymdhms[5]= today.getSeconds();
      setSecsDays(ymdhms);
      //convert to UTC
      int offset = today.getTimezoneOffset();
      //System.out.println("offset is "+offset);
      addMinutes(offset);
   }

   /**
    * Constructs a specific date
    * @param yyyy year (full year, e.g., 1996,
    * not starting from 1900)
    * @param m month
    * @param d day
    * @exception IllegalArgumentException if yyyy m d not a
    * valid date
    */
   public UTCDate(int yyyy, int m, int d)
   {
    this(yyyy,m,d,0,0,0);
   }

   /**
    * Constructs a specific date
    * @param yyyy year (full year, e.g., 1996,
    * not starting from 1900)
    * @param y_day (1-366) day of year
    * @param h hour
    * @param m minute
    * @param s second
    */
   public UTCDate(int yyyy,int y_day,int hour, int min, int sec) {
     int i,leap, month,mday;
     // get month and day from julian day
     //see p 111 of Kernighan and Richie, 2nd ed.
     if( (yyyy%4 == 0 && yyyy%100 != 0) || yyyy%400 == 0) {
       leap=1;
     } else {
       leap=0;
     }
     for(i=1;y_day>daytab[leap][i];i++) {
       y_day -= daytab[leap][i];
     }
     month = i;
     mday = y_day;  //julday has been decremented to just be day of the month
     int ymdhms[] = new int[6];
     ymdhms[0] = yyyy;
     ymdhms[1] = month;
     ymdhms[2] = mday;
     ymdhms[3]=hour;
     ymdhms[4]=min;
     ymdhms[5]=sec;
     setSecsDays(ymdhms);
   }

   /**
    * Constructs a specific date
    * @param yyyy year (full year, e.g., 1996,
    * not starting from 1900)
    * @param m month (1 -12)
    * @param d day
    * @param h hour
    * @param m minute
    * @param s second
    */
   public UTCDate(int yyyy, int m, int d, int h, int min, int s) {
    int ymdhms[] = new int[6];
      ymdhms[0] = yyyy;
      ymdhms[1] = m;
      ymdhms[2] = d;
      ymdhms[3]=h;
      ymdhms[4]=min;
      ymdhms[5]=s;
      setSecsDays(ymdhms);
   }

   public UTCDate(int yyyy, String m_name, int d, int h, int min, int s) {
    int m = get_month_num(m_name);
      int ymdhms[] = new int[6];
      ymdhms[0] = yyyy;
      ymdhms[1] = m;
      ymdhms[2] = d;
      ymdhms[3]=h;
      ymdhms[4]=min;
      ymdhms[5]=s;
      setSecsDays(ymdhms);
  }

   /**
    * Construsts a specific date
    * @param cal_secs seconds since 1/1/1970
    */
   public UTCDate(int cal_secs) {
    //get number of days since 1/1/1970
    int days_since_1970 = cal_secs/86400;
    julian_day = JULIAN_1970 + days_since_1970;
    sec_of_day = cal_secs - days_since_1970 * 86400;
   }

   public static String leadingZero(int val) {
        String result = ""+val;
        if(val < 10) {
            result = "0"+val;
        }
        return result;
   }

   public static int get_month_num(String m_name) {
     int i=0;
     for(;i<month_name.length;i++) {
        if(month_name[i].equalsIgnoreCase(m_name)) {
            break;
        }
     }
     return i+1;
   }


   /**
    * Advances this day by m minutes. For example.
    * d.addMinutes(3) adds three minutes to d
    * @param m the number of minutes by which to change this
    * day (can be < 0)
    */
   public void addMinutes(int m) {
     if(m == 0) {
         return;
     }
     sec_of_day += m*60;
     while(sec_of_day > 86399) {
        sec_of_day -= 86400;
        julian_day++;
     }
     while(sec_of_day < 0) {
        sec_of_day += 86400;
        julian_day--;
     }
   }

  /**
    * Advances this day by h hours. For example.
    * d.addHours(3) adds three hours to d
    * @param h the number of hours by which to change this
    * day (can be < 0)
    */
   public void addHours(int h) {
     if(h == 0) {
         return;
     }
     sec_of_day += h*3600;
     while(sec_of_day > 86399) {
        sec_of_day -= 86400;
        julian_day++;
     }
     while(sec_of_day < 0) {
        sec_of_day += 86400;
        julian_day--;
     }
   }

   /**
    * Advances this day by n days. For example.
    * d.addDays(30) adds thirty days to d
    * @param n the number of days by which to change this
    * day (can be < 0)
    */
   public void addDays(int n) {
    if(n == 0) {
        return;
    }
    julian_day += n;
   }

   /**
    * Advances this day by n months. For example.
    * d.addMonths(3) adds three months to d
    * @param m the number of months by which to change this
    * day (can be < 0)
    */
   public void addMonths(int m) {
    if(m == 0) {
      return;
    }
    int[] ymd = fromJulian();
    int year=ymd[0];
    int month=ymd[1];
    int day=ymd[2];
      int years_to_add = m/12;
      int months_to_add = m - 12*years_to_add;
      year += years_to_add;
      month += months_to_add;
      if(month > 12) {
        month -= 12;
        year++;
      } else if (month < 1) {
        month += 12;
        year--;
      }
      ymd[0]=year;
      ymd[1]=month;
      ymd[2]=day;
      setJulian(ymd);
    }

  public boolean equals(UTCDate other) {
    return sec_of_day == other.sec_of_day &&
           julian_day == other.julian_day;
  }

  /**
    * @return the hour of the day (0 - 23)
    */
  public int getHour() {
    return sec_of_day/3600;
  }

  /**
    * @return the minute of the hour (0 - 59)
    */
  public int getMinute() {
    return (sec_of_day - getHour()*3600)/60;
  }

  /**
    * @return the second of the minute (0 -59)
    */
  public int getSecond() {
    return sec_of_day - 60*getMinute() - 3600*getHour();
  }

  /**
    * Gets the day of the month
    * @return the day of the month (1...31)
    */
  public int getDay() {
    int[] r = fromJulian();
      return r[2];
   }

  /**
   * Gets the Julian day
   * @return the Julian day (2440588 is 1-Jan-1970)
   */
   public int getJulian() {
    return julian_day;
   }

   /**
    * Gets the month
    * @return the month (1...12)
    */
  public int getMonth() {
    int[] r = fromJulian();
    return r[1];
    }

  /**
    * Gets the month name
    * @return the month ("Jan"..."Dec")
    */
  public String getMonthName() {
    int[] r = fromJulian();
    return month_name[r[1]-1];
    }

   /**
    * @return the second in the day (0 - 86399)
    */
   public int getSecs() {
    return sec_of_day;
   }

   /**
    * Gets the year
    * @return the year (counting from 0, not from 1900)
    */
  public int getYear() {
    int[] r = fromJulian();
    return r[0];
   }

   /**
    * Gets the weekday
    * @return the weekday (0 = Sunday, 1 = Monday, ...,
    * 6 = Saturday)
    */
    public int weekday() { return (julian_day + 1)% 7; }

   /**
    * @return the seconds since 1/1/1970
    */
   public int get1970Secs() {
     return (julian_day - JULIAN_1970) * 86400 + sec_of_day;
   }
     
   /**
    * The number of days between this and day parameter
    * @param b any date
    * @return the number of days between this and day parameter
    * and b (> 0 if this day comes after b)
    */
   public int daysBetween(UTCDate b)
   {  return julian_day - b.julian_day;
   }

   /**
    * The number of seconds between this and b (+ if this is LATER)
    * @param b any date
    * @return the number of days between this and day parameter
    * and b (> 0 if this day comes after b)
    */
   public int secsAfter(UTCDate b) {
    int secs_between_days = daysBetween(b) * 86400;
    return secs_between_days + this.sec_of_day - b.sec_of_day;
   }

   /**
    * @param u any UTCDate
    * @return true iff 'this' is before u
    */
   public boolean isBefore(UTCDate u) {
    boolean before=false;
    int day_dif = this.julian_day - u.julian_day;
    if(day_dif < 0) {
        before=true;
    } else if (day_dif > 0) {
        before=false;
    } else {
        int sec_dif = this.sec_of_day - u.getSecs();
        if(sec_dif < 0) {
            before=true;
        }
    }
    return before;
   }

   /**
    * @param u any UTCDate
    * @return true iff 'this' is after u
    */
   public boolean isAfter(UTCDate u) {
    boolean after=false;
    int day_dif = this.julian_day - u.julian_day;
    if(day_dif > 0) {
        after=true;
    } else if (day_dif < 0) {
        after=false;
    } else {
        int sec_dif = this.sec_of_day - u.getSecs();
        if(sec_dif > 0) {
            after=true;
        }
    }
    return after;
   }

   /**
    * A string representation of the day
    * @return a string representation of the day
    */
   public String toString() {
     return leadingZero(getDay())+"-"+month_name[getMonth()-1]+
            "-"+getYear()+" "+
            leadingZero(getHour())+":"+leadingZero(getMinute())
            +":"+leadingZero(getSecond());
   }

   public String shortString() {
    //returns a short versiion of the date
    int short_year = getYear() % 100;
    return leadingZero(getMonth())+"/"+leadingZero(getDay())+
            "/"+leadingZero(short_year)+" "+
            leadingZero(getHour())+leadingZero(getMinute());
   }

    /**
    * A string representation of the time of day
    * @return a string representation of the time of day
    */
   public String getHHMM() {
    return leadingZero(getHour())+leadingZero(getMinute());
   }

  /**
    * Makes a bitwise copy of a Day object
    * @return a bitwise copy of a Day object
    */
   public Object clone()
   {  try
      {  return super.clone();
      } catch (CloneNotSupportedException e)
      {  // this shouldn't happen, since we are Cloneable
         return null;
      }
   }

   /**
    * Sets the julian day and sec_of_day given hour,min, and second
    */
   private void setSecsDays(int[] ymdhms) {
      julian_day = toJulian(ymdhms);
      sec_of_day = ymdhms[5] + 60*ymdhms[4] + 3600*ymdhms[3];
   }

  /**
    * Sets the julian day and sec_of_day given hour,min, and second
    */
   private void setJulian(int[] ymd) {
      julian_day = toJulian(ymd);
    }

    /**
    * @return The Julian day number that begins at noon of
    * this day
    * Positive year signifies A.D., negative year B.C.
    * Remember that the year after 1 B.C. was 1 A.D.
    *
    * A convenient reference point is that May 23, 1968 noon
    * is Julian day 2440000.
    *
    * Julian day 0 is a Monday.
    *
    * This algorithm is from Press et al., Numerical Recipes
    * in C, 2nd ed., Cambridge University Press 1992
    */
   private int toJulian(int[] ymdhms) {
    int year=ymdhms[0];
    int month=ymdhms[1];
    int day=ymdhms[2];
      int jy = year;
      if (year < 0) jy++;
      int jm = month;
      if (month > 2) jm++;
      else
      {  jy--;
         jm += 13;
      }
      int jul = (int) (java.lang.Math.floor(365.25 * jy)
      + java.lang.Math.floor(30.6001*jm) + day + 1720995.0);

      int IGREG = 15 + 31*(10+12*1582);
         // Gregorian Calendar adopted Oct. 15, 1582

      if (day + 31 * (month + 12 * year) >= IGREG)
         // change over to Gregorian calendar
      {  int ja = (int)(0.01 * jy);
         jul += 2 - ja + (int)(0.25 * ja);
      }
      return jul;
   }

   /**
    * Converts a Julian day to a calendar date
    * This algorithm is from Press et al., Numerical Recipes
    * in C, 2nd ed., Cambridge University Press 1992
    */
   private int[] fromJulian() {
    int j = julian_day;
    int year,month,day;
    int result[] = new int[3];
    int ja = j;


      if (j >= JGREG)
      /* cross-over to Gregorian Calendar produces this
         correction
      */
      {  int jalpha = (int)(((float)(j - 1867216) - 0.25)
             / 36524.25);
         ja += 1 + jalpha - (int)(0.25 * jalpha);
      }
      int jb = ja + 1524;
      int jc = (int)(6680.0 + ((float)(jb-2439870) - 122.1)
          /365.25);
      int jd = (int)(365 * jc + (0.25 * jc));
      int je = (int)((jb - jd)/30.6001);
      day = jb - jd - (int)(30.6001 * je);
      month = je - 1;
      if (month > 12) month -= 12;
      year = jc - 4715;
      if (month > 2) --year;
      if (year <= 0) --year;

   result[0]=year;
   result[1]=month;
   result[2]=day;
   return result;
 }
}

AWRA
Symposium TOC AWRA Home page

Maintainer: AWRA Webserver Team
Copyright © 1999 American Water Resources Association