Week of year calculation.

This commit is contained in:
Vincent Richard 2006-04-24 19:40:24 +00:00
parent 6933fb8a30
commit 01ba897060
5 changed files with 118 additions and 0 deletions

View File

@ -794,6 +794,7 @@ const int datetime::getMinute() const { return (m_minute); }
const int datetime::getSecond() const { return (m_second); }
const int datetime::getZone() const { return (m_zone); }
const int datetime::getWeekDay() const { return (utility::datetimeUtils::getDayOfWeek(m_year, m_month, m_day)); }
const int datetime::getWeek() const { return utility::datetimeUtils::getWeekOfYear(m_year, m_month, m_day); }
void datetime::setYear(const int year) { m_year = year; }
void datetime::setMonth(const int month) { m_month = std::min(std::max(month, 1), 12); }

View File

@ -252,5 +252,75 @@ const int datetimeUtils::getDayOfWeek(const int year, const int month, const int
}
const int datetimeUtils::getWeekOfYear(const int year, const int month, const int day)
{
// Algorithm from http://personal.ecu.edu/mccartyr/ISOwdALG.txt
const bool leapYear = ((year % 4) == 0 && (year % 100) != 0) || (year % 400) == 0;
const bool leapYear_1 = (((year - 1) % 4) == 0 && ((year - 1) % 100) != 0) || ((year - 1) % 400) == 0;
// 4. Find the DayOfYearNumber for Y M D
static const int DAY_OF_YEAR_NUMBER_MAP[12] =
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
int DayOfYearNumber = day + DAY_OF_YEAR_NUMBER_MAP[month - 1];
if (leapYear && month > 2)
DayOfYearNumber += 1;
// 5. Find the Jan1Weekday for Y (Monday=1, Sunday=7)
const int YY = (year - 1) % 100;
const int C = (year - 1) - YY;
const int G = YY + YY / 4;
const int Jan1Weekday = 1 + (((((C / 100) % 4) * 5) + G) % 7);
// 6. Find the Weekday for Y M D
const int H = DayOfYearNumber + (Jan1Weekday - 1);
const int Weekday = 1 + ((H - 1) % 7);
// 7. Find if Y M D falls in YearNumber Y-1, WeekNumber 52 or 53
int YearNumber, WeekNumber;
if (DayOfYearNumber <= (8 - Jan1Weekday) && Jan1Weekday > 4)
{
YearNumber = year - 1;
if (Jan1Weekday == 5 || (Jan1Weekday == 6 && leapYear_1))
WeekNumber = 53;
else
WeekNumber = 52;
}
else
{
YearNumber = year;
}
// 8. Find if Y M D falls in YearNumber Y+1, WeekNumber 1
if (YearNumber == year)
{
const int I = (leapYear ? 366 : 365);
if ((I - DayOfYearNumber) < (4 - Weekday))
{
YearNumber = year + 1;
WeekNumber = 1;
}
}
// 9. Find if Y M D falls in YearNumber Y, WeekNumber 1 through 53
if (YearNumber == year)
{
const int J = DayOfYearNumber + (7 - Weekday) + (Jan1Weekday - 1);
WeekNumber = J / 7;
if (Jan1Weekday > 4)
WeekNumber -= 1;
}
return WeekNumber;
}
} // utility
} // vmime

View File

