Java Date and Calendar Class Bug


Search engine sent you here?
Click here for a Javascript days between dates utility.
Click here for a Java days between dates/calendar utility.

The source code

/** CustomDate.java
    The java Date class is buggy. Perhaps that's why it was deprecated in 
    version 1.1. It is poorly documented, and only trial and error informs
    you that January is the "zeroth" month and February is the first month of the
    year. This slovenliness I can at least adjust to, but there's a bug I
    cannot adjust to--the Date class, and the Calendar class that rely on 
    it believe that April has only 29 days (i.e. 29*24*60*60*1000 milliseconds).
    Oddly, the year 1900 correctly has 30 days in April, so it seems you can
    use these classes for the year 1900 but not others.
	
    So here's a CustomDate class based on Julian days. 
    See http://www.tondering.dk/claus/cal/calendar26.txt for the algorithm.
    Here it is used just for calculating days between dates, and you'll have
    to fancy it up to use it for anything else.	
	
    The main method is a comparison of the CustomDate class, java.util.Date class,
    and java.util.Calendar classes. It calculates the number of days in April,
    which is of course 30, but the Java classes say it has 29.
*/

package customdate;

import java.util.Date;
import java.util.Calendar;

public class CustomDate{
  public static final int GREGORIAN = 0;  //15 Oct 1582 and later
  public static final int JULIAN = 1;     //before that
  int year = 0;
  int month = 0;
  int day = 0;
  double julianday = 0; //accurate from noon 1 Jan 4713 BC (Julian day zero) to 1 Jan 3268
  double modifiedjulianday = 0; //Modified Julian day zero is 17 Nov 1858 (Gregorian) at 00:00:00 UTC

  public CustomDate(int yr, int mo, int da, int type){
    if (year < -4713 || year > 6716){
      System.out.println("Year out of range");
      return;
    }
    year = yr;
    month = mo;
    day = da;
    long a = ipart((14 - month) / 12);
    long y = year + 4800 -a;
    long m = month + 12 * a - 3;
    if (type == GREGORIAN){
      julianday = day + ipart((153*m + 2)/5) + y*365 + ipart(y/4) - ipart(y/100) + ipart(y/400) - 32045;
    }
    if (type == JULIAN){
      julianday = day + ipart((153*m + 2)/5) + y*365 + ipart(y/4) - 32083;
    }
    modifiedjulianday = julianday - 2400000.5;
  }

  public CustomDate(int yr, int mo, int da){
    this(yr,mo,da,GREGORIAN);
  }

  public double getJulianDay(){ return (int) this.julianday; }
  public double getModifiedJulianDay(){ return (int) this.modifiedjulianday; }

  private long ipart(double r){ return Math.round(r - 0.5); }

  public static void main(String args[]){
    int y1 = 2003;
    int m1 = Calendar.APRIL;
    int date1 = 1;
    int y2 = 2003;
    int m2 = Calendar.MAY;
    int date2 = 1;
    int msperday = 1000 * 60 *60 * 24;

    Date d1 = new Date(y1, m1, date1);
    Date d2 = new Date(y2, m2, date2);
    System.out.println("java.util.Date");
    System.out.println("Month numbers in Date and Calendar start at ZERO!");
    System.out.println(d1.getMonth() + "/" + d1.getDate() + "/" + d1.getYear());
    System.out.println(d2.getMonth() + "/" + d2.getDate() + "/" + d2.getYear() );
    int dbd = (int) ((d2.getTime() - d1.getTime()) / msperday);
    System.out.println("Days between dates " + dbd);

    Calendar cal1 = Calendar.getInstance();
    Calendar cal2 = Calendar.getInstance();
    cal1.set(y1, m1, date1);
    cal2.set(y2, m2, date2);
    Date n1 = cal1.getTime();
    Date n2 = cal2.getTime();
    dbd = (int) ((n2.getTime() - n1.getTime()) / msperday);
    System.out.println("java.util.Calendar");
    System.out.print(cal1.get(Calendar.MONTH) + "/");
    System.out.print(cal1.get(Calendar.DAY_OF_MONTH) + "/");
    System.out.println(cal1.get(Calendar.YEAR));
    System.out.print(cal2.get(Calendar.MONTH) + "/");
    System.out.print(cal2.get(Calendar.DAY_OF_MONTH) + "/");
    System.out.println(cal2.get(Calendar.YEAR));
    System.out.println("Days between dates " + dbd);

    m1++; //Because Calendar.JANUARY = 0
    m2++;
    CustomDate cd1 = new CustomDate(y1, m1, date1);
    CustomDate cd2 = new CustomDate(y2, m2, date2);
    System.out.println("Custom Date");
    System.out.println(cd1.month + "/" + cd1.day + "/" + cd1.year);
    System.out.println(cd2.month + "/" + cd2.day + "/" + cd2.year);
    dbd = (int) (cd2.getJulianDay() - cd1.getJulianDay());
    System.out.println("Days between dates " + dbd);
  }
}

The output

java.util.Date
Month numbers in Date and Calendar start at ZERO!
3/1/2003
4/1/2003
Days between dates 29
java.util.Calendar
3/1/2003
4/1/2003
Days between dates 29
Custom Date
4/1/2003
5/1/2003
Days between dates 30


Last revised 12/21/03
M. Steven Evans [ mail | home page ]