1
|
|
/*
|
2
|
|
* JBind
|
3
|
|
*
|
4
|
|
* Copyright (c) by Stefan Wachter. All rights reserved.
|
5
|
|
*
|
6
|
|
* Usage, modification, and redistribution is subject to license terms that are
|
7
|
|
* available at 'http://www.jbind.org'. The JBind license is like the
|
8
|
|
* 'Apache Software License V 1.1'.
|
9
|
|
*/
|
10
|
|
package org.jbind.xml.instance.data;
|
11
|
|
|
12
|
|
import java.math.BigDecimal;
|
13
|
|
|
14
|
|
import org.jbind.util.other.StrBuffer;
|
15
|
|
import org.jbind.xml.core.data.IDateTime;
|
16
|
|
import org.jbind.xml.core.data.IDurationBase;
|
17
|
|
import org.jbind.xml.core.data.ITime;
|
18
|
|
import org.jbind.xml.core.data.ITimeZone;
|
19
|
|
|
20
|
|
public class TimeHelper {
|
21
|
|
|
22
|
0
|
private TimeHelper() {}
|
23
|
|
|
24
|
4
|
public static ITime add(ITime aTime, ITimeZone aDuration) {
|
25
|
4
|
int tmp, carry;
|
26
|
4
|
int s = -aDuration.getSign();
|
27
|
|
|
28
|
4
|
BigDecimal fraction = null;
|
29
|
4
|
if ((null != aTime.getFraction()) && (null != aDuration.getFraction())) {
|
30
|
0
|
fraction = (s == 1) ? aTime.getFraction().add(aDuration.getFraction()) : aTime.getFraction().subtract(aDuration.getFraction());
|
31
|
4
|
} else if (null != aTime.getFraction()) {
|
32
|
4
|
fraction = aTime.getFraction();
|
33
|
0
|
} else if (null != aDuration.getFraction()) {
|
34
|
0
|
fraction = (s == 1) ? aDuration.getFraction().negate() : aDuration.getFraction();
|
35
|
|
}
|
36
|
4
|
BigDecimal one = new BigDecimal("1");
|
37
|
4
|
if (fraction.compareTo(one) > 0) {
|
38
|
0
|
fraction = fraction.subtract(one);
|
39
|
0
|
carry = 1;
|
40
|
4
|
} else if (fraction.signum() < 0) {
|
41
|
0
|
fraction = fraction.add(one);
|
42
|
0
|
carry = -1;
|
43
|
|
} else {
|
44
|
4
|
carry = 0;
|
45
|
|
}
|
46
|
|
|
47
|
4
|
tmp = aTime.getSecond() + s * aDuration.getSeconds() + carry;
|
48
|
4
|
carry = fQuotient(tmp, 60);
|
49
|
4
|
int second = mod(tmp, 60, carry);
|
50
|
|
|
51
|
4
|
tmp = aTime.getMinute() + s * aDuration.getMinutes() + carry;
|
52
|
4
|
carry = fQuotient(tmp, 60);
|
53
|
4
|
int minute = mod(tmp, 60, carry);
|
54
|
|
|
55
|
4
|
tmp = aTime.getHour() + s * aDuration.getHours() + carry;
|
56
|
4
|
carry = fQuotient(tmp, 24);
|
57
|
4
|
int hour = mod(tmp, 24, carry);
|
58
|
|
|
59
|
4
|
return new Time(hour, minute, second, fraction, aTime.hadTimeZone());
|
60
|
|
}
|
61
|
|
|
62
|
0
|
public static IDateTime add(IDateTime aDateTime, IDurationBase aDuration) {
|
63
|
0
|
return addOrSubtract(aDateTime, aDuration, true);
|
64
|
|
}
|
65
|
|
|
66
|
9
|
public static IDateTime subtract(IDateTime aDateTime, IDurationBase aDuration) {
|
67
|
9
|
return addOrSubtract(aDateTime, aDuration, false);
|
68
|
|
}
|
69
|
|
|
70
|
9
|
private static IDateTime addOrSubtract(IDateTime aDateTime, IDurationBase aDuration, boolean anAddNotSubtract) {
|
71
|
9
|
int s = aDateTime.getSign() * aDuration.getSign();
|
72
|
9
|
if (!anAddNotSubtract) {
|
73
|
9
|
s *= -1;
|
74
|
|
}
|
75
|
9
|
int tmp, carry;
|
76
|
|
|
77
|
9
|
tmp = aDateTime.getMonth() + s * aDuration.getMonths();
|
78
|
9
|
carry = fQuotient(tmp, 1, 13);
|
79
|
9
|
int month = modulo(tmp, 1, 13);
|
80
|
|
|
81
|
9
|
int year = aDateTime.getYear() + s * aDuration.getYears() + carry;
|
82
|
9
|
if (year == 0) {
|
83
|
0
|
year += s;
|
84
|
|
}
|
85
|
|
|
86
|
9
|
BigDecimal fraction = null;
|
87
|
9
|
if ((null != aDateTime.getFraction()) && (null != aDuration.getFraction())) {
|
88
|
0
|
fraction = (s == 1) ? aDateTime.getFraction().add(aDuration.getFraction()) : aDateTime.getFraction().subtract(aDuration.getFraction());
|
89
|
9
|
} else if (null != aDateTime.getFraction()) {
|
90
|
0
|
fraction = aDateTime.getFraction();
|
91
|
9
|
} else if (null != aDuration.getFraction()) {
|
92
|
0
|
fraction = (s == 1) ? aDuration.getFraction().negate() : aDuration.getFraction();
|
93
|
|
}
|
94
|
9
|
if (null != fraction) {
|
95
|
0
|
BigDecimal one = new BigDecimal("1");
|
96
|
0
|
if (fraction.compareTo(one) > 0) {
|
97
|
0
|
fraction = fraction.subtract(one);
|
98
|
0
|
carry = 1;
|
99
|
0
|
} else if (fraction.signum() < 0) {
|
100
|
0
|
fraction = fraction.add(one);
|
101
|
0
|
carry = -1;
|
102
|
|
} else {
|
103
|
0
|
carry = 0;
|
104
|
|
}
|
105
|
|
}
|
106
|
|
|
107
|
9
|
tmp = aDateTime.getSecond() + s * aDuration.getSeconds() + carry;
|
108
|
9
|
carry = fQuotient(tmp, 60);
|
109
|
9
|
int second = mod(tmp, 60, carry);
|
110
|
|
|
111
|
9
|
tmp = aDateTime.getMinute() + s * aDuration.getMinutes() + carry;
|
112
|
9
|
carry = fQuotient(tmp, 60);
|
113
|
9
|
int minute = mod(tmp, 60, carry);
|
114
|
|
|
115
|
9
|
tmp = aDateTime.getHour() + s * aDuration.getHours() + carry;
|
116
|
9
|
carry = fQuotient(tmp, 24);
|
117
|
9
|
int hour = mod(tmp, 24, carry);
|
118
|
|
|
119
|
9
|
int tmpDay;
|
120
|
9
|
if (aDateTime.getDay() > maxDayInMonthFor(year, month)) {
|
121
|
0
|
tmpDay = maxDayInMonthFor(year, month);
|
122
|
|
} else {
|
123
|
9
|
tmpDay = aDateTime.getDay();
|
124
|
|
}
|
125
|
|
|
126
|
9
|
int day = tmpDay + s * aDuration.getDays() + carry;
|
127
|
|
|
128
|
9
|
while (true) {
|
129
|
11
|
if (day < 1) {
|
130
|
1
|
day = day + maxDayInMonthFor(year, month - 1);
|
131
|
1
|
carry = -1;
|
132
|
10
|
} else if (day > maxDayInMonthFor(year, month)) {
|
133
|
1
|
day = day - maxDayInMonthFor(year, month);
|
134
|
1
|
carry = 1;
|
135
|
|
} else {
|
136
|
9
|
break;
|
137
|
|
}
|
138
|
2
|
tmp = month + carry;
|
139
|
2
|
month = modulo(tmp, 1, 13);
|
140
|
2
|
year = year + fQuotient(tmp, 1, 13);
|
141
|
2
|
if (year == 0) {
|
142
|
0
|
year += s;
|
143
|
|
}
|
144
|
|
}
|
145
|
|
|
146
|
9
|
int sign;
|
147
|
9
|
if (year > 0) {
|
148
|
9
|
sign = aDateTime.getSign();
|
149
|
|
} else {
|
150
|
0
|
sign = -aDateTime.getSign();
|
151
|
0
|
year = -year;
|
152
|
|
}
|
153
|
|
|
154
|
9
|
return new DateTime(sign, year, month, day, hour, minute, second, fraction, aDateTime.hadTimeZone());
|
155
|
|
}
|
156
|
|
|
157
|
|
/**
|
158
|
|
* Given {year,month} computes maximum
|
159
|
|
* number of days for given month
|
160
|
|
*
|
161
|
|
* @param year
|
162
|
|
* @param month
|
163
|
|
* @return integer containg the number of days in a given month
|
164
|
|
*/
|
165
|
46
|
public static int maxDayInMonthFor(int aYear, int aMonth) {
|
166
|
46
|
int month = modulo(aMonth, 1, 13);
|
167
|
46
|
int year = aYear + fQuotient(aMonth, 1, 13);
|
168
|
|
|
169
|
|
//validate days
|
170
|
46
|
if ((month == 4) || (month == 6) || (month == 9) || (month == 11)) {
|
171
|
6
|
return 30;
|
172
|
40
|
} else if (month == 2) {
|
173
|
9
|
if (isLeapYear(year)) {
|
174
|
6
|
return 29;
|
175
|
|
} else {
|
176
|
3
|
return 28;
|
177
|
|
}
|
178
|
|
} else {
|
179
|
31
|
return 31;
|
180
|
|
}
|
181
|
|
}
|
182
|
|
|
183
|
9
|
private static boolean isLeapYear(int year) {
|
184
|
9
|
if (year == 0) {
|
185
|
0
|
return false;
|
186
|
|
}
|
187
|
|
//REVISIT: should we take care about Julian calendar?
|
188
|
9
|
return ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)));
|
189
|
|
}
|
190
|
|
|
191
|
0
|
private static int modulo(int a, int b) {
|
192
|
0
|
return a - fQuotient(a, b) * b;
|
193
|
|
}
|
194
|
|
|
195
|
|
//
|
196
|
|
// help function described in W3C PR Schema [E Adding durations to dateTimes]
|
197
|
|
//
|
198
|
96
|
private static int mod(int a, int b, int quotient) {
|
199
|
|
//modulo(a, b) = a - fQuotient(a,b)*b
|
200
|
96
|
return (a - quotient * b);
|
201
|
|
}
|
202
|
|
|
203
|
|
//
|
204
|
|
// help function described in W3C PR Schema [E Adding durations to dateTimes]
|
205
|
|
//
|
206
|
153
|
private static int fQuotient(int a, int b) {
|
207
|
|
//fQuotient(a, b) = the greatest integer less than or equal to a/b
|
208
|
153
|
return (int)Math.floor((float)a / b);
|
209
|
|
}
|
210
|
|
|
211
|
|
//
|
212
|
|
// help function described in W3C PR Schema [E Adding durations to dateTimes]
|
213
|
|
//
|
214
|
57
|
private static int modulo(int temp, int low, int high) {
|
215
|
|
//modulo(a - low, high - low) + low
|
216
|
57
|
int a = temp - low;
|
217
|
57
|
int b = high - low;
|
218
|
57
|
return (mod(a, b, fQuotient(a, b)) + low);
|
219
|
|
}
|
220
|
|
|
221
|
|
//
|
222
|
|
// help function described in W3C PR Schema [E Adding durations to dateTimes]
|
223
|
|
//
|
224
|
57
|
private static int fQuotient(int temp, int low, int high) {
|
225
|
|
//fQuotient(a - low, high - low)
|
226
|
|
|
227
|
57
|
return fQuotient(temp - low, high - low);
|
228
|
|
}
|
229
|
|
|
230
|
3
|
public static void output(int anInt, int aLength, StrBuffer aStringBuffer) {
|
231
|
3
|
StrBuffer b = new StrBuffer();
|
232
|
3
|
int x = anInt;
|
233
|
3
|
for (int i = 0; i < aLength; i++, x /= 10) {
|
234
|
6
|
b.append((char)('0' + x % 10));
|
235
|
|
}
|
236
|
|
assert 0 == x;
|
237
|
3
|
for (int i = b.length(); --i >= 0; ) {
|
238
|
6
|
aStringBuffer.append(b.charAt(i));
|
239
|
|
}
|
240
|
|
}
|
241
|
|
|
242
|
6
|
public static void output(int anInt, StrBuffer aStrBuffer) {
|
243
|
6
|
int x = anInt;
|
244
|
6
|
StrBuffer b = new StrBuffer();
|
245
|
6
|
do {
|
246
|
9
|
b.append((char)('0' + x % 10));
|
247
|
9
|
x /= 10;
|
248
|
9
|
} while (x != 0);
|
249
|
6
|
for (int i = b.length(); --i >= 0; ) {
|
250
|
9
|
aStrBuffer.append(b.charAt(i));
|
251
|
|
}
|
252
|
|
}
|
253
|
|
}
|
254
|
|
|