2
* The Apache Software License, Version 1.1
5
* Copyright (c) 1999-2002 The Apache Software Foundation. All rights
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in
17
* the documentation and/or other materials provided with the
20
* 3. The end-user documentation included with the redistribution,
21
* if any, must include the following acknowledgment:
22
* "This product includes software developed by the
23
* Apache Software Foundation (http://www.apache.org/)."
24
* Alternately, this acknowledgment may appear in the software itself,
25
* if and wherever such third-party acknowledgments normally appear.
27
* 4. The names "Xerces" and "Apache Software Foundation" must
28
* not be used to endorse or promote products derived from this
29
* software without prior written permission. For written
30
* permission, please contact apache@apache.org.
32
* 5. Products derived from this software may not be called "Apache",
33
* nor may "Apache" appear in their name, without prior written
34
* permission of the Apache Software Foundation.
36
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48
* ====================================================================
50
* This software consists of voluntary contributions made by many
51
* individuals on behalf of the Apache Software Foundation and was
52
* originally based on software copyright (c) 2001, International
53
* Business Machines, Inc., http://www.apache.org. For more
54
* information on the Apache Software Foundation, please see
55
* <http://www.apache.org/>.
2
* Copyright 1999-2002,2004,2005 The Apache Software Foundation.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
58
17
package org.apache.xerces.impl.dv.xs;
19
import java.math.BigDecimal;
20
import java.math.BigInteger;
22
import javax.xml.datatype.DatatypeConstants;
23
import javax.xml.datatype.Duration;
60
25
import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
61
26
import org.apache.xerces.impl.dv.ValidationContext;
64
* Validator for <duration> datatype (W3C Schema Datatypes)
29
* Validator for <duration> datatype (W3C Schema Datatypes)
66
33
* @author Elena Litani
67
34
* @author Gopal Sharma, SUN Microsystem Inc.
68
* @version $Id: DurationDV.java,v 1.8 2003/12/11 15:08:25 sandygao Exp $
35
* @version $Id: DurationDV.java 320310 2005-05-06 15:31:15Z ankitp $
70
37
public class DurationDV extends AbstractDateTimeDV {
39
public static final int DURATION_TYPE = 0;
40
public static final int YEARMONTHDURATION_TYPE = 1;
41
public static final int DAYTIMEDURATION_TYPE = 2;
72
42
// order-relation on duration is a partial order. The dates below are used to
73
43
// for comparison of 2 durations, based on the fact that
74
44
// duration x and y is x<=y iff s+x<=s+y
75
45
// see 3.2.6 duration W3C schema datatype specs
77
47
// the dates are in format: {CCYY,MM,DD, H, S, M, MS, timezone}
78
private final static int[][] DATETIMES= {
79
{1696, 9, 1, 0, 0, 0, 0, 'Z'},
80
{1697, 2, 1, 0, 0, 0, 0, 'Z'},
81
{1903, 3, 1, 0, 0, 0, 0, 'Z'},
82
{1903, 7, 1, 0, 0, 0, 0, 'Z'}};
48
private final static DateTimeData[] DATETIMES= {
49
new DateTimeData(1696, 9, 1, 0, 0, 0, 'Z', null, true, null),
50
new DateTimeData(1697, 2, 1, 0, 0, 0, 'Z', null, true, null),
51
new DateTimeData(1903, 3, 1, 0, 0, 0, 'Z', null, true, null),
52
new DateTimeData(1903, 7, 1, 0, 0, 0, 'Z', null, true, null)};
84
54
public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException{
86
return new DateTimeData(parse(content), this);
56
return parse(content, DURATION_TYPE);
87
57
} catch (Exception ex) {
88
58
throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "duration"});
93
63
* Parses, validates and computes normalized version of duration object
95
65
* @param str The lexical representation of duration object PnYn MnDTnH nMnS
96
* @param date uninitialized date object
97
67
* @return normalized date representation
98
68
* @exception SchemaDateTimeException Invalid lexical representation
100
protected int[] parse(String str) throws SchemaDateTimeException{
70
protected DateTimeData parse(String str, int durationType) throws SchemaDateTimeException{
101
71
int len = str.length();
102
int[] date=new int[TOTAL_SIZE];
72
DateTimeData date= new DateTimeData(str, this);
105
75
char c=str.charAt(start++);
106
76
if ( c!='P' && c!='-' ) {
107
77
throw new SchemaDateTimeException();
110
date[utc]=(c=='-')?'-':0;
80
date.utc=(c=='-')?'-':0;
111
81
if ( c=='-' && str.charAt(start++)!='P' ) {
112
82
throw new SchemaDateTimeException();
117
87
//negative duration
118
if ( date[utc]=='-' ) {
88
if ( date.utc=='-' ) {
122
92
//at least one number and designator must be seen after P
123
93
boolean designator = false;
125
95
int endDate = indexOf (str, start, len, 'T');
126
96
if ( endDate == -1 ) {
99
else if (durationType == YEARMONTHDURATION_TYPE) {
100
throw new SchemaDateTimeException();
130
104
int end = indexOf (str, start, endDate, 'Y');
107
if (durationType == DAYTIMEDURATION_TYPE) {
108
throw new SchemaDateTimeException();
133
date[CY]=negate * parseInt(str,start,end);
112
date.year=negate * parseInt(str,start,end);
135
114
designator = true;
138
117
end = indexOf (str, start, endDate, 'M');
120
if (durationType == DAYTIMEDURATION_TYPE) {
121
throw new SchemaDateTimeException();
141
date[M]=negate * parseInt(str,start,end);
125
date.month=negate * parseInt(str,start,end);
143
127
designator = true;
146
130
end = indexOf (str, start, endDate, 'D');
133
if(durationType == YEARMONTHDURATION_TYPE) {
134
throw new SchemaDateTimeException();
149
date[D]=negate * parseInt(str,start,end);
138
date.day=negate * parseInt(str,start,end);
151
140
designator = true;
154
143
if ( len == endDate && start!=len ) {
155
144
throw new SchemaDateTimeException();
157
146
if ( len !=endDate ) {
159
148
//scan hours, minutes, seconds
160
149
//REVISIT: can any item include a decimal fraction or only seconds?
163
152
end = indexOf (str, ++start, len, 'H');
166
date[h]=negate * parseInt(str,start,end);
155
date.hour=negate * parseInt(str,start,end);
168
157
designator = true;
171
160
end = indexOf (str, start, len, 'M');
174
date[m]=negate * parseInt(str,start,end);
163
date.minute=negate * parseInt(str,start,end);
176
165
designator = true;
179
168
end = indexOf (str, start, len, 'S');
182
int mlsec = indexOf (str, start, end, '.');
184
date[s] = negate * parseInt (str, start, mlsec);
185
date[ms] = negate * parseInt (str, mlsec+1, end);
188
date[s]=negate * parseInt(str, start,end);
171
date.second = negate * parseSecond(str, start, end);
191
173
designator = true;
295
278
resetDateObj(duration);
296
279
//add months (may be modified additionaly below)
297
int temp = addto[M] + date[M];
298
duration[M] = modulo (temp, 1, 13);
280
int temp = addto.month + date.month;
281
duration.month = modulo (temp, 1, 13);
299
282
int carry = fQuotient (temp, 1, 13);
301
284
//add years (may be modified additionaly below)
302
duration[CY]=addto[CY] + date[CY] + carry;
285
duration.year=addto.year + date.year + carry;
305
temp = addto[s] + date[s];
306
carry = fQuotient (temp, 60);
307
duration[s] = mod(temp, 60, carry);
288
double dtemp = addto.second + date.second;
289
carry = (int)Math.floor(dtemp/60);
290
duration.second = dtemp - carry*60;
310
temp = addto[m] +date[m] + carry;
293
temp = addto.minute +date.minute + carry;
311
294
carry = fQuotient (temp, 60);
312
duration[m]= mod(temp, 60, carry);
295
duration.minute= mod(temp, 60, carry);
315
temp = addto[h] + date[h] + carry;
298
temp = addto.hour + date.hour + carry;
316
299
carry = fQuotient(temp, 24);
317
duration[h] = mod(temp, 24, carry);
320
duration[D]=addto[D] + date[D] + carry;
300
duration.hour = mod(temp, 24, carry);
303
duration.day=addto.day + date.day + carry;
324
temp=maxDayInMonthFor(duration[CY], duration[M]);
325
if ( duration[D] < 1 ) { //original duration was negative
326
duration[D] = duration[D] + maxDayInMonthFor(duration[CY], duration[M]-1);
307
temp=maxDayInMonthFor(duration.year, duration.month);
308
if ( duration.day < 1 ) { //original duration was negative
309
duration.day = duration.day + maxDayInMonthFor(duration.year, duration.month-1);
329
else if ( duration[D] > temp ) {
330
duration[D] = duration[D] - temp;
312
else if ( duration.day > temp ) {
313
duration.day = duration.day - temp;
336
temp = duration[M]+carry;
337
duration[M] = modulo(temp, 1, 13);
338
duration[CY] = duration[CY]+fQuotient(temp, 1, 13);
319
temp = duration.month+carry;
320
duration.month = modulo(temp, 1, 13);
321
duration.year = duration.year+fQuotient(temp, 1, 13);
345
protected String dateToString(int[] date) {
328
protected double parseSecond(String buffer, int start, int end)
329
throws NumberFormatException {
331
for (int i = start; i < end; i++) {
332
char ch = buffer.charAt(i);
335
else if (ch > '9' || ch < '0')
336
throw new NumberFormatException("'" + buffer + "' has wrong format");
339
throw new NumberFormatException("'" + buffer + "' has wrong format");
341
return Double.parseDouble(buffer.substring(start, end));
344
protected String dateToString(DateTimeData date) {
346
345
StringBuffer message = new StringBuffer(30);
346
if ( date.year<0 || date.month<0 || date.day<0
347
|| date.hour<0 || date.minute<0 || date.second<0) {
349
348
message.append('-');
352
350
message.append('P');
353
message.append(negate * date[CY]);
351
message.append((date.year < 0?-1:1) * date.year);
354
352
message.append('Y');
355
message.append(negate * date[M]);
353
message.append((date.month < 0?-1:1) * date.month);
356
354
message.append('M');
357
message.append(negate * date[D]);
355
message.append((date.day < 0?-1:1) * date.day);
358
356
message.append('D');
359
357
message.append('T');
360
message.append(negate * date[h]);
358
message.append((date.hour < 0?-1:1) * date.hour);
361
359
message.append('H');
362
message.append(negate * date[m]);
360
message.append((date.minute < 0?-1:1) * date.minute);
363
361
message.append('M');
364
message.append(negate * date[s]);
366
message.append(negate * date[ms]);
362
message.append((date.second < 0?-1:1) * date.second);
367
363
message.append('S');
369
365
return message.toString();
368
protected Duration getDuration(DateTimeData date) {
370
if ( date.year<0 || date.month<0 || date.day<0
371
|| date.hour<0 || date.minute<0 || date.second<0) {
374
return factory.newDuration(sign == 1,
375
date.year != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.year):null,
376
date.month != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.month):null,
377
date.day != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.day):null,
378
date.hour != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.hour):null,
379
date.minute != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.minute):null,
380
date.second != DatatypeConstants.FIELD_UNDEFINED?new BigDecimal(String.valueOf(sign*date.second)):null);