@ -39,6 +39,8 @@ VMIME_TEST_SUITE_BEGIN
VMIME_TEST(testGetDaysInMonthLeapYear)
VMIME_TEST(testToUniversalTime)
VMIME_TEST(testToLocalTime)
VMIME_TEST(testGetDayOfWeek)
VMIME_TEST(testGetWeekOfYear)
VMIME_TEST_LIST_END
@ -124,5 +126,40 @@ VMIME_TEST_SUITE_BEGIN
VASSERT_EQ("7", 120, local.getZone());
}
void testGetDayOfWeek()
{
VASSERT_EQ("1", vmime::datetime::WEDNESDAY, datetimeUtils::getDayOfWeek(1969, 12, 31));
VASSERT_EQ("2", vmime::datetime::FRIDAY, datetimeUtils::getDayOfWeek(1976, 4, 9));
VASSERT_EQ("3", vmime::datetime::TUESDAY, datetimeUtils::getDayOfWeek(1987, 6, 23));
VASSERT_EQ("4", vmime::datetime::SATURDAY, datetimeUtils::getDayOfWeek(1990, 1, 13));
VASSERT_EQ("5", vmime::datetime::MONDAY, datetimeUtils::getDayOfWeek(1999, 9, 20));
VASSERT_EQ("6", vmime::datetime::THURSDAY, datetimeUtils::getDayOfWeek(2003, 2, 27));
VASSERT_EQ("7", vmime::datetime::SATURDAY, datetimeUtils::getDayOfWeek(2005, 11, 19));
VASSERT_EQ("8", vmime::datetime::WEDNESDAY, datetimeUtils::getDayOfWeek(2012, 5, 16));
VASSERT_EQ("9", vmime::datetime::FRIDAY, datetimeUtils::getDayOfWeek(2027, 3, 12));
}
void testGetWeekOfYear()
{
VASSERT_EQ("1.1", 52, datetimeUtils::getWeekOfYear(2003, 12, 27));
VASSERT_EQ("1.2", 52, datetimeUtils::getWeekOfYear(2003, 12, 28));
VASSERT_EQ("1.3", 1, datetimeUtils::getWeekOfYear(2003, 12, 29));
VASSERT_EQ("1.4", 1, datetimeUtils::getWeekOfYear(2004, 1, 4));
VASSERT_EQ("1.5", 2, datetimeUtils::getWeekOfYear(2004, 1, 5));
VASSERT_EQ("1.6", 2, datetimeUtils::getWeekOfYear(2004, 1, 11));
VASSERT_EQ("2.1", 52, datetimeUtils::getWeekOfYear(2004, 12, 26));
VASSERT_EQ("2.2", 53, datetimeUtils::getWeekOfYear(2004, 12, 27));
VASSERT_EQ("2.3", 53, datetimeUtils::getWeekOfYear(2005, 1, 2));
VASSERT_EQ("2.4", 1, datetimeUtils::getWeekOfYear(2005, 1, 3));
VASSERT_EQ("2.5", 1, datetimeUtils::getWeekOfYear(2005, 1, 4));
VASSERT_EQ("2.6", 2, datetimeUtils::getWeekOfYear(2005, 1, 11));
VASSERT_EQ("3.1", 9, datetimeUtils::getWeekOfYear(2027, 3, 7));
VASSERT_EQ("3.2", 10, datetimeUtils::getWeekOfYear(2027, 3, 8));
VASSERT_EQ("3.3", 10, datetimeUtils::getWeekOfYear(2027, 3, 14));
VASSERT_EQ("3.4", 11, datetimeUtils::getWeekOfYear(2027, 3, 15));
}
VMIME_TEST_SUITE_END

View File

@ -200,6 +200,7 @@ public:
const int getSecond() const;
const int getZone() const;
const int getWeekDay() const;
const int getWeek() const;
void getTime(int& hour, int& minute, int& second, int& zone) const;
void getTime(int& hour, int& minute, int& second) const;

View File

@ -78,6 +78,15 @@ public:
* @return the day of the week, Sunday is 0, Monday is 1 (see datetime::DaysOfWeek enum)
*/
static const int getDayOfWeek(const int year, const int month, const int day);
/** Return the week number in the year (ISO 8601).
*
* @param year year in 4-digit format
* @param month month (1-12), January is 1, December is 12 (see datetime::Months enum)
* @param day month day (1-31)
* @return the week number (1 is the first week of the year)
*/
static const int getWeekOfYear(const int year, const int month, const int day);
};