1 /* DateType.java --
2    Copyright (C) 2006  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 package gnu.xml.validation.datatype;
39 
40 import java.util.Calendar;
41 import java.util.GregorianCalendar;
42 import java.util.TimeZone;
43 import javax.xml.XMLConstants;
44 import javax.xml.namespace.QName;
45 import org.relaxng.datatype.DatatypeException;
46 import org.relaxng.datatype.ValidationContext;
47 
48 /**
49  * The XML Schema date type.
50  *
51  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
52  */
53 final class DateType
54   extends AtomicSimpleType
55 {
56 
57   static final int[] CONSTRAINING_FACETS = {
58     Facet.PATTERN,
59     Facet.ENUMERATION,
60     Facet.WHITESPACE,
61     Facet.MAX_INCLUSIVE,
62     Facet.MAX_EXCLUSIVE,
63     Facet.MIN_INCLUSIVE,
64     Facet.MIN_EXCLUSIVE
65   };
66 
DateType()67   DateType()
68   {
69     super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "date"),
70           TypeLibrary.ANY_SIMPLE_TYPE);
71   }
72 
getConstrainingFacets()73   public int[] getConstrainingFacets()
74   {
75     return CONSTRAINING_FACETS;
76   }
77 
checkValid(String value, ValidationContext context)78   public void checkValid(String value, ValidationContext context)
79     throws DatatypeException
80   {
81     super.checkValid(value, context);
82     int len = value.length();
83     int state = 0;
84     int start = 0;
85     for (int i = 0; i < len; i++)
86       {
87         char c = value.charAt(i);
88         if (c == '-' && i == 0)
89           {
90             start++;
91             continue;
92           }
93         if (c >= 0x30 && c <= 0x39)
94           continue;
95         switch (state)
96           {
97           case 0: // year
98             if (c == '-')
99               {
100                 String year = value.substring(start, i);
101                 if ("0000".equals(year) || year.length() < 4)
102                   throw new DatatypeException(i, "invalid date value");
103                 state = 1;
104                 start = i + 1;
105                 continue;
106               }
107             break;
108           case 1: // month
109             if (c == '-')
110               {
111                 if (i - start != 2)
112                   throw new DatatypeException(i, "invalid date value");
113                 state = 2;
114                 start = i + 1;
115                 continue;
116               }
117             break;
118           }
119                   throw new DatatypeException(i, "invalid date value");
120       }
121     switch (state)
122       {
123       case 2: // day
124         if (len - start != 2)
125           throw new DatatypeException("invalid date value");
126         break;
127       default:
128         throw new DatatypeException("invalid date value");
129       }
130   }
131 
createValue(String value, ValidationContext context)132   public Object createValue(String value, ValidationContext context) {
133     int len = value.length();
134     int state = 0;
135     int start = 0;
136     Calendar cal = new GregorianCalendar();
137     cal.set(Calendar.HOUR, 0);
138     cal.set(Calendar.MINUTE, 0);
139     cal.set(Calendar.SECOND, 0);
140     try
141       {
142         for (int i = 0; i < len; i++)
143           {
144             char c = value.charAt(i);
145             if (c == '-' && i == 0)
146               {
147                 start++;
148                 continue;
149               }
150             if (c >= 0x30 && c <= 0x39)
151               continue;
152             switch (state)
153               {
154               case 0: // year
155                 if (c == '-')
156                   {
157                     cal.set(Calendar.YEAR,
158                             Integer.parseInt(value.substring(0, i)));
159                     state = 1;
160                     start = i + 1;
161                     continue;
162                   }
163                 break;
164               case 1: // month
165                 if (c == '-')
166                   {
167                     cal.set(Calendar.MONTH,
168                             Integer.parseInt(value.substring(start, i)));
169                     state = 2;
170                     start = i + 1;
171                     continue;
172                   }
173                 break;
174               case 2: // day
175                 if (c == 'T')
176                   {
177                     cal.set(Calendar.DATE,
178                             Integer.parseInt(value.substring(start, i)));
179                     state = 7;
180                     start = i + 1;
181                     continue;
182                   }
183                 break;
184               }
185           }
186         // end of input
187         if (len - start > 0 && state == 7)
188           {
189             // Timezone
190             String timezone = value.substring(len - start);
191             int i = timezone.indexOf(':');
192             if (i == -1)
193               {
194                 if ("Z".equals(timezone))
195                   timezone = "UTC";
196                 TimeZone tz = TimeZone.getTimeZone(timezone);
197                 if (tz == null)
198                   return null;
199                 cal.set(Calendar.ZONE_OFFSET, tz.getRawOffset());
200               }
201             else
202               {
203                 String tzh = timezone.substring(0, i);
204                 String tzm = timezone.substring(i + 1);
205                 int offset = Integer.parseInt(tzh) * 360000;
206                 if (offset < 0)
207                   offset -= Integer.parseInt(tzm) * 60000;
208                 else
209                   offset += Integer.parseInt(tzm) * 60000;
210                 cal.set(Calendar.ZONE_OFFSET, offset);
211               }
212           }
213         return cal.getTime();
214       }
215     catch (NumberFormatException e)
216       {
217         return null;
218       }
219   }
220 
221 }
222