aboutsummaryrefslogtreecommitdiff
path: root/vmime-master/src/vmime/utility/datetimeUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vmime-master/src/vmime/utility/datetimeUtils.cpp')
-rw-r--r--vmime-master/src/vmime/utility/datetimeUtils.cpp317
1 files changed, 317 insertions, 0 deletions
diff --git a/vmime-master/src/vmime/utility/datetimeUtils.cpp b/vmime-master/src/vmime/utility/datetimeUtils.cpp
new file mode 100644
index 0000000..b1a6c55
--- /dev/null
+++ b/vmime-master/src/vmime/utility/datetimeUtils.cpp
@@ -0,0 +1,317 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/datetimeUtils.hpp"
+
+#include <stdexcept>
+
+
+namespace vmime {
+namespace utility {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+static inline void nextMonth(datetime& d) {
+
+ if (d.getMonth() >= 12) {
+ d.setMonth(1);
+ d.setYear(d.getYear() + 1);
+ } else {
+ d.setMonth(d.getMonth() + 1);
+ }
+}
+
+
+static inline void prevMonth(datetime& d) {
+
+ if (d.getMonth() <= 1) {
+ d.setYear(d.getYear() - 1);
+ d.setMonth(12);
+ } else {
+ d.setMonth(d.getMonth() - 1);
+ }
+}
+
+
+static inline void nextDay(datetime& d) {
+
+ if (d.getDay() >= datetimeUtils::getDaysInMonth(d.getYear(), d.getMonth())) {
+ d.setDay(1);
+ nextMonth(d);
+ } else {
+ d.setDay(d.getDay() + 1);
+ }
+}
+
+
+static inline void prevDay(datetime& d) {
+
+ if (d.getDay() <= 1) {
+ prevMonth(d);
+ d.setDay(datetimeUtils::getDaysInMonth(d.getYear(), d.getMonth()));
+ } else {
+ d.setDay(d.getDay() - 1);
+ }
+}
+
+
+static inline void nextHour(datetime& d) {
+
+ if (d.getHour() >= 23) {
+ d.setHour(0);
+ nextDay(d);
+ } else {
+ d.setHour(d.getHour() + 1);
+ }
+}
+
+
+static inline void prevHour(datetime& d) {
+
+ if (d.getHour() <= 0) {
+ d.setHour(23);
+ prevDay(d);
+ } else {
+ d.setHour(d.getHour() - 1);
+ }
+}
+
+
+static inline void addHoursAndMinutes(datetime& d, const int h, const int m) {
+
+ d.setMinute(d.getMinute() + m);
+
+ if (d.getMinute() >= 60) {
+ d.setMinute(d.getMinute() - 60);
+ nextHour(d);
+ }
+
+ d.setHour(d.getHour() + h);
+
+ if (d.getHour() >= 24) {
+ d.setHour(d.getHour() - 24);
+ nextDay(d);
+ }
+}
+
+
+static inline void substractHoursAndMinutes(datetime& d, const int h, const int m) {
+
+ if (m > d.getMinute()) {
+ d.setMinute(60 - (m - d.getMinute()));
+ prevHour(d);
+ } else {
+ d.setMinute(d.getMinute() - m);
+ }
+
+ if (h > d.getHour()) {
+ d.setHour(24 - (h - d.getHour()));
+ prevDay(d);
+ } else {
+ d.setHour(d.getHour() - h);
+ }
+}
+
+#endif // VMIME_BUILDING_DOC
+
+
+const datetime datetimeUtils::toUniversalTime(const datetime& date) {
+
+ if (date.getZone() == datetime::GMT) {
+ return date; // no conversion needed
+ }
+
+ datetime nd(date);
+ nd.setZone(datetime::GMT);
+
+ const int z = date.getZone();
+ const int h = (z < 0) ? (-z / 60) : (z / 60);
+ const int m = (z < 0) ? (-z - h * 60) : (z - h * 60);
+
+ if (z < 0) { // GMT-hhmm: add hours and minutes to date
+ addHoursAndMinutes(nd, h, m);
+ } else { // GMT+hhmm: substract hours and minutes from date
+ substractHoursAndMinutes(nd, h, m);
+ }
+
+ return nd;
+}
+
+
+const datetime datetimeUtils::toLocalTime(const datetime& date, const int zone) {
+
+ datetime utcDate(date);
+
+ if (utcDate.getZone() != datetime::GMT) {
+ utcDate = toUniversalTime(date); // convert to UT before
+ }
+
+ datetime nd(utcDate);
+ nd.setZone(zone);
+
+ const int h = (zone < 0) ? (-zone / 60) : (zone / 60);
+ const int m = (zone < 0) ? (-zone - h * 60) : (zone - h * 60);
+
+ if (zone < 0) { // GMT+hhmm: substract hours and minutes from date
+ substractHoursAndMinutes(nd, h, m);
+ } else { // GMT-hhmm: add hours and minutes to date
+ addHoursAndMinutes(nd, h, m);
+ }
+
+ return nd;
+}
+
+
+bool datetimeUtils::isLeapYear(const int year) {
+
+ // From RFC 3339 - Appendix C. Leap Years:
+ return ((year % 4) == 0 && (year % 100 != 0 || year % 400 == 0));
+}
+
+
+int datetimeUtils::getDaysInMonth(const int year, const int month) {
+
+ static const int daysInMonth[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+ static const int daysInMonthLeapYear[12] = {
+ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+
+ if (month < 1 || month > 12) {
+ throw std::out_of_range("Invalid month number");
+ }
+
+ return isLeapYear(year) ? daysInMonthLeapYear[month - 1] : daysInMonth[month - 1];
+}
+
+
+int datetimeUtils::getDayOfWeek(const int year, const int month, const int day) {
+
+ int y = year;
+ int m = month;
+
+ if (month < 1 || month > 12) {
+ throw std::out_of_range("Invalid month number");
+ } else if (day < 1 || day > getDaysInMonth(year, month)) {
+ throw std::out_of_range("Invalid day number");
+ }
+
+ // From RFC-3339 - Appendix B. Day of the Week
+
+ // Adjust months so February is the last one
+ m -= 2;
+
+ if (m < 1) {
+ m += 12;
+ --y;
+ }
+
+ // Split by century
+ const int cent = y / 100;
+ y %= 100;
+
+ return ((26 * m - 2) / 10 + day + y + (y >> 2) + (cent >> 2) + 5 * cent) % 7;
+}
+
+
+int datetimeUtils::getWeekOfYear(const int year, const int month, const int day, const bool iso) {
+
+ // 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 = 0, WeekNumber = 0;
+
+ 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;
+ }
+ }
+
+ if (!iso && (WeekNumber == 1 && month == 12)) {
+ WeekNumber = 53;
+ }
+
+ return WeekNumber;
+}
+
+
+} // utility
+} // vmime