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();
}
}
}