Super fast DateMath class (days_between & day_of_week)

I wrote this code because I needed something much faster than java.util.Calendar

Benchmark showing factor 25 higher performance
Running 100 * (for all days between 1970 and 2010)
DAY_OF_WEEK of Calendar: 1658ms
DAY_OF_WEEK of DateMath: 67ms

Usage:

int dow  = dayOfWeek(int year, int month, int date)
int days = duration(int fromYear, int fromMonth, int fromDate, int untilYear, int untilMonth, int untilDate)

Sourcecode


public class DateMath
{
   /**
    * duration(2000/01/01 => 2000/01/01) = 1 days

    * duration(2000/01/01 => 2000/01/03) = 3 days

    * duration(2000/01/03 => 2000/01/01) = [exception]

    */

   public static int duration(int fromYear, int fromMonth, int fromDate, int untilYear, int untilMonth, int untilDate)
   {
      int diff = compare(fromYear, fromMonth, fromDate, untilYear, untilMonth, untilDate);
      if (diff < 0)
         throw new IllegalStateException("from > until");
      return diff + 1;
   }

   /**
    * compare(2000/01/01 => 2000/01/01) = 0

    * compare(2000/01/01 => 2000/01/03) = +2

    * compare(2000/01/03 => 2000/01/01) = -2

    */

   public static int compare(int fromYear, int fromMonth, int fromDate, int untilYear, int untilMonth, int untilDate)
   {
      int from = daysSinceEpoch(fromYear, fromMonth, fromDate);
      int until = daysSinceEpoch(untilYear, untilMonth, untilDate);
      return until - from;
   }

   /**
    * Sunday = 0

    * Monday = 1

    * Tuesday = 2

    * Wednesday = 3

    * Thursday = 4

    * Friday = 5

    * Saturday = 6 
    */

   public static int dayOfWeek(int year, int month, int date)
   {
      return (dayOfWeekOnEpoch() + daysSinceEpoch(year, month, date)) % 7;
   }

   /**
    * Range: 1..{365|366}
    */

   public static int getDayInYear(int year, int month, int date)
   {
      if (month < 3)
         return date + (month - 1) * 31;
      date += daysInFebruary(year);
      date += (month - 2) * 30;
      date += (month + (month >> 3)) >> 1;
      return date;
   }

   public static int daysInMonth(int year, int month)
   {
      if (month == 2)
         return daysInFebruary(year);
      return 30 + ((month & 1) ^ (month >> 3));
   }

   public static boolean isLeapDay(int year, int month, int date)
   {
      return (month != 2 || date != 29) ? false : isLeapYear(year);
   }

   public static boolean isLeapYear(int year)
   {
      if (year % 100 == 0)
         return (year % 400 == 0);
      return ((year & 3) == 0);
   }

   private static int daysInFebruary(int year)
   {
      return isLeapYear(year) ? 29 : 28;
   }

   private static int dayOfWeekOnEpoch()
   {
      // 1970/01/01 is a Thursday, 4 days after Sunday
      return 4; //Calendar.THURSDAY - Calendar.SUNDAY;
   }

   private static int daysSinceEpoch(int year, int month, int date)
   {
      int epochLeapDays = getLeapDaysInEpoch();
      int crrntLeapDays = getLeapDaysInYear(year);
      int daysInYearsBetween = 365 * (year - 1970);
      daysInYearsBetween += crrntLeapDays - epochLeapDays;
      daysInYearsBetween += getDayInYear(year, month, date);
      return daysInYearsBetween - 1;
   }

   private static int getLeapDaysInYear(int year)
   {
      return (year / 4) - (year / 100) + (year / 400);
   }

   private static int getLeapDaysInEpoch()
   {
      // final int year = 1970;
      // return (year / 4) - (year / 100) + (year / 400);
      // return 492 - 19 + 4;
      // return 477;
      return 477;
   }
}

