/* TimeUtilities.c * * * Emilio 2/2/2001 * Added GetDaysInMonth function. Added local array nDaysPerMonthLocal. * * Functions used to make calendar format conversions, particularly to convert * among Julian Day, Gregorian Calendar, Solar Day, and Day of the Week. * Leap Years and other subtleties are taken into account. * Code taken from TJ Saunders' code, originally adapted in large part from * "Numerical Recipes in C", 2nd ed, pp. 11-12. ******************************************************************************/ #include "emu.h" /* array used locally, so it doesn't conflict or modify the global array * * nDaysPerMonth from unitconv.h */ static int nDaysPerMonthLocal[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* ------------------------------------------------------------------------------ */ void GregorianToJulianDay(int nMonth, int nDay, int nYear, long *plJulianDay) { /* this algorithm is based on that found in "Numerical Recipes in C", 2nd ed, */ /* pp. 11-12. */ /* local (as in local to this function) working variables */ int nLocalMonth; int nLocalYear; /* working variable */ int nAdjust; /* capture the input values */ nLocalMonth = nMonth; nLocalYear = nYear; if (nYear == 0) { /* display an error */ Warning("GregorianToJulianDay()", "no year 0 AD"); return; } if (nYear < 0) /* add one to an AD year for the "Scalinger Year" */ nLocalYear++; if (nMonth > 2) { /* increment the month if is March or later */ nLocalMonth = nMonth + 1; } else { /* decrement the year into the previous Julian cycle */ nLocalYear--; /* place January and February into the previous Julian cycle */ nLocalMonth = nMonth + 13; } *plJulianDay = (long) (floor(365.25 * nLocalYear) + floor(30.6001 * nLocalMonth) + nDay + 1720995); /* test whether to adjust the day for the Gregorian calendar or not */ if ((nDay + 31L * (nMonth + 12L * nYear)) >= GREGORIAN_START) { /* a small adjustment factor */ nAdjust = (int) (0.01 * nLocalYear); *plJulianDay += (2 - nAdjust + (int) (0.25 * nAdjust)); } /* done */ return; } /* ------------------------------------------------------------------------------ */ void GregorianToSolarDay(int nMonth, int nDay, int nYear, int *pnSolarDay) { /* a loop variable */ int nMonthIndex; /* working variables */ int nDays = 0; /* first, adjust the number of days in February, if necessary */ nDaysPerMonthLocal[1] = (IsLeapYear(nYear)) ? 29 : 28; /* loop through the number of months, summing up the number of days so far */ /* use the input month minus one as the loop limit to allow for the number of days */ /* for the next month */ for (nMonthIndex = 0; nMonthIndex < (nMonth - 1); nMonthIndex++) nDays += nDaysPerMonthLocal[nMonthIndex]; /* add the day of the month */ nDays += nDay; /* and that's your Solar day, 1-based */ *pnSolarDay = nDays; /* done */ return; } /* ------------------------------------------------------------------------------ */ void JulianToGregorianDay(long lJulianDay, int *pnMonth, int *pnDay, int *pnYear) { /* this algorithm is taken from "Numerical Recipes in C", 2nd ed, pp 14-15. */ /* working variables */ long lFactorA, lFactorB, lFactorC, lFactorD, lFactorE; long lAdjust; /* test whether to adjust for the Gregorian calendar crossover */ if (lJulianDay >= GREGORIAN_CROSSOVER) { /* calculate a small adjustment */ lAdjust = (long) (((float) (lJulianDay - 1867216) - 0.25) / 36524.25); lFactorA = lJulianDay + 1 + lAdjust - ((long) (0.25 * lAdjust)); } else /* no adjustment needed */ lFactorA = lJulianDay; /* what follows is a lot of numerical hocus-pocus that I can't follow...I'm just */ /* copying it right out of "Numerical Recipes" */ lFactorB = lFactorA + 1524; lFactorC = (long) (6680.0 + ((float) (lFactorB - 2439870) - 122.1) / 365.25); lFactorD = (long) (365 * lFactorC + (0.25 * lFactorC)); lFactorE = (long) ((lFactorB - lFactorD) / 30.6001); /* now, pull out the day number */ *pnDay = lFactorB - lFactorD - (long) (30.6001 * lFactorE); /* ...and the month, adjusting it if necessary */ *pnMonth = lFactorE - 1; if (*pnMonth > 12) (*pnMonth) -= 12; /* ...and similarly for the year */ *pnYear = lFactorC - 4715; if (*pnMonth > 2) (*pnYear)--; if (*pnYear <= 0) (*pnYear)--; /* done */ return; } /* ------------------------------------------------------------------------------ */ void JulianToSolarDay(long lJulianDay, int *pnSolarDay) { /* convert the input Julian day to a Gregorian day, then call GregorianToSolarDay() */ /* variables for the Gregorian day values */ int nMonth, nDay, nYear; /* convert to Gregorian dates */ JulianToGregorianDay(lJulianDay, &nMonth, &nDay, &nYear); /* now get the Solar day */ GregorianToSolarDay(nMonth, nDay, nYear, pnSolarDay); /* done */ return; } /* ------------------------------------------------------------------------------ */ int GetDayOfWeekIndex(long lJulianDay) { /* returns the day of the week given the input Julian day. The output ranges */ /* from 0 to 7, with 0 being Monday and 6 being Sunday */ return (int) (lJulianDay % 7L); } /* ------------------------------------------------------------------------------ */ void GetDayOfWeekName(long lJulianDay, char *pszDayOfWeek) { /* return a string with the name of the day of the week for the given Julian */ /* Day */ switch (GetDayOfWeekIndex(lJulianDay)) { case 0: /* Monday */ sprintf(pszDayOfWeek, "Monday"); break; case 1: /* Tuesday */ sprintf(pszDayOfWeek, "Tuesday"); break; case 2: /* Wednesday */ sprintf(pszDayOfWeek, "Wednesday"); break; case 3: /* Thursday */ sprintf(pszDayOfWeek, "Thursday"); break; case 4: /* Friday */ sprintf(pszDayOfWeek, "Friday"); break; case 5: /* Saturday */ sprintf(pszDayOfWeek, "Saturday"); break; case 6: /* Sunday */ sprintf(pszDayOfWeek, "Sunday"); break; default: sprintf(pszDayOfWeek, "error -- unknown day of the week"); } /* done */ return; } /* ------------------------------------------------------------------------------ */ /* return the number of days of the specified months (base 1), accounting for * * Leap years */ short GetDaysInMonth(short month, int nYear) { /* account for leap years */ nDaysPerMonthLocal[1] = (IsLeapYear(nYear)) ? 29 : 28; return((short)nDaysPerMonthLocal[month-1]); } /* ------------------------------------------------------------------------------ */ BOOL IsLeapYear(int nYear) { /* the result */ BOOL bIsLeapYear; if ((nYear % 4 == 0) && (nYear % 100 != 0 || nYear % 400 == 0)) bIsLeapYear = TRUE; else bIsLeapYear = FALSE; /* return the result */ return bIsLeapYear; } /* ------------------------------------------------------------------------------ */ void SolarToGregorianDay(int nSolarDay, int nYear, int *pnMonth, int *pnDay) { /* convert the given Solar day (1-based) and year to a month and day */ /* a loop variable */ int nMonthIndex; /* working variables */ int nDaysRemaining = nSolarDay; int nDay = 0; /* determine if it's a leap year */ nDaysPerMonthLocal[1] = (IsLeapYear(nYear)) ? 29 : 28; /* loop through the months, subtracting the number of days per month from the */ /* the given Solar day */ for (nMonthIndex = 0; nMonthIndex < YEAR2MONTH; nMonthIndex++) { nDaysRemaining -= nDaysPerMonthLocal[nMonthIndex]; /* stop subtracting */ if (nDaysRemaining <= 0) break; } /* the month index pointer (plus a small adjustment) should now be the month */ *pnMonth = nMonthIndex + 1; /* add the number of days for the month back into the remaining days variable */ /* to get the day of the month */ *pnDay = nDaysRemaining + nDaysPerMonthLocal[nMonthIndex]; /* done */ return; } /* ------------------------------------------------------------------------------ */ void SolarToJulianDay(int nSolarDay, int nYear, long *plJulianDay) { /* convert the given Solar day and year to a Gregorian day, then call */ /* GregorianToJulianDay() */ /* working variables */ int nMonth, nDay; SolarToGregorianDay(nSolarDay, nYear, &nMonth, &nDay); GregorianToJulianDay(nMonth, nDay, nYear, plJulianDay); /* done */ return; }