Source Code Cross Referenced for DateUtil.java in  » GIS » GeoTools-2.4.1 » org » geotools » feature » iso » attribute » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.feature.iso.attribute 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *    Geotools2 - OpenSource mapping toolkit
0003:         *    http://geotools.org
0004:         *    (C) 2002, Geotools Project Managment Committee (PMC)
0005:         *
0006:         *    This library is free software; you can redistribute it and/or
0007:         *    modify it under the terms of the GNU Lesser General Public
0008:         *    License as published by the Free Software Foundation;
0009:         *    version 2.1 of the License.
0010:         *
0011:         *    This library is distributed in the hope that it will be useful,
0012:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014:         *    Lesser General Public License for more details.
0015:         *
0016:         */
0017:        /*
0018:         Copyright (c) 2002-2004, Dennis M. Sosnoski.
0019:         All rights reserved.
0020:         Redistribution and use in source and binary forms, with or without modification,
0021:         are permitted provided that the following conditions are met:
0022:         * Redistributions of source code must retain the above copyright notice, this
0023:         list of conditions and the following disclaimer.
0024:         * Redistributions in binary form must reproduce the above copyright notice,
0025:         this list of conditions and the following disclaimer in the documentation
0026:         and/or other materials provided with the distribution.
0027:         * Neither the name of JiBX nor the names of its contributors may be used
0028:         to endorse or promote products derived from this software without specific
0029:         prior written permission.
0030:         THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
0031:         ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0032:         WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0033:         DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
0034:         ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0035:         (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0036:         LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
0037:         ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0038:         (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0039:         SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0040:         */
0041:        package org.geotools.feature.iso.attribute;
0042:
0043:        import java.sql.Time;
0044:        import java.sql.Timestamp;
0045:        import java.util.ArrayList;
0046:        import java.util.Date;
0047:        import java.util.List;
0048:        import java.util.TimeZone;
0049:
0050:        /**
0051:         * Utility class supplying static methods. Date serialization is based on the
0052:         * algorithms published by Peter Baum (http://www.capecod.net/~pbaum). All
0053:         * date handling is done according to the W3C Schema specification, which uses
0054:         * a proleptic Gregorian calendar with no year 0. Note that this differs from
0055:         * the Java date handling, which uses a discontinuous Gregorian calendar.
0056:         *
0057:         * @author Dennis M. Sosnoski
0058:         * @version 1.0
0059:         */
0060:        public abstract class DateUtil {
0061:            /** Number of milliseconds in a minute. */
0062:            private static final int MSPERMINUTE = 60000;
0063:
0064:            /** Number of milliseconds in an hour. */
0065:            private static final int MSPERHOUR = MSPERMINUTE * 60;
0066:
0067:            /** Number of milliseconds in a day. */
0068:            private static final int MSPERDAY = MSPERHOUR * 24;
0069:
0070:            /** Number of milliseconds in a day as a long. */
0071:            private static final long LMSPERDAY = (long) MSPERDAY;
0072:
0073:            /** Number of milliseconds in a (non-leap) year. */
0074:            private static final long MSPERYEAR = LMSPERDAY * 365;
0075:
0076:            /** Average number of milliseconds in a year within century. */
0077:            private static final long MSPERAVGYEAR = (long) (MSPERDAY * 365.25);
0078:
0079:            /** Number of milliseconds in a normal century. */
0080:            private static final long MSPERCENTURY = (long) (MSPERDAY * 36524.25);
0081:
0082:            /**
0083:             * Millisecond value of base time for internal representation. This gives
0084:             * the bias relative to January 1 of the year 1 C.E.
0085:             */
0086:            private static final long TIME_BASE = (1969 * MSPERYEAR)
0087:                    + (((1969 / 4) - 19 + 4) * LMSPERDAY);
0088:
0089:            /** Day number for start of month in non-leap year. */
0090:            private static final int[] MONTHS_NONLEAP = { 0, 31, 59, 90, 120,
0091:                    151, 181, 212, 243, 273, 304, 334, 365 };
0092:
0093:            /** Day number for start of month in non-leap year. */
0094:            private static final int[] MONTHS_LEAP = { 0, 31, 60, 91, 121, 152,
0095:                    182, 213, 244, 274, 305, 335, 366 };
0096:
0097:            /** Millisecond count prior to start of month in March 1-biased year. */
0098:            private static final long[] BIAS_MONTHMS = { 0 * LMSPERDAY,
0099:                    0 * LMSPERDAY, 0 * LMSPERDAY, 0 * LMSPERDAY,
0100:                    31 * LMSPERDAY, 61 * LMSPERDAY, 92 * LMSPERDAY,
0101:                    122 * LMSPERDAY, 153 * LMSPERDAY, 184 * LMSPERDAY,
0102:                    214 * LMSPERDAY, 245 * LMSPERDAY, 275 * LMSPERDAY,
0103:                    306 * LMSPERDAY, 337 * LMSPERDAY };
0104:
0105:            /** Pad character for base64 encoding. */
0106:            private static final char PAD_CHAR = '=';
0107:
0108:            /** Characters used in base64 encoding. */
0109:            private static final char[] s_base64Chars = { 'A', 'B', 'C', 'D',
0110:                    'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
0111:                    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
0112:                    'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
0113:                    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
0114:                    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
0115:
0116:            /** Values corresponding to characters used in bas64 encoding. */
0117:            private static final byte[] s_base64Values = new byte[128];
0118:
0119:            static {
0120:                for (int i = 0; i < s_base64Values.length; i++) {
0121:                    s_base64Values[i] = -1;
0122:                }
0123:
0124:                s_base64Values[PAD_CHAR] = 0;
0125:
0126:                for (int i = 0; i < s_base64Chars.length; i++) {
0127:                    s_base64Values[s_base64Chars[i]] = (byte) i;
0128:                }
0129:            }
0130:
0131:            /**
0132:             * Parse digits in text as integer value. This internal method is used for
0133:             * number values embedded within lexical structures. Only decimal digits
0134:             * can be included in the text range parsed.
0135:             *
0136:             * @param text text to be parsed
0137:             * @param offset starting offset in text
0138:             * @param length number of digits to be parsed
0139:             *
0140:             * @return converted positive integer value
0141:             *
0142:             * @throws IllegalArgumentException on parse error
0143:             */
0144:            private static int parseDigits(String text, int offset, int length)
0145:                    throws IllegalArgumentException {
0146:                // check if overflow a potential problem
0147:                int value = 0;
0148:
0149:                if (length > 9) {
0150:                    // use library parse code for potential overflow
0151:                    try {
0152:                        value = Integer.parseInt(text.substring(offset, offset
0153:                                + length));
0154:                    } catch (NumberFormatException ex) {
0155:                        throw new IllegalArgumentException(ex.getMessage());
0156:                    }
0157:                } else {
0158:                    // parse with no overflow worries
0159:                    int limit = offset + length;
0160:
0161:                    while (offset < limit) {
0162:                        char chr = text.charAt(offset++);
0163:
0164:                        if ((chr >= '0') && (chr <= '9')) {
0165:                            value = (value * 10) + (chr - '0');
0166:                        } else {
0167:                            throw new IllegalArgumentException(
0168:                                    "Non-digit in number value");
0169:                        }
0170:                    }
0171:                }
0172:
0173:                return value;
0174:            }
0175:
0176:            /**
0177:             * Parse integer value from text. Integer values are parsed with optional
0178:             * leading sign flag, followed by any number of digits.
0179:             *
0180:             * @param text text to be parsed
0181:             *
0182:             * @return converted integer value
0183:             *
0184:             * @throws IllegalArgumentException on parse error
0185:             */
0186:            public static int parseInt(String text)
0187:                    throws IllegalArgumentException {
0188:                // make sure there's text to be processed
0189:                text = text.trim();
0190:
0191:                int offset = 0;
0192:                int limit = text.length();
0193:
0194:                if (limit == 0) {
0195:                    throw new IllegalArgumentException("Empty number value");
0196:                }
0197:
0198:                // check leading sign present in text
0199:                boolean negate = false;
0200:                char chr = text.charAt(0);
0201:
0202:                if (chr == '-') {
0203:                    if (limit > 9) {
0204:                        // special case to make sure maximum negative value handled
0205:                        try {
0206:                            return Integer.parseInt(text);
0207:                        } catch (NumberFormatException ex) {
0208:                            throw new IllegalArgumentException(ex.getMessage());
0209:                        }
0210:                    } else {
0211:                        negate = true;
0212:                        offset++;
0213:                    }
0214:                } else if (chr == '+') {
0215:                    offset++;
0216:                }
0217:
0218:                if (offset >= limit) {
0219:                    throw new IllegalArgumentException("Invalid number format");
0220:                }
0221:
0222:                // handle actual value conversion
0223:                int value = parseDigits(text, offset, limit - offset);
0224:
0225:                if (negate) {
0226:                    return -value;
0227:                } else {
0228:                    return value;
0229:                }
0230:            }
0231:
0232:            /**
0233:             * Serialize int value to text.
0234:             *
0235:             * @param value int value to be serialized
0236:             *
0237:             * @return text representation of value
0238:             */
0239:            public static String serializeInt(int value) {
0240:                return Integer.toString(value);
0241:            }
0242:
0243:            /**
0244:             * Parse long value from text. Long values are parsed with optional leading
0245:             * sign flag, followed by any number of digits.
0246:             *
0247:             * @param text text to be parsed
0248:             *
0249:             * @return converted long value
0250:             *
0251:             * @throws IllegalArgumentException on parse error
0252:             */
0253:            public static long parseLong(String text)
0254:                    throws IllegalArgumentException {
0255:                // make sure there's text to be processed
0256:                text = text.trim();
0257:
0258:                int offset = 0;
0259:                int limit = text.length();
0260:
0261:                if (limit == 0) {
0262:                    throw new IllegalArgumentException("Empty number value");
0263:                }
0264:
0265:                // check leading sign present in text
0266:                boolean negate = false;
0267:                char chr = text.charAt(0);
0268:
0269:                if (chr == '-') {
0270:                    negate = true;
0271:                    offset++;
0272:                } else if (chr == '+') {
0273:                    offset++;
0274:                }
0275:
0276:                if (offset >= limit) {
0277:                    throw new IllegalArgumentException("Invalid number format");
0278:                }
0279:
0280:                // check if overflow a potential problem
0281:                long value = 0;
0282:
0283:                if ((limit - offset) > 18) {
0284:                    // pass text to library parse code (less leading +)
0285:                    if (chr == '+') {
0286:                        text = text.substring(1);
0287:                    }
0288:
0289:                    try {
0290:                        value = Long.parseLong(text);
0291:                    } catch (NumberFormatException ex) {
0292:                        throw new IllegalArgumentException(ex.getMessage());
0293:                    }
0294:                } else {
0295:                    // parse with no overflow worries
0296:                    while (offset < limit) {
0297:                        chr = text.charAt(offset++);
0298:
0299:                        if ((chr >= '0') && (chr <= '9')) {
0300:                            value = (value * 10) + (chr - '0');
0301:                        } else {
0302:                            throw new IllegalArgumentException(
0303:                                    "Non-digit in number value");
0304:                        }
0305:                    }
0306:
0307:                    if (negate) {
0308:                        value = -value;
0309:                    }
0310:                }
0311:
0312:                return value;
0313:            }
0314:
0315:            /**
0316:             * Serialize long value to text.
0317:             *
0318:             * @param value long value to be serialized
0319:             *
0320:             * @return text representation of value
0321:             */
0322:            public static String serializeLong(long value) {
0323:                return Long.toString(value);
0324:            }
0325:
0326:            /**
0327:             * Parse short value from text. Short values are parsed with optional
0328:             * leading sign flag, followed by any number of digits.
0329:             *
0330:             * @param text text to be parsed
0331:             *
0332:             * @return converted short value
0333:             *
0334:             * @throws IllegalArgumentException on parse error
0335:             */
0336:            public static short parseShort(String text)
0337:                    throws IllegalArgumentException {
0338:                int value = parseInt(text);
0339:
0340:                if ((value < Short.MIN_VALUE) || (value > Short.MAX_VALUE)) {
0341:                    throw new IllegalArgumentException("Value out of range");
0342:                }
0343:
0344:                return (short) value;
0345:            }
0346:
0347:            /**
0348:             * Serialize short value to text.
0349:             *
0350:             * @param value short value to be serialized
0351:             *
0352:             * @return text representation of value
0353:             */
0354:            public static String serializeShort(short value) {
0355:                return Short.toString(value);
0356:            }
0357:
0358:            /**
0359:             * Parse byte value from text. Byte values are parsed with optional leading
0360:             * sign flag, followed by any number of digits.
0361:             *
0362:             * @param text text to be parsed
0363:             *
0364:             * @return converted byte value
0365:             *
0366:             * @throws IllegalArgumentException on parse error
0367:             */
0368:            public static byte parseByte(String text)
0369:                    throws IllegalArgumentException {
0370:                int value = parseInt(text);
0371:
0372:                if ((value < Byte.MIN_VALUE) || (value > Byte.MAX_VALUE)) {
0373:                    throw new IllegalArgumentException("Value out of range");
0374:                }
0375:
0376:                return (byte) value;
0377:            }
0378:
0379:            /**
0380:             * Serialize byte value to text.
0381:             *
0382:             * @param value byte value to be serialized
0383:             *
0384:             * @return text representation of value
0385:             */
0386:            public static String serializeByte(byte value) {
0387:                return Byte.toString(value);
0388:            }
0389:
0390:            /**
0391:             * Parse boolean value from text. Boolean values are parsed as either text
0392:             * "true" and "false", or "1" and "0" numeric equivalents.
0393:             *
0394:             * @param text text to be parsed
0395:             *
0396:             * @return converted boolean value
0397:             *
0398:             * @throws IllegalArgumentException on parse error
0399:             */
0400:            public static boolean parseBoolean(String text)
0401:                    throws IllegalArgumentException {
0402:                text = text.trim();
0403:
0404:                if ("true".equals(text) || "1".equals(text)) {
0405:                    return true;
0406:                } else if ("false".equals(text) || "0".equals(text)) {
0407:                    return false;
0408:                } else {
0409:                    throw new IllegalArgumentException("Invalid boolean value");
0410:                }
0411:            }
0412:
0413:            /**
0414:             * Serialize boolean value to text. This serializes the value using the
0415:             * text representation as "true" or "false".
0416:             *
0417:             * @param value boolean value to be serialized
0418:             *
0419:             * @return text representation of value
0420:             */
0421:            public static String serializeBoolean(boolean value) {
0422:                return value ? "true" : "false";
0423:            }
0424:
0425:            /**
0426:             * Parse char value from text as unsigned 16-bit integer. Char values are
0427:             * parsed with optional leading sign flag, followed by any number of
0428:             * digits.
0429:             *
0430:             * @param text text to be parsed
0431:             *
0432:             * @return converted char value
0433:             *
0434:             * @throws IllegalArgumentException on parse error
0435:             */
0436:            public static char parseChar(String text)
0437:                    throws IllegalArgumentException {
0438:                int value = parseInt(text);
0439:
0440:                if ((value < Character.MIN_VALUE)
0441:                        || (value > Character.MAX_VALUE)) {
0442:                    throw new IllegalArgumentException("Value out of range");
0443:                }
0444:
0445:                return (char) value;
0446:            }
0447:
0448:            /**
0449:             * Serialize char value to text as unsigned 16-bit integer.
0450:             *
0451:             * @param value char value to be serialized
0452:             *
0453:             * @return text representation of value
0454:             */
0455:            public static String serializeChar(char value) {
0456:                return Integer.toString(value);
0457:            }
0458:
0459:            /**
0460:             * Parse char value from text as character value. This requires that the
0461:             * string must be of length one.
0462:             *
0463:             * @param text text to be parsed
0464:             *
0465:             * @return converted char value
0466:             *
0467:             * @throws IllegalArgumentException on parse error
0468:             */
0469:            public static char parseCharString(String text)
0470:                    throws IllegalArgumentException {
0471:                if (text.length() == 1) {
0472:                    return text.charAt(0);
0473:                } else {
0474:                    throw new IllegalArgumentException(
0475:                            "Input must be a single character");
0476:                }
0477:            }
0478:
0479:            /**
0480:             * Deserialize char value from text as character value. This requires that
0481:             * the string must be null or of length one.
0482:             *
0483:             * @param text text to be parsed (may be <code>null</code>)
0484:             *
0485:             * @return converted char value
0486:             *
0487:             * @throws IllegalArgumentException on parse error
0488:             */
0489:            public static char deserializeCharString(String text)
0490:                    throws IllegalArgumentException {
0491:                if (text == null) {
0492:                    return 0;
0493:                } else {
0494:                    return parseCharString(text);
0495:                }
0496:            }
0497:
0498:            /**
0499:             * Serialize char value to text as string of length one.
0500:             *
0501:             * @param value char value to be serialized
0502:             *
0503:             * @return text representation of value
0504:             */
0505:            public static String serializeCharString(char value) {
0506:                return String.valueOf(value);
0507:            }
0508:
0509:            /**
0510:             * Parse float value from text. This uses the W3C XML Schema format for
0511:             * floats, with the exception that it will accept "+NaN" and "-NaN" as
0512:             * valid formats. This is not in strict compliance with the specification,
0513:             * but is included for interoperability with other Java XML processing.
0514:             *
0515:             * @param text text to be parsed
0516:             *
0517:             * @return converted float value
0518:             *
0519:             * @throws IllegalArgumentException on parse error
0520:             */
0521:            public static float parseFloat(String text)
0522:                    throws IllegalArgumentException {
0523:                text = text.trim();
0524:
0525:                if ("-INF".equals(text)) {
0526:                    return Float.NEGATIVE_INFINITY;
0527:                } else if ("INF".equals(text)) {
0528:                    return Float.POSITIVE_INFINITY;
0529:                } else {
0530:                    try {
0531:                        return Float.parseFloat(text);
0532:                    } catch (NumberFormatException ex) {
0533:                        throw new IllegalArgumentException(ex.getMessage());
0534:                    }
0535:                }
0536:            }
0537:
0538:            /**
0539:             * Serialize float value to text.
0540:             *
0541:             * @param value float value to be serialized
0542:             *
0543:             * @return text representation of value
0544:             */
0545:            public static String serializeFloat(float value) {
0546:                if (Float.isInfinite(value)) {
0547:                    return (value < 0.0f) ? "-INF" : "INF";
0548:                } else {
0549:                    return Float.toString(value);
0550:                }
0551:            }
0552:
0553:            /**
0554:             * Parse double value from text. This uses the W3C XML Schema format for
0555:             * doubles, with the exception that it will accept "+NaN" and "-NaN" as
0556:             * valid formats. This is not in strict compliance with the specification,
0557:             * but is included for interoperability with other Java XML processing.
0558:             *
0559:             * @param text text to be parsed
0560:             *
0561:             * @return converted double value
0562:             *
0563:             * @throws IllegalArgumentException on parse error
0564:             */
0565:            public static double parseDouble(String text)
0566:                    throws IllegalArgumentException {
0567:                text = text.trim();
0568:
0569:                if ("-INF".equals(text)) {
0570:                    return Double.NEGATIVE_INFINITY;
0571:                } else if ("INF".equals(text)) {
0572:                    return Double.POSITIVE_INFINITY;
0573:                } else {
0574:                    try {
0575:                        return Double.parseDouble(text);
0576:                    } catch (NumberFormatException ex) {
0577:                        throw new IllegalArgumentException(ex.getMessage());
0578:                    }
0579:                }
0580:            }
0581:
0582:            /**
0583:             * Serialize double value to text.
0584:             *
0585:             * @param value double value to be serialized
0586:             *
0587:             * @return text representation of value
0588:             */
0589:            public static String serializeDouble(double value) {
0590:                if (Double.isInfinite(value)) {
0591:                    return (value < 0.0f) ? "-INF" : "INF";
0592:                } else {
0593:                    return Double.toString(value);
0594:                }
0595:            }
0596:
0597:            /**
0598:             * Convert gYear text to Java date. Date values are expected to be in W3C
0599:             * XML Schema standard format as CCYY, with optional leading sign.
0600:             *
0601:             * @param text text to be parsed
0602:             *
0603:             * @return start of year date as millisecond value from 1 C.E.
0604:             *
0605:             * @throws IllegalArgumentException on parse error
0606:             */
0607:            public static long parseYear(String text)
0608:                    throws IllegalArgumentException {
0609:                // start by validating the length
0610:                text = text.trim();
0611:
0612:                boolean valid = true;
0613:                int minc = 4;
0614:                char chr = text.charAt(0);
0615:
0616:                if (chr == '-') {
0617:                    minc = 5;
0618:                } else if (chr == '+') {
0619:                    valid = false;
0620:                }
0621:
0622:                if (text.length() < minc) {
0623:                    valid = false;
0624:                }
0625:
0626:                if (!valid) {
0627:                    throw new IllegalArgumentException("Invalid year format");
0628:                }
0629:
0630:                // handle year conversion
0631:                int year = parseInt(text);
0632:
0633:                if (year == 0) {
0634:                    throw new IllegalArgumentException(
0635:                            "Year value 0 is not allowed");
0636:                }
0637:
0638:                if (year > 0) {
0639:                    year--;
0640:                }
0641:
0642:                long day = ((((long) year) * 365) + (year / 4)) - (year / 100)
0643:                        + (year / 400);
0644:
0645:                return (day * MSPERDAY) - TIME_BASE;
0646:            }
0647:
0648:            /**
0649:             * Convert gYearMonth text to Java date. Date values are expected to be in
0650:             * W3C XML Schema standard format as CCYY-MM, with optional leading sign.
0651:             *
0652:             * @param text text to be parsed
0653:             *
0654:             * @return start of month in year date as millisecond value
0655:             *
0656:             * @throws IllegalArgumentException on parse error
0657:             */
0658:            public static long parseYearMonth(String text)
0659:                    throws IllegalArgumentException {
0660:                // start by validating the length and basic format
0661:                text = text.trim();
0662:
0663:                boolean valid = true;
0664:                int minc = 7;
0665:                char chr = text.charAt(0);
0666:
0667:                if (chr == '-') {
0668:                    minc = 8;
0669:                } else if (chr == '+') {
0670:                    valid = false;
0671:                }
0672:
0673:                int split = text.length() - 3;
0674:
0675:                if (text.length() < minc) {
0676:                    valid = false;
0677:                } else {
0678:                    if (text.charAt(split) != '-') {
0679:                        valid = false;
0680:                    }
0681:                }
0682:
0683:                if (!valid) {
0684:                    throw new IllegalArgumentException("Invalid date format");
0685:                }
0686:
0687:                // handle year and month conversion
0688:                int year = parseInt(text.substring(0, split));
0689:
0690:                if (year == 0) {
0691:                    throw new IllegalArgumentException(
0692:                            "Year value 0 is not allowed");
0693:                }
0694:
0695:                int month = parseDigits(text, split + 1, 2) - 1;
0696:
0697:                if ((month < 0) || (month > 11)) {
0698:                    throw new IllegalArgumentException(
0699:                            "Month value out of range");
0700:                }
0701:
0702:                boolean leap = ((year % 4) == 0)
0703:                        && !(((year % 100) == 0) && ((year % 400) != 0));
0704:
0705:                if (year > 0) {
0706:                    year--;
0707:                }
0708:
0709:                long day = ((((long) year) * 365) + (year / 4)) - (year / 100)
0710:                        + (year / 400)
0711:                        + (leap ? MONTHS_LEAP : MONTHS_NONLEAP)[month];
0712:
0713:                return (day * MSPERDAY) - TIME_BASE;
0714:            }
0715:
0716:            /**
0717:             * Convert date text to Java date. Date values are expected to be in W3C
0718:             * XML Schema standard format as CCYY-MM-DD, with optional leading sign
0719:             * and trailing time zone (though the time zone is ignored in this case).
0720:             *
0721:             * @param text text to be parsed
0722:             *
0723:             * @return start of day in month and year date as millisecond value
0724:             *
0725:             * @throws IllegalArgumentException on parse error
0726:             */
0727:            public static long parseDate(String text)
0728:                    throws IllegalArgumentException {
0729:                // start by validating the length and basic format
0730:                boolean valid = true;
0731:                int minc = 10;
0732:                char chr = text.charAt(0);
0733:
0734:                if (chr == '-') {
0735:                    minc = 11;
0736:                } else if (chr == '+') {
0737:                    valid = false;
0738:                }
0739:
0740:                int split = text.length() - 6;
0741:
0742:                if (text.length() < minc) {
0743:                    valid = false;
0744:                } else {
0745:                    if ((text.charAt(split) != '-')
0746:                            || (text.charAt(split + 3) != '-')) {
0747:                        valid = false;
0748:                    }
0749:                }
0750:
0751:                if (!valid) {
0752:                    throw new IllegalArgumentException("Invalid date format");
0753:                }
0754:
0755:                // handle year, month, and day conversion
0756:                int year = parseInt(text.substring(0, split));
0757:
0758:                if (year == 0) {
0759:                    throw new IllegalArgumentException(
0760:                            "Year value 0 is not allowed");
0761:                }
0762:
0763:                int month = parseDigits(text, split + 1, 2) - 1;
0764:
0765:                if ((month < 0) || (month > 11)) {
0766:                    throw new IllegalArgumentException(
0767:                            "Month value out of range");
0768:                }
0769:
0770:                long day = parseDigits(text, split + 4, 2) - 1;
0771:                boolean leap = ((year % 4) == 0)
0772:                        && !(((year % 100) == 0) && ((year % 400) != 0));
0773:                int[] starts = leap ? MONTHS_LEAP : MONTHS_NONLEAP;
0774:
0775:                if ((day < 0) || (day >= (starts[month + 1] - starts[month]))) {
0776:                    throw new IllegalArgumentException("Day value out of range");
0777:                }
0778:
0779:                if (year > 0) {
0780:                    year--;
0781:                }
0782:
0783:                day += (((((long) year) * 365) + (year / 4)) - (year / 100)
0784:                        + (year / 400) + starts[month]);
0785:
0786:                return (day * MSPERDAY) - TIME_BASE;
0787:            }
0788:
0789:            /**
0790:             * Deserialize date from text. Date values are expected to match W3C XML
0791:             * Schema standard format as CCYY-MM-DD, with optional leading minus sign
0792:             * if necessary. This method follows standard JiBX deserializer usage
0793:             * requirements by accepting a <code>null</code> input.
0794:             *
0795:             * @param text text to be parsed (may be <code>null</code>)
0796:             *
0797:             * @return converted date, or <code>null</code> if passed <code>null</code>
0798:             *         input
0799:             *
0800:             * @throws IllegalArgumentException on parse error
0801:             */
0802:            public static Date deserializeDate(String text)
0803:                    throws IllegalArgumentException {
0804:                if (text == null) {
0805:                    return null;
0806:                } else {
0807:                    return new Date(parseDate(text));
0808:                }
0809:            }
0810:
0811:            /**
0812:             * Deserialize SQL date from text. Date values are expected to match W3C
0813:             * XML Schema standard format as CCYY-MM-DD, with optional leading minus
0814:             * sign if necessary. This method follows standard JiBX deserializer usage
0815:             * requirements by accepting a <code>null</code> input.
0816:             *
0817:             * @param text text to be parsed (may be <code>null</code>)
0818:             *
0819:             * @return converted date, or <code>null</code> if passed <code>null</code>
0820:             *         input
0821:             *
0822:             * @throws IllegalArgumentException on parse error
0823:             */
0824:            public static java.sql.Date deserializeSqlDate(String text)
0825:                    throws IllegalArgumentException {
0826:                if (text == null) {
0827:                    return null;
0828:                } else {
0829:                    // convert value, assuming maximum daylight time change of 2 hours
0830:                    long time = parseDate(text);
0831:                    time += (TimeZone.getDefault().getRawOffset() + (MSPERHOUR * 2));
0832:
0833:                    return new java.sql.Date(time);
0834:                }
0835:            }
0836:
0837:            /**
0838:             * Parse general time value from text. Time values are expected to be in
0839:             * W3C XML Schema standard format as hh:mm:ss.fff, with optional leading
0840:             * sign and trailing time zone.
0841:             *
0842:             * @param text text to be parsed
0843:             * @param start offset of first character of time value
0844:             * @param length number of characters in time value
0845:             *
0846:             * @return converted time as millisecond value
0847:             *
0848:             * @throws IllegalArgumentException on parse error
0849:             */
0850:            public static long parseTime(String text, int start, int length)
0851:                    throws IllegalArgumentException {
0852:                // validate time value following date
0853:                long milli = 0;
0854:                boolean valid = (length > (start + 7))
0855:                        && (text.charAt(start + 2) == ':')
0856:                        && (text.charAt(start + 5) == ':');
0857:
0858:                if (valid) {
0859:                    int hour = parseDigits(text, start, 2);
0860:                    int minute = parseDigits(text, start + 3, 2);
0861:                    int second = parseDigits(text, start + 6, 2);
0862:
0863:                    if ((hour > 23) || (minute > 59) || (second > 60)) {
0864:                        valid = false;
0865:                    } else {
0866:                        // convert to base millisecond in day
0867:                        milli = ((((hour * 60) + minute) * 60) + second) * 1000;
0868:                        start += 8;
0869:
0870:                        if (length > start) {
0871:                            // adjust for time zone
0872:                            if (text.charAt(length - 1) == 'Z') {
0873:                                length--;
0874:                            } else {
0875:                                char chr = text.charAt(length - 6);
0876:
0877:                                if ((chr == '-') || (chr == '+')) {
0878:                                    hour = parseDigits(text, length - 5, 2);
0879:                                    minute = parseDigits(text, length - 2, 2);
0880:
0881:                                    if ((hour > 23) || (minute > 59)) {
0882:                                        valid = false;
0883:                                    } else {
0884:                                        int offset = ((hour * 60) + minute) * 60 * 1000;
0885:
0886:                                        if (chr == '-') {
0887:                                            milli += offset;
0888:                                        } else {
0889:                                            milli -= offset;
0890:                                        }
0891:                                    }
0892:
0893:                                    length -= 6;
0894:                                }
0895:                            }
0896:
0897:                            // check for trailing fractional second
0898:                            if (text.charAt(start) == '.') {
0899:                                double fraction = Double.parseDouble(text
0900:                                        .substring(start, length));
0901:                                milli += (fraction * 1000.0);
0902:                            } else if (length > start) {
0903:                                valid = false;
0904:                            }
0905:                        }
0906:                    }
0907:                }
0908:
0909:                // check for valid result
0910:                if (valid) {
0911:                    return milli;
0912:                } else {
0913:                    throw new IllegalArgumentException(
0914:                            "Invalid dateTime format");
0915:                }
0916:            }
0917:
0918:            /**
0919:             * Parse general dateTime value from text. Date values are expected to be
0920:             * in W3C XML Schema standard format as CCYY-MM-DDThh:mm:ss.fff, with
0921:             * optional leading sign and trailing time zone.
0922:             *
0923:             * @param text text to be parsed
0924:             *
0925:             * @return converted date as millisecond value
0926:             *
0927:             * @throws IllegalArgumentException on parse error
0928:             */
0929:            public static long parseDateTime(String text)
0930:                    throws IllegalArgumentException {
0931:                // split text to convert portions separately
0932:                int split = text.indexOf('T');
0933:
0934:                if (split < 0) {
0935:                    throw new IllegalArgumentException(
0936:                            "Missing 'T' separator in dateTime");
0937:                }
0938:
0939:                return parseDate(text.substring(0, split))
0940:                        + parseTime(text, split + 1, text.length());
0941:            }
0942:
0943:            /**
0944:             * Deserialize date from general dateTime text. Date values are expected to
0945:             * match W3C XML Schema standard format as CCYY-MM-DDThh:mm:ss, with
0946:             * optional leading minus sign and trailing seconds decimal, as necessary.
0947:             * This method follows standard JiBX deserializer usage requirements by
0948:             * accepting a <code>null</code> input.
0949:             *
0950:             * @param text text to be parsed (may be <code>null</code>)
0951:             *
0952:             * @return converted date, or <code>null</code> if passed <code>null</code>
0953:             *         input
0954:             *
0955:             * @throws IllegalArgumentException on parse error
0956:             */
0957:            public static Date deserializeDateTime(String text)
0958:                    throws IllegalArgumentException {
0959:                if (text == null) {
0960:                    return null;
0961:                } else {
0962:                    return new Date(parseDateTime(text));
0963:                }
0964:            }
0965:
0966:            /**
0967:             * Deserialize timestamp from general dateTime text. Timestamp values are
0968:             * represented in the same way as regular dates, but allow more precision
0969:             * in the fractional second value (down to nanoseconds). This method
0970:             * follows standard JiBX deserializer usage requirements by accepting a
0971:             * <code>null</code> input.
0972:             *
0973:             * @param text text to be parsed (may be <code>null</code>)
0974:             *
0975:             * @return converted timestamp, or <code>null</code> if passed
0976:             *         <code>null</code> input
0977:             *
0978:             * @throws IllegalArgumentException on parse error
0979:             */
0980:            public static Timestamp deserializeTimestamp(String text)
0981:                    throws IllegalArgumentException {
0982:                if (text == null) {
0983:                    return null;
0984:                } else {
0985:                    // check for fractional second value present
0986:                    int split = text.indexOf('.');
0987:                    int nano = 0;
0988:
0989:                    if (split > 0) {
0990:                        // make sure there aren't multiple decimal points
0991:                        if (text.indexOf('.', split) > 0) {
0992:                            throw new IllegalArgumentException(
0993:                                    "Not a valid dateTime value");
0994:                        }
0995:
0996:                        // scan through all digits following decimal point
0997:                        int limit = text.length();
0998:                        int scan = split;
0999:
1000:                        while (++scan < limit) {
1001:                            char chr = text.charAt(scan);
1002:
1003:                            if ((chr < '0') || (chr > '9')) {
1004:                                break;
1005:                            }
1006:                        }
1007:
1008:                        // parse digits following decimal point
1009:                        int length = scan - split - 1;
1010:
1011:                        if (length > 9) {
1012:                            length = 9;
1013:                        }
1014:
1015:                        nano = parseDigits(text, split + 1, length);
1016:
1017:                        // convert to number of nanoseconds
1018:                        while (length < 9) {
1019:                            nano *= 10;
1020:                            length++;
1021:                        }
1022:
1023:                        // strip fractional second off text
1024:                        if (scan < limit) {
1025:                            text = text.substring(0, split)
1026:                                    + text.substring(scan);
1027:                        } else {
1028:                            text = text.substring(0, split);
1029:                        }
1030:                    }
1031:
1032:                    // return timestamp value with nanoseconds
1033:                    Timestamp stamp = new Timestamp(parseDateTime(text));
1034:                    stamp.setNanos(nano);
1035:
1036:                    return stamp;
1037:                }
1038:            }
1039:
1040:            /**
1041:             * Deserialize time from text. Time values obey the rules of the time
1042:             * portion of a dataTime value. This method follows standard JiBX
1043:             * deserializer usage requirements by accepting a <code>null</code> input.
1044:             *
1045:             * @param text text to be parsed (may be <code>null</code>)
1046:             *
1047:             * @return converted time, or <code>null</code> if passed <code>null</code>
1048:             *         input
1049:             *
1050:             * @throws IllegalArgumentException on parse error
1051:             */
1052:            public static Time deserializeSqlTime(String text)
1053:                    throws IllegalArgumentException {
1054:                if (text == null) {
1055:                    return null;
1056:                } else {
1057:                    return new Time(parseTime(text, 0, text.length()));
1058:                }
1059:            }
1060:
1061:            /**
1062:             * Format year number consistent with W3C XML Schema definitions, using a
1063:             * minimum of four digits padded with zeros if necessary. A leading minus
1064:             * sign is included for years prior to 1 C.E.
1065:             *
1066:             * @param year number to be formatted
1067:             * @param buff text formatting buffer
1068:             */
1069:            protected static void formatYearNumber(long year, StringBuffer buff) {
1070:                // start with minus sign for dates prior to 1 C.E.
1071:                if (year <= 0) {
1072:                    buff.append('-');
1073:                    year = -(year - 1);
1074:                }
1075:
1076:                // add padding if needed to bring to length of four
1077:                if (year < 1000) {
1078:                    buff.append('0');
1079:
1080:                    if (year < 100) {
1081:                        buff.append('0');
1082:
1083:                        if (year < 10) {
1084:                            buff.append('0');
1085:                        }
1086:                    }
1087:                }
1088:
1089:                // finish by converting the actual year number
1090:                buff.append(year);
1091:            }
1092:
1093:            /**
1094:             * Format a positive number as two digits. This uses an optional leading
1095:             * zero digit for values less than ten.
1096:             *
1097:             * @param value number to be formatted (<code>0</code> to <code>99</code>)
1098:             * @param buff text formatting buffer
1099:             */
1100:            protected static void formatTwoDigits(int value, StringBuffer buff) {
1101:                if (value < 10) {
1102:                    buff.append('0');
1103:                }
1104:
1105:                buff.append(value);
1106:            }
1107:
1108:            /**
1109:             * Format time in milliseconds to year number. The resulting year number
1110:             * format is consistent with W3C XML Schema definitions, using a minimum
1111:             * of four digits padded with zeros if necessary. A leading minus sign is
1112:             * included for years prior to 1 C.E.
1113:             *
1114:             * @param value time in milliseconds to be converted (from 1 C.E.)
1115:             * @param buff text formatting buffer
1116:             */
1117:            protected static void formatYear(long value, StringBuffer buff) {
1118:                // find the actual year and month number; this uses a integer arithmetic
1119:                //  conversion based on Baum, first making the millisecond count
1120:                //  relative to March 1 of the year 0 C.E., then using simple arithmetic
1121:                //  operations to compute century, year, and month; it's slightly
1122:                //  different for pre-C.E. values because of Java's handling of divisions.
1123:                long time = value + (306 * LMSPERDAY) + ((LMSPERDAY * 3) / 4);
1124:                long century = time / MSPERCENTURY; // count of centuries
1125:                long adjusted = time + ((century - (century / 4)) * MSPERDAY);
1126:                int year = (int) (adjusted / MSPERAVGYEAR); // year in March 1 terms
1127:
1128:                if (adjusted < 0) {
1129:                    year--;
1130:                }
1131:
1132:                long yms = (adjusted + (LMSPERDAY / 4))
1133:                        - (((year * 365) + (year / 4)) * LMSPERDAY);
1134:                int yday = (int) (yms / LMSPERDAY); // day number in year
1135:                int month = ((5 * yday) + 456) / 153; // (biased) month number
1136:
1137:                if (month > 12) { // convert start of year
1138:                    year++;
1139:                }
1140:
1141:                // format year to text
1142:                formatYearNumber(year, buff);
1143:            }
1144:
1145:            /**
1146:             * Format time in milliseconds to year number and month number. The
1147:             * resulting year number format is consistent with W3C XML Schema
1148:             * definitions, using a minimum of four digits for the year and exactly
1149:             * two digits for the month.
1150:             *
1151:             * @param value time in milliseconds to be converted (from 1 C.E.)
1152:             * @param buff text formatting buffer
1153:             *
1154:             * @return number of milliseconds into month
1155:             */
1156:            protected static long formatYearMonth(long value, StringBuffer buff) {
1157:                // find the actual year and month number; this uses a integer arithmetic
1158:                //  conversion based on Baum, first making the millisecond count
1159:                //  relative to March 1 of the year 0 C.E., then using simple arithmetic
1160:                //  operations to compute century, year, and month; it's slightly
1161:                //  different for pre-C.E. values because of Java's handling of divisions.
1162:                long time = value + (306 * LMSPERDAY) + ((LMSPERDAY * 3) / 4);
1163:                long century = time / MSPERCENTURY; // count of centuries
1164:                long adjusted = time + ((century - (century / 4)) * MSPERDAY);
1165:                int year = (int) (adjusted / MSPERAVGYEAR); // year in March 1 terms
1166:
1167:                if (adjusted < 0) {
1168:                    year--;
1169:                }
1170:
1171:                long yms = (adjusted + (LMSPERDAY / 4))
1172:                        - (((year * 365) + (year / 4)) * LMSPERDAY);
1173:                int yday = (int) (yms / LMSPERDAY); // day number in year
1174:
1175:                if (yday == 0) { // special for negative
1176:
1177:                    boolean bce = year < 0;
1178:
1179:                    if (bce) {
1180:                        year--;
1181:                    }
1182:
1183:                    int dcnt = ((year % 4) == 0) ? 366 : 365;
1184:
1185:                    if (!bce) {
1186:                        year--;
1187:                    }
1188:
1189:                    yms += (dcnt * LMSPERDAY);
1190:                    yday += dcnt;
1191:                }
1192:
1193:                int month = ((5 * yday) + 456) / 153; // (biased) month number
1194:                long rem = yms - BIAS_MONTHMS[month] - LMSPERDAY; // ms into month
1195:
1196:                if (month > 12) { // convert start of year
1197:                    year++;
1198:                    month -= 12;
1199:                }
1200:
1201:                // format year and month as text
1202:                formatYearNumber(year, buff);
1203:                buff.append('-');
1204:                formatTwoDigits(month, buff);
1205:
1206:                // return extra milliseconds into month
1207:                return rem;
1208:            }
1209:
1210:            /**
1211:             * Format time in milliseconds to year number, month number, and day
1212:             * number. The resulting year number format is consistent with W3C XML
1213:             * Schema definitions, using a minimum of four digits for the year and
1214:             * exactly two digits each for the month and day.
1215:             *
1216:             * @param value time in milliseconds to be converted (from 1 C.E.)
1217:             * @param buff text formatting buffer
1218:             *
1219:             * @return number of milliseconds into day
1220:             */
1221:            protected static int formatYearMonthDay(long value,
1222:                    StringBuffer buff) {
1223:                // convert year and month
1224:                long extra = formatYearMonth(value, buff);
1225:
1226:                // append the day of month
1227:                int day = (int) (extra / MSPERDAY) + 1;
1228:                buff.append('-');
1229:                formatTwoDigits(day, buff);
1230:
1231:                // return excess of milliseconds into day
1232:                return (int) (extra % MSPERDAY);
1233:            }
1234:
1235:            /**
1236:             * Serialize time to general gYear text. Date values are formatted in W3C
1237:             * XML Schema standard format as CCYY, with optional leading sign included
1238:             * if necessary.
1239:             *
1240:             * @param time time to be converted, as milliseconds from January 1, 1970
1241:             *
1242:             * @return converted gYear text
1243:             *
1244:             * @throws IllegalArgumentException on conversion error
1245:             */
1246:            public static String serializeYear(long time)
1247:                    throws IllegalArgumentException {
1248:                StringBuffer buff = new StringBuffer(6);
1249:                formatYear(time + TIME_BASE, buff);
1250:
1251:                return buff.toString();
1252:            }
1253:
1254:            /**
1255:             * Serialize date to general gYear text. Date values are formatted in W3C
1256:             * XML Schema standard format as CCYY, with optional leading sign included
1257:             * if necessary.
1258:             *
1259:             * @param date date to be converted
1260:             *
1261:             * @return converted gYear text
1262:             *
1263:             * @throws IllegalArgumentException on conversion error
1264:             */
1265:            public static String serializeYear(Date date)
1266:                    throws IllegalArgumentException {
1267:                return serializeYear(date.getTime());
1268:            }
1269:
1270:            /**
1271:             * Serialize time to general gYearMonth text. Date values are formatted in
1272:             * W3C XML Schema standard format as CCYY-MM, with optional leading sign
1273:             * included if necessary.
1274:             *
1275:             * @param time time to be converted, as milliseconds from January 1, 1970
1276:             *
1277:             * @return converted gYearMonth text
1278:             *
1279:             * @throws IllegalArgumentException on conversion error
1280:             */
1281:            public static String serializeYearMonth(long time)
1282:                    throws IllegalArgumentException {
1283:                StringBuffer buff = new StringBuffer(12);
1284:                formatYearMonth(time + TIME_BASE, buff);
1285:
1286:                return buff.toString();
1287:            }
1288:
1289:            /**
1290:             * Serialize date to general gYearMonth text. Date values are formatted in
1291:             * W3C XML Schema standard format as CCYY-MM, with optional leading sign
1292:             * included if necessary.
1293:             *
1294:             * @param date date to be converted
1295:             *
1296:             * @return converted gYearMonth text
1297:             *
1298:             * @throws IllegalArgumentException on conversion error
1299:             */
1300:            public static String serializeYearMonth(Date date)
1301:                    throws IllegalArgumentException {
1302:                return serializeYearMonth(date.getTime());
1303:            }
1304:
1305:            /**
1306:             * Serialize time to general date text. Date values are formatted in W3C
1307:             * XML Schema standard format as CCYY-MM-DD, with optional leading sign
1308:             * included if necessary.
1309:             *
1310:             * @param time time to be converted, as milliseconds from January 1, 1970
1311:             *
1312:             * @return converted date text
1313:             *
1314:             * @throws IllegalArgumentException on conversion error
1315:             */
1316:            public static String serializeDate(long time)
1317:                    throws IllegalArgumentException {
1318:                StringBuffer buff = new StringBuffer(12);
1319:                formatYearMonthDay(time + TIME_BASE, buff);
1320:
1321:                return buff.toString();
1322:            }
1323:
1324:            /**
1325:             * Serialize date to general date text. Date values are formatted in W3C
1326:             * XML Schema standard format as CCYY-MM-DD, with optional leading sign
1327:             * included if necessary.
1328:             *
1329:             * @param date date to be converted
1330:             *
1331:             * @return converted date text
1332:             *
1333:             * @throws IllegalArgumentException on conversion error
1334:             */
1335:            public static String serializeDate(Date date)
1336:                    throws IllegalArgumentException {
1337:                return serializeDate(date.getTime());
1338:            }
1339:
1340:            /**
1341:             * Serialize SQL date to general date text. Date values are formatted in
1342:             * W3C XML Schema standard format as CCYY-MM-DD, with optional leading
1343:             * sign included if necessary.
1344:             *
1345:             * @param date date to be converted
1346:             *
1347:             * @return converted date text
1348:             *
1349:             * @throws IllegalArgumentException on conversion error
1350:             */
1351:            public static String serializeSqlDate(java.sql.Date date)
1352:                    throws IllegalArgumentException {
1353:                // convert time assuming maximum daylight time difference of two hours
1354:                long time = date.getTime();
1355:                time -= (TimeZone.getDefault().getRawOffset() - (MSPERHOUR * 2));
1356:
1357:                return serializeDate(time);
1358:            }
1359:
1360:            /**
1361:             * Serialize time to general time text in buffer. Time values are formatted
1362:             * in W3C XML Schema standard format as hh:mm:ss, with optional trailing
1363:             * seconds decimal, as necessary. This form uses a supplied buffer to
1364:             * support flexible use, including with dateTime combination values.
1365:             *
1366:             * @param time time to be converted, as milliseconds in day
1367:             * @param buff buffer for appending time text
1368:             *
1369:             * @throws IllegalArgumentException on conversion error
1370:             */
1371:            public static void serializeTime(int time, StringBuffer buff)
1372:                    throws IllegalArgumentException {
1373:                // append the hour, minute, and second
1374:                formatTwoDigits(time / MSPERHOUR, buff);
1375:                time = time % MSPERHOUR;
1376:                buff.append(':');
1377:                formatTwoDigits(time / MSPERMINUTE, buff);
1378:                time = time % MSPERMINUTE;
1379:                buff.append(':');
1380:                formatTwoDigits(time / 1000, buff);
1381:                time = time % 1000;
1382:
1383:                // check if decimals needed on second
1384:                if (time > 0) {
1385:                    buff.append('.');
1386:                    buff.append(time / 100);
1387:                    time = time % 100;
1388:
1389:                    if (time > 0) {
1390:                        buff.append(time / 10);
1391:                        time = time % 10;
1392:
1393:                        if (time > 0) {
1394:                            buff.append(time);
1395:                        }
1396:                    }
1397:                }
1398:            }
1399:
1400:            /**
1401:             * Serialize time to general dateTime text. Date values are formatted in
1402:             * W3C XML Schema standard format as CCYY-MM-DDThh:mm:ss, with optional
1403:             * leading sign and trailing seconds decimal, as necessary.
1404:             *
1405:             * @param time time to be converted, as milliseconds from January 1, 1970
1406:             * @param zone flag for trailing 'Z' to be appended to indicate UTC
1407:             *
1408:             * @return converted dateTime text
1409:             *
1410:             * @throws IllegalArgumentException on conversion error
1411:             */
1412:            public static String serializeDateTime(long time, boolean zone)
1413:                    throws IllegalArgumentException {
1414:                // start with the year, month, and day
1415:                StringBuffer buff = new StringBuffer(25);
1416:                int extra = formatYearMonthDay(time + TIME_BASE, buff);
1417:
1418:                // append the time for full form
1419:                buff.append('T');
1420:                serializeTime(extra, buff);
1421:
1422:                // return full text with optional trailing zone indicator
1423:                if (zone) {
1424:                    buff.append('Z');
1425:                }
1426:
1427:                return buff.toString();
1428:            }
1429:
1430:            /**
1431:             * Serialize time to general dateTime text. This method is provided for
1432:             * backward compatibility. It generates the dateTime text without the
1433:             * trailing 'Z' to indicate UTC.
1434:             *
1435:             * @param time time to be converted, as milliseconds from January 1, 1970
1436:             *
1437:             * @return converted dateTime text
1438:             *
1439:             * @throws IllegalArgumentException on conversion error
1440:             */
1441:            public static String serializeDateTime(long time)
1442:                    throws IllegalArgumentException {
1443:                return serializeDateTime(time, false);
1444:            }
1445:
1446:            /**
1447:             * Serialize date to general dateTime text. Date values are formatted in
1448:             * W3C XML Schema standard format as CCYY-MM-DDThh:mm:ss, with optional
1449:             * leading sign and trailing seconds decimal, as necessary.
1450:             *
1451:             * @param date date to be converted
1452:             *
1453:             * @return converted dateTime text
1454:             *
1455:             * @throws IllegalArgumentException on conversion error
1456:             */
1457:            public static String serializeDateTime(Date date)
1458:                    throws IllegalArgumentException {
1459:                return serializeDateTime(date.getTime(), false);
1460:            }
1461:
1462:            /**
1463:             * Serialize timestamp to general dateTime text. Timestamp values are
1464:             * represented in the same way as regular dates, but allow more precision
1465:             * in the fractional second value (down to nanoseconds).
1466:             *
1467:             * @param stamp timestamp to be converted
1468:             *
1469:             * @return converted dateTime text
1470:             *
1471:             * @throws IllegalArgumentException on conversion error
1472:             */
1473:            public static String serializeTimestamp(Timestamp stamp)
1474:                    throws IllegalArgumentException {
1475:                // check for nanosecond value to be included
1476:                int nano = stamp.getNanos();
1477:
1478:                if (nano > 0) {
1479:                    // convert the number of nanoseconds to text
1480:                    String value = serializeInt(nano);
1481:
1482:                    // pad with leading zeros if less than 9 digits
1483:                    StringBuffer digits = new StringBuffer(9);
1484:
1485:                    if (value.length() < 9) {
1486:                        int lead = 9 - value.length();
1487:
1488:                        for (int i = 0; i < lead; i++) {
1489:                            digits.append('0');
1490:                        }
1491:                    }
1492:
1493:                    digits.append(value);
1494:
1495:                    // strip trailing zeros from value
1496:                    int last = 9;
1497:
1498:                    while (--last > 0) {
1499:                        if (digits.charAt(last) != '0') {
1500:                            break;
1501:                        }
1502:                    }
1503:
1504:                    digits.setLength(last);
1505:
1506:                    // finish by appending to time with decimal separator
1507:                    return serializeDateTime(stamp.getTime(), false) + '.'
1508:                            + digits + 'Z';
1509:                } else {
1510:                    return serializeDateTime(stamp.getTime(), true);
1511:                }
1512:            }
1513:
1514:            /**
1515:             * Serialize time to standard text. Time values are formatted in W3C XML
1516:             * Schema standard format as hh:mm:ss, with optional trailing seconds
1517:             * decimal, as necessary. The standard conversion does not append a time
1518:             * zone indication.
1519:             *
1520:             * @param time time to be converted
1521:             *
1522:             * @return converted time text
1523:             *
1524:             * @throws IllegalArgumentException on conversion error
1525:             */
1526:            public static String serializeSqlTime(Time time)
1527:                    throws IllegalArgumentException {
1528:                StringBuffer buff = new StringBuffer(12);
1529:                serializeTime((int) time.getTime(), buff);
1530:
1531:                return buff.toString();
1532:            }
1533:
1534:            /**
1535:             * General object comparison method. Don't know why Sun hasn't seen fit to
1536:             * include this somewhere, but at least it's easy to write (over and over
1537:             * again).
1538:             *
1539:             * @param a first object to be compared
1540:             * @param b second object to be compared
1541:             *
1542:             * @return <code>true</code> if both objects are <code>null</code>, or if
1543:             *         <code>a.equals(b)</code>; <code>false</code> otherwise
1544:             */
1545:            public static boolean isEqual(Object a, Object b) {
1546:                return (a == null) ? (b == null) : a.equals(b);
1547:            }
1548:
1549:            /**
1550:             * Find text value in enumeration. This first does a binary search through
1551:             * an array of allowed text matches. If a separate array of corresponding
1552:             * values is supplied, the value at the matched position is returned;
1553:             * otherwise the match index is returned directly.
1554:             *
1555:             * @param target text to be found in enumeration
1556:             * @param enums ordered array of texts included in enumeration
1557:             * @param vals array of values to be returned for corresponding text match
1558:             *        positions (position returned directly if this is
1559:             *        <code>null</code>)
1560:             *
1561:             * @return enumeration value for target text
1562:             *
1563:             * @throws IllegalArgumentException if target text not found in enumeration
1564:             */
1565:            public static int enumValue(String target, String[] enums,
1566:                    int[] vals) throws IllegalArgumentException {
1567:                int base = 0;
1568:                int limit = enums.length - 1;
1569:
1570:                while (base <= limit) {
1571:                    int cur = (base + limit) >> 1;
1572:                    int diff = target.compareTo(enums[cur]);
1573:
1574:                    if (diff < 0) {
1575:                        limit = cur - 1;
1576:                    } else if (diff > 0) {
1577:                        base = cur + 1;
1578:                    } else if (vals != null) {
1579:                        return vals[cur];
1580:                    } else {
1581:                        return cur;
1582:                    }
1583:                }
1584:
1585:                throw new IllegalArgumentException("Target value \"" + target
1586:                        + "\" not found in enumeration");
1587:            }
1588:
1589:            /**
1590:             * Decode a chunk of data from base64 encoding. The length of a chunk is
1591:             * always 4 characters in the base64 representation, but may be 1, 2, or 3
1592:             * bytes of data, as determined by whether there are any pad characters at
1593:             * the end of the base64 representation
1594:             *
1595:             * @param base starting offset within base64 character array
1596:             * @param chrs character array for base64 text representation
1597:             * @param fill starting offset within byte data array
1598:             * @param byts byte data array
1599:             *
1600:             * @return number of decoded bytes
1601:             *
1602:             * @throws IllegalArgumentException if invalid character in base64
1603:             *         representation
1604:             */
1605:            private static int decodeChunk(int base, char[] chrs, int fill,
1606:                    byte[] byts) throws IllegalArgumentException {
1607:                // find the byte count to be decoded
1608:                int length = 3;
1609:
1610:                if (chrs[base + 3] == PAD_CHAR) {
1611:                    length = 2;
1612:
1613:                    if (chrs[base + 2] == PAD_CHAR) {
1614:                        length = 1;
1615:                    }
1616:                }
1617:
1618:                // get 6-bit values
1619:                int v0 = s_base64Values[chrs[base + 0]];
1620:                int v1 = s_base64Values[chrs[base + 1]];
1621:                int v2 = s_base64Values[chrs[base + 2]];
1622:                int v3 = s_base64Values[chrs[base + 3]];
1623:
1624:                // convert and store bytes of data
1625:                switch (length) {
1626:                case 3:
1627:                    byts[fill + 2] = (byte) ((v2 << 6) | v3);
1628:
1629:                case 2:
1630:                    byts[fill + 1] = (byte) ((v1 << 4) | (v2 >> 2));
1631:
1632:                case 1:
1633:                    byts[fill] = (byte) ((v0 << 2) | (v1 >> 4));
1634:
1635:                    break;
1636:                }
1637:
1638:                return length;
1639:            }
1640:
1641:            /**
1642:             * Parse base64 data from text. This converts the base64 data into a byte
1643:             * array of the appopriate length. In keeping with the recommendations,
1644:             *
1645:             * @param text text to be parsed (may include extra characters)
1646:             *
1647:             * @return byte array of data
1648:             *
1649:             * @throws IllegalArgumentException if invalid character in base64
1650:             *         representation
1651:             */
1652:            public static byte[] parseBase64(String text)
1653:                    throws IllegalArgumentException {
1654:                // convert raw text to base64 character array
1655:                char[] chrs = new char[text.length()];
1656:                int length = 0;
1657:
1658:                for (int i = 0; i < text.length(); i++) {
1659:                    char chr = text.charAt(i);
1660:
1661:                    if ((chr < 128) && (s_base64Values[chr] >= 0)) {
1662:                        chrs[length++] = chr;
1663:                    }
1664:                }
1665:
1666:                // check the text length
1667:                if ((length % 4) != 0) {
1668:                    throw new IllegalArgumentException(
1669:                            "Text length for base64 must be a multiple of 4");
1670:                } else if (length == 0) {
1671:                    return new byte[0];
1672:                }
1673:
1674:                // find corresponding byte count for data
1675:                int blength = length / 4 * 3;
1676:
1677:                if (chrs[length - 1] == PAD_CHAR) {
1678:                    blength--;
1679:
1680:                    if (chrs[length - 2] == PAD_CHAR) {
1681:                        blength--;
1682:                    }
1683:                }
1684:
1685:                // convert text to actual bytes of data
1686:                byte[] byts = new byte[blength];
1687:                int fill = 0;
1688:
1689:                for (int i = 0; i < length; i += 4) {
1690:                    fill += decodeChunk(i, chrs, fill, byts);
1691:                }
1692:
1693:                if (fill != blength) {
1694:                    throw new IllegalArgumentException(
1695:                            "Embedded padding characters in byte64 text");
1696:                }
1697:
1698:                return byts;
1699:            }
1700:
1701:            /**
1702:             * Parse base64 data from text. This converts the base64 data into a byte
1703:             * array of the appopriate length. In keeping with the recommendations,
1704:             *
1705:             * @param text text to be parsed (may be null, or include extra characters)
1706:             *
1707:             * @return byte array of data
1708:             *
1709:             * @throws IllegalArgumentException if invalid character in base64
1710:             *         representation
1711:             */
1712:            public static byte[] deserializeBase64(String text)
1713:                    throws IllegalArgumentException {
1714:                if (text == null) {
1715:                    return null;
1716:                } else {
1717:                    return parseBase64(text);
1718:                }
1719:            }
1720:
1721:            /**
1722:             * Encode a chunk of data to base64 encoding. Converts the next three bytes
1723:             * of data into four characters of text representation, using padding at
1724:             * the end of less than three bytes of data remain.
1725:             *
1726:             * @param base starting offset within byte array
1727:             * @param byts byte data array
1728:             * @param buff buffer for encoded text
1729:             */
1730:            public static void encodeChunk(int base, byte[] byts,
1731:                    StringBuffer buff) {
1732:                // get actual byte data length to be encoded
1733:                int length = 3;
1734:
1735:                if ((base + length) > byts.length) {
1736:                    length = byts.length - base;
1737:                }
1738:
1739:                // convert up to three bytes of data to four characters of text
1740:                int b0 = byts[base];
1741:                int value = (b0 >> 2) & 0x3F;
1742:                buff.append(s_base64Chars[value]);
1743:
1744:                if (length > 1) {
1745:                    int b1 = byts[base + 1];
1746:                    value = ((b0 & 3) << 4) + ((b1 >> 4) & 0x0F);
1747:                    buff.append(s_base64Chars[value]);
1748:
1749:                    if (length > 2) {
1750:                        int b2 = byts[base + 2];
1751:                        value = ((b1 & 0x0F) << 2) + ((b2 >> 6) & 3);
1752:                        buff.append(s_base64Chars[value]);
1753:                        value = b2 & 0x3F;
1754:                        buff.append(s_base64Chars[value]);
1755:                    } else {
1756:                        value = (b1 & 0x0F) << 2;
1757:                        buff.append(s_base64Chars[value]);
1758:                        buff.append(PAD_CHAR);
1759:                    }
1760:                } else {
1761:                    value = (b0 & 3) << 4;
1762:                    buff.append(s_base64Chars[value]);
1763:                    buff.append(PAD_CHAR);
1764:                    buff.append(PAD_CHAR);
1765:                }
1766:            }
1767:
1768:            /**
1769:             * Serialize byte array to base64 text. In keeping with the specification,
1770:             * this adds a line break every 76 characters in the encoded
1771:             * representation.
1772:             *
1773:             * @param byts byte data array
1774:             *
1775:             * @return base64 encoded text
1776:             */
1777:            public static String serializeBase64(byte[] byts) {
1778:                StringBuffer buff = new StringBuffer((byts.length + 2) / 3 * 4);
1779:
1780:                for (int i = 0; i < byts.length; i += 3) {
1781:                    encodeChunk(i, byts, buff);
1782:
1783:                    if ((i > 0) && ((i % 57) == 0) && ((i + 3) < byts.length)) {
1784:                        buff.append("\r\n");
1785:                    }
1786:                }
1787:
1788:                return buff.toString();
1789:            }
1790:
1791:            /**
1792:             * Factory method to create a <code>java.util.ArrayList</code> as the
1793:             * implementation of a <code>java.util.List</code>.
1794:             *
1795:             * @return new <code>java.util.ArrayList</code>
1796:             */
1797:            public static List arrayListFactory() {
1798:                return new ArrayList();
1799:            }
1800:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.