Verification code:


         for (int year = 1970; year <= 2010; year++)
         {
            for (int month = 1; month <= 12; month++)
            {
               int daysInMonth = DateMath.daysInMonth(year, month);

               for (int date = 1; date <= daysInMonth; date++)
               {
                  current.set(year, month - 1, date);

                  // check for invalid date
                  if (current.get(Calendar.YEAR) != year) throw new IllegalStateException();
                  if (current.get(Calendar.MONTH) != month - 1) throw new IllegalStateException();
                  if (current.get(Calendar.DATE) != date) throw new IllegalStateException();

                  // check for different results
                  int a = current.get(Calendar.DAY_OF_WEEK);
                  int b = DateMath.dayOfWeek(year, month, date) + Calendar.SUNDAY;
                  if (a != b) throw new IllegalStateException();
               }
            }
         }

Benchmark code:


   public static void benchmark()
   {
      Calendar current = Calendar.getInstance();

      final int runs = 4;
      final int loops = 100;
      int opt1 = 1337;
      int opt2 = 1337;

      for (int i = 0; i < runs; i++)
      {
         // verify results
         for (int year = 1970; year <= 2010; year++)
         {
            for (int month = 1; month <= 12; month++)
            {
               int daysInMonth = DateMath.daysInMonth(year, month);
               for (int date = 1; date <= daysInMonth; date++)
               {
                  current.set(year, month - 1, date);
                  if (current.get(Calendar.YEAR) != year)
                     throw new IllegalStateException();
                  if (current.get(Calendar.MONTH) != month - 1)
                     throw new IllegalStateException();
                  if (current.get(Calendar.DATE) != date)
                     throw new IllegalStateException();

                  opt1 = current.get(Calendar.DAY_OF_WEEK);
                  opt2 = DateMath.dayOfWeek(year, month, date) + Calendar.SUNDAY;
                  if (opt1 != opt2)
                     throw new IllegalStateException(year + "/" + month + "/" + date + " => " + opt1 + " <> " + opt2);
               }
            }
         }
         long t0 = System.nanoTime();
         for (int k = 0; k < loops; k++) // benchmark Calendar
         {
            for (int year = 1970; year <= 2010; year++)
            {
               for (int month = 1; month <= 12; month++)
               {
                  int daysInMonth = DateMath.daysInMonth(year, month);
                  for (int date = 1; date <= daysInMonth; date++)
                  {
                     current.set(year, month - 1, date);
                     opt1 += current.get(Calendar.DAY_OF_WEEK);
                  }
               }
            }
         }
         long t1 = System.nanoTime();
         for (int k = 0; k < loops; k++) // benchmark DateMath
         {
            for (int year = 1970; year <= 2010; year++)
            {
               for (int month = 1; month <= 12; month++)
               {
                  int daysInMonth = DateMath.daysInMonth(year, month);
                  for (int date = 1; date <= daysInMonth; date++)
                  {
                     opt2 += DateMath.dayOfWeek(year, month, date) + Calendar.SUNDAY;
                  }
               }
            }
         }
         long t2 = System.nanoTime();
         System.out.println("Calendar: " + (t1 - t0) / 1000000 + "ms, DateMath: " + (t2 - t1) / 1000000 + "ms");
      }
      System.out.println("prevent opt1 by HotSpot ~~ " + opt1);
      System.out.println("prevent opt2 by HotSpot ~~ " + opt2);
   }

OMG!


int dow  = dayOfWeek(2010, 5, 22);

if (dow > currentDow)
{
    this.BUYBUYBUY();
}
else
{
    this.SELLSELLSELL();
}

BRILLIANT, RIVEN, BRILLIANT! I CAN’T BEIEVE YOU CRACKED THE DOW JONES INDUSTRIAL AVERAGE.

/endJoking

This class will be mighty useful, I’ve been annoyed with Java’s Calendar in the past.

True.

Calendar isn’t really that bad, it’s just plain slow.
Calendar c = Calendar.getInstance(); c.setTime(year, month-1, date); int dow = c.get(Calendar.DAY_OF_WEEK);

On a side note:
I made a physical copy of your code and have sent it to the authorities.