1 #include "globus_wsrf_core_tools.h"
2
3 #include <math.h>
4 #include <assert.h>
5
6 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
7 static
8 long
9 fQuotient(double a, double b)
10 0 {
11 0 return (long) floor(a/b);
12 }
13 /* fQuotient() */
14
15 static
16 double
17 modulo(double a, double b)
18 0 {
19 0 return a - fQuotient(a,b) * b;
20 }
21 /* modulo() */
22
23 static
24 long
25 fQuotient3(double a, double low, double high)
26 0 {
27 0 return fQuotient(a - low, high - low);
28 }
29
30 static
31 double
32 modulo3(double a, double low, double high)
33 0 {
34 0 return modulo(a - low, high - low) + low;
35 }
36 /* modulo3() */
37
38 static
39 int
40 maximumDayInMonthFor(long yearValue, long monthValue)
41 0 {
42 0 long M = modulo3(monthValue, 1, 13);
43 0 long Y = yearValue + fQuotient3(monthValue, 1, 13);
44
45 0 switch (M)
46 {
47 case 1: case 3: case 5: case 7: case 8: case 10: case 12:
48 0 return 31;
49 case 4: case 6: case 9: case 11:
50 0 return 30;
51 case 2:
52 0 if ((modulo(Y, 400) == 0 || modulo(Y, 100) != 0) && modulo(Y, 4))
53 {
54 0 return 29;
55 }
56 else
57 {
58 0 return 28;
59 }
60 default:
61 0 assert(M > 0 && M < 13);
62 }
63 0 return -1;
64 }
65 /* maximumDayInMonthFor() */
66 #endif
67
68 /**
69 * Add a xsd:duration to an xsd:dateTime
70 * @ingroup globus_wsrf_core_types
71 * Modifies the @a date parameter to contain the result of adding the
72 * given @a duration to it.
73 *
74 * @param date
75 * Date to add to and modify.
76 * @param duration
77 * Duration to add to date.
78 * @retval GLOBUS_SUCCESS
79 * Success.
80 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
81 * Invalid parameter.
82 * @note This function implements the algorithm described in
83 * http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes with
84 * the following exceptions
85 * - uninitialized elements in the original @a date value are not detected
86 * - subsecond values in the date or duration are ignored.
87 * - timezones are not taken into account
88 */
89 globus_result_t
90 globus_wsrf_core_add_duration(
91 xsd_dateTime * date,
92 const xsd_duration * duration)
93 0 {
94 xsd_dateTime E;
95 long temp;
96 long tempDays;
97 long carry;
98
99 0 if (date == NULL || duration == NULL)
100 {
101 0 return GlobusSoapMessageErrorNullParam;
102 }
103
104 0 memset(&E, '\0', sizeof(xsd_dateTime));
105
106 /* Months */
107 0 temp = (date->tm_mon + 1) + duration->month;
108 0 E.tm_mon = modulo3(temp, 1, 13);
109 0 carry = fQuotient3(temp, 1, 13);
110 /* Years */
111 0 E.tm_year = (date->tm_year + 1900) + duration->year + carry;
112 /* Seconds */
113 0 temp = date->tm_sec + duration->sec;
114 0 E.tm_sec = modulo(temp, 60);
115 0 carry = fQuotient(temp, 60);
116 /* Minutes */
117 0 temp = date->tm_min + duration->min + carry;
118 0 E.tm_min = modulo(temp, 60);
119 0 carry = fQuotient(temp, 60);
120 /* Hours */
121 0 temp = date->tm_hour + duration->hour + carry;
122 0 E.tm_hour = modulo(temp, 24);
123 0 carry = fQuotient(temp, 24);
124 /* Days */
125 0 tempDays = maximumDayInMonthFor(E.tm_year, E.tm_mon);
126 0 if (date->tm_mday > tempDays)
127 {
128 ;
129 }
130 0 else if (date->tm_mday < 1)
131 {
132 0 tempDays = 1;
133 }
134 else
135 {
136 0 tempDays = date->tm_mday;
137 }
138 0 E.tm_mday = tempDays + duration->day + carry;
139
140 while (1)
141 {
142 0 if (E.tm_mday < 1)
143 {
144 0 E.tm_mday = E.tm_mday +
145 maximumDayInMonthFor(E.tm_year, E.tm_mon - 1);
146 0 carry = -1;
147 }
148 0 else if (E.tm_mday > maximumDayInMonthFor(E.tm_year, E.tm_mon))
149 {
150 0 E.tm_mday = E.tm_mday - maximumDayInMonthFor(
151 E.tm_year, E.tm_mon);
152 0 carry = 1;
153 }
154 else
155 {
156 0 break;
157 }
158 0 temp = E.tm_mon + carry;
159 0 E.tm_mon = modulo3(temp, 1, 13);
160 0 E.tm_year = E.tm_mon + fQuotient3(temp, 1, 13);
161 0 }
162
163 /* Adjust values to be struct tm */
164 0 E.tm_year -= 1900;
165 0 E.tm_mon -= 1;
166
167 0 memcpy(date, &E, sizeof(struct tm));
168
169 0 return GLOBUS_SUCCESS;
170 }