Source Code Cross Referenced for ClockCmd.java in  » Scripting » jacl » tcl » lang » 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 » Scripting » jacl » tcl.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * ClockCmd.java --
0003:         *
0004:         *	Implements the built-in "clock" Tcl command.
0005:         *
0006:         * Copyright (c) 1998-2000 Christian Krone.
0007:         * Copyright (c) 1997 Cornell University.
0008:         * Copyright (c) 1995-1997 Sun Microsystems, Inc.
0009:         * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
0010:         *
0011:         * See the file "license.terms" for information on usage and
0012:         * redistribution of this file, and for a DISCLAIMER OF ALL
0013:         * WARRANTIES.
0014:         * 
0015:         * RCS: @(#) $Id: ClockCmd.java,v 1.7 2006/01/26 19:49:18 mdejong Exp $
0016:         *
0017:         */
0018:
0019:        package tcl.lang;
0020:
0021:        import java.util.*;
0022:        import java.text.*;
0023:
0024:        /**
0025:         * This class implements the built-in "clock" command in Tcl.
0026:         */
0027:
0028:        class ClockCmd implements  Command {
0029:
0030:            static final private String[] validCmds = { "clicks", "format",
0031:                    "scan", "seconds" };
0032:
0033:            static final private int CMD_CLICKS = 0;
0034:            static final private int CMD_FORMAT = 1;
0035:            static final private int CMD_SCAN = 2;
0036:            static final private int CMD_SECONDS = 3;
0037:
0038:            static final private String clicksOpts[] = { "-milliseconds" };
0039:
0040:            static final private int OPT_CLICKS_MILLISECONDS = 0;
0041:
0042:            static final private String[] formatOpts = { "-format", "-gmt" };
0043:
0044:            static final private int OPT_FORMAT_FORMAT = 0;
0045:            static final private int OPT_FORMAT_GMT = 1;
0046:
0047:            static final private String[] scanOpts = { "-base", "-gmt" };
0048:
0049:            static final private int OPT_SCAN_BASE = 0;
0050:            static final private int OPT_SCAN_GMT = 1;
0051:
0052:            static final int EPOCH_YEAR = 1970;
0053:            static final int MILLIS_PER_HOUR = 60 * 60 * 1000;
0054:
0055:            /**
0056:             *----------------------------------------------------------------------
0057:             *
0058:             * cmdProc --
0059:             *
0060:             *	This procedure is invoked as part of the Command interface to
0061:             *	process the "clock" Tcl command.  See the user documentation
0062:             *	for details on what it does.
0063:             *
0064:             * Results:
0065:             *	None.
0066:             *
0067:             * Side effects:
0068:             *	See the user documentation.
0069:             *
0070:             *----------------------------------------------------------------------
0071:             */
0072:
0073:            public void cmdProc(Interp interp, // Current interpreter.
0074:                    TclObject[] objv) // Argument list.
0075:                    throws TclException // A standard Tcl exception.
0076:            {
0077:                int clockVal; // Time value as seconds of epoch.
0078:                String dateString; // Time value as string.
0079:                int argIx; // Counter over arguments.
0080:                String format = null; // User specified format string.
0081:                boolean useGmt = false; // User specified flag to use gmt.
0082:                TclObject baseObj = null; // User specified raw value of baseClock.
0083:                Date baseClock; // User specified time value.
0084:                Date date; // Parsed date value.
0085:
0086:                if (objv.length < 2) {
0087:                    throw new TclNumArgsException(interp, 1, objv,
0088:                            "option ?arg ...?");
0089:                }
0090:                int cmd = TclIndex.get(interp, objv[1], validCmds, "option", 0);
0091:
0092:                switch (cmd) {
0093:                case CMD_CLICKS: {
0094:                    if (objv.length > 3) {
0095:                        throw new TclNumArgsException(interp, 2, objv,
0096:                                "?-milliseconds?");
0097:                    }
0098:                    if (objv.length == 3) {
0099:                        // We can safely ignore the -milliseconds options, since
0100:                        // we measure the clicks in milliseconds anyway...
0101:                        int clicksOpt = TclIndex.get(interp, objv[2],
0102:                                clicksOpts, "switch", 0);
0103:                    }
0104:                    long millis = System.currentTimeMillis();
0105:                    int clicks = (int) (millis % Integer.MAX_VALUE);
0106:                    interp.setResult(clicks);
0107:                    break;
0108:                }
0109:
0110:                case CMD_FORMAT: {
0111:                    if ((objv.length < 3) || (objv.length > 7)) {
0112:                        throw new TclNumArgsException(interp, 2, objv,
0113:                                "clockval ?-format string? ?-gmt boolean?");
0114:                    }
0115:                    clockVal = TclInteger.get(interp, objv[2]);
0116:
0117:                    for (argIx = 3; argIx + 1 < objv.length; argIx += 2) {
0118:                        int formatOpt = TclIndex.get(interp, objv[argIx],
0119:                                formatOpts, "switch", 0);
0120:                        switch (formatOpt) {
0121:                        case OPT_FORMAT_FORMAT: {
0122:                            format = objv[argIx + 1].toString();
0123:                            break;
0124:                        }
0125:                        case OPT_FORMAT_GMT: {
0126:                            useGmt = TclBoolean.get(interp, objv[argIx + 1]);
0127:                            break;
0128:                        }
0129:                        }
0130:                    }
0131:                    if (argIx < objv.length) {
0132:                        throw new TclNumArgsException(interp, 2, objv,
0133:                                "clockval ?-format string? ?-gmt boolean?");
0134:                    }
0135:                    FormatClock(interp, clockVal, useGmt, format);
0136:                    break;
0137:                }
0138:
0139:                case CMD_SCAN: {
0140:                    if ((objv.length < 3) || (objv.length > 7)) {
0141:                        throw new TclNumArgsException(interp, 2, objv,
0142:                                "dateString ?-base clockValue? ?-gmt boolean?");
0143:                    }
0144:                    dateString = objv[2].toString();
0145:
0146:                    for (argIx = 3; argIx + 1 < objv.length; argIx += 2) {
0147:                        int scanOpt = TclIndex.get(interp, objv[argIx],
0148:                                scanOpts, "switch", 0);
0149:                        switch (scanOpt) {
0150:                        case OPT_SCAN_BASE: {
0151:                            baseObj = objv[argIx + 1];
0152:                            break;
0153:                        }
0154:                        case OPT_SCAN_GMT: {
0155:                            useGmt = TclBoolean.get(interp, objv[argIx + 1]);
0156:                            break;
0157:                        }
0158:                        }
0159:                    }
0160:                    if (argIx < objv.length) {
0161:                        throw new TclNumArgsException(interp, 2, objv,
0162:                                "clockval ?-format string? ?-gmt boolean?");
0163:                    }
0164:                    if (baseObj != null) {
0165:                        long seconds = TclInteger.get(interp, baseObj);
0166:                        baseClock = new Date(seconds * 1000);
0167:                    } else {
0168:                        baseClock = new Date();
0169:                    }
0170:
0171:                    date = GetDate(dateString, baseClock, useGmt);
0172:                    if (date == null) {
0173:                        throw new TclException(interp,
0174:                                "unable to convert date-time string \""
0175:                                        + dateString + "\"");
0176:                    }
0177:
0178:                    int seconds = (int) (date.getTime() / 1000);
0179:                    interp.setResult(seconds);
0180:                    break;
0181:                }
0182:
0183:                case CMD_SECONDS: {
0184:                    if (objv.length != 2) {
0185:                        throw new TclNumArgsException(interp, 2, objv, null);
0186:                    }
0187:                    long millis = System.currentTimeMillis();
0188:                    int seconds = (int) (millis / 1000);
0189:                    interp.setResult(seconds);
0190:                    break;
0191:                }
0192:                }
0193:            }
0194:
0195:            /**
0196:             *-----------------------------------------------------------------------------
0197:             *
0198:             * FormatClock --
0199:             *
0200:             *      Formats a time value based on seconds into a human readable
0201:             *	string.
0202:             *
0203:             * Results:
0204:             *      None.
0205:             *
0206:             * Side effects:
0207:             *      The interpreter will contain the formatted string as result.
0208:             *
0209:             *-----------------------------------------------------------------------------
0210:             */
0211:
0212:            private void FormatClock(Interp interp, // Current interpreter.
0213:                    int clockVal, // Time in seconds.
0214:                    boolean useGMT, // Boolean
0215:                    String format) // Format string
0216:                    throws TclException // A standard Tcl exception.
0217:            {
0218:                Date date = new Date((long) clockVal * 1000);
0219:                GregorianCalendar calendar = new GregorianCalendar();
0220:                SimpleDateFormat fmt, locFmt;
0221:                FieldPosition fp = new FieldPosition(0);
0222:                StringBuffer result = new StringBuffer();
0223:
0224:                if (format == null) {
0225:                    format = new String("%a %b %d %H:%M:%S %Z %Y");
0226:                }
0227:
0228:                if (useGMT) {
0229:                    calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
0230:                }
0231:                calendar.setTime(date);
0232:                fmt = new SimpleDateFormat("mm.dd.yy", Locale.US);
0233:                fmt.setCalendar(calendar);
0234:
0235:                if (format.equals("%Q")) { // Enterprise Stardate.
0236:                    int trekYear = calendar.get(Calendar.YEAR) + 377 - 2323;
0237:                    int trekDay = (calendar.get(Calendar.DAY_OF_YEAR) * 1000)
0238:                            / (calendar.isLeapYear(calendar.get(Calendar.YEAR)) ? 366
0239:                                    : 365);
0240:                    int trekHour = (calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar
0241:                            .get(Calendar.MINUTE)) / 144;
0242:
0243:                    interp.setResult("Stardate " + (trekYear < 10 ? "0" : "")
0244:                            + (trekYear * 1000 + trekDay) + '.' + trekHour);
0245:                    return;
0246:                }
0247:
0248:                for (int ix = 0; ix < format.length(); ix++) {
0249:                    if (format.charAt(ix) == '%' && ix + 1 < format.length()) {
0250:                        switch (format.charAt(++ix)) {
0251:                        case '%': // Insert a %. 
0252:                            result.append('%');
0253:                            break;
0254:                        case 'a': // Abbreviated weekday name (Mon, Tue, etc.). 
0255:                            fmt.applyPattern("EEE");
0256:                            fmt.format(date, result, fp);
0257:                            break;
0258:                        case 'A': // Full weekday name (Monday, Tuesday, etc.). 
0259:                            fmt.applyPattern("EEEE");
0260:                            fmt.format(date, result, fp);
0261:                            break;
0262:                        case 'b':
0263:                        case 'h': // Abbreviated month name (Jan,Feb,etc.). 
0264:                            fmt.applyPattern("MMM");
0265:                            fmt.format(date, result, fp);
0266:                            break;
0267:                        case 'B': // Full month name. 
0268:                            fmt.applyPattern("MMMM");
0269:                            fmt.format(date, result, fp);
0270:                            break;
0271:                        case 'c': // Locale specific date and time. 
0272:                            locFmt = (SimpleDateFormat) DateFormat
0273:                                    .getDateTimeInstance(DateFormat.SHORT,
0274:                                            DateFormat.SHORT);
0275:                            locFmt.setCalendar(calendar);
0276:                            locFmt.format(date, result, fp);
0277:                            break;
0278:                        case 'C': // Century (00 - 99).
0279:                            int century = calendar.get(Calendar.YEAR) / 100;
0280:                            result.append((century < 10 ? "0" : "") + century);
0281:                            break;
0282:                        case 'd': // Day of month (01 - 31). 
0283:                            fmt.applyPattern("dd");
0284:                            fmt.format(date, result, fp);
0285:                            break;
0286:                        case 'D': // Date as %m/%d/%y. 
0287:                            fmt.applyPattern("MM/dd/yy");
0288:                            fmt.format(date, result, fp);
0289:                            break;
0290:                        case 'e': // Day of month (1 - 31), no leading zeros. 
0291:                            fmt.applyPattern("d");
0292:                            String day = fmt.format(date);
0293:                            result.append((day.length() < 2 ? " " : "") + day);
0294:                            break;
0295:                        case 'H': // Hour in 24-hour format (00 - 23). 
0296:                            fmt.applyPattern("HH");
0297:                            fmt.format(date, result, fp);
0298:                            break;
0299:                        case 'I': // Hour in 12-hour format (01 - 12). 
0300:                            fmt.applyPattern("hh");
0301:                            fmt.format(date, result, fp);
0302:                            break;
0303:                        case 'j': // Day of year (001 - 366). 
0304:                            fmt.applyPattern("DDD");
0305:                            fmt.format(date, result, fp);
0306:                            break;
0307:                        case 'k': // Hour in 24-hour format (0 - 23), no leading zeros. 
0308:                            fmt.applyPattern("H");
0309:                            String h24 = fmt.format(date);
0310:                            result.append((h24.length() < 2 ? " " : "") + h24);
0311:                            break;
0312:                        case 'l': // Hour in 12-hour format (1 - 12), no leading zeros. 
0313:                            fmt.applyPattern("h");
0314:                            String h12 = fmt.format(date);
0315:                            result.append((h12.length() < 2 ? " " : "") + h12);
0316:                            break;
0317:                        case 'm': // Month number (01 - 12). 
0318:                            fmt.applyPattern("MM");
0319:                            fmt.format(date, result, fp);
0320:                            break;
0321:                        case 'M': // Minute (00 - 59). 
0322:                            fmt.applyPattern("mm");
0323:                            fmt.format(date, result, fp);
0324:                            break;
0325:                        case 'n': // Insert a newline. 
0326:                            result.append('\n');
0327:                            break;
0328:                        case 'p': // AM/PM indicator. 
0329:                            fmt.applyPattern("aa");
0330:                            fmt.format(date, result, fp);
0331:                            break;
0332:                        case 'r': // Time as %I:%M:%S %p. 
0333:                            fmt.applyPattern("KK:mm:ss aaaa");
0334:                            fmt.format(date, result, fp);
0335:                            break;
0336:                        case 'R': // Time as %H:%M. 
0337:                            fmt.applyPattern("hh:mm");
0338:                            fmt.format(date, result, fp);
0339:                            break;
0340:                        case 's': // seconds since epoch. 
0341:                            long millis = calendar.getTime().getTime();
0342:                            if (useGMT) {
0343:                                Calendar localCalendar = Calendar.getInstance();
0344:                                localCalendar.setTime(calendar.getTime());
0345:                                millis -= localCalendar
0346:                                        .get(Calendar.ZONE_OFFSET)
0347:                                        + localCalendar
0348:                                                .get(Calendar.DST_OFFSET);
0349:                            }
0350:                            result.append((int) (millis / 1000));
0351:                            break;
0352:                        case 'S': // Seconds (00 - 59). 
0353:                            fmt.applyPattern("ss");
0354:                            fmt.format(date, result, fp);
0355:                            break;
0356:                        case 't': // Insert a tab. 
0357:                            result.append('\t');
0358:                            break;
0359:                        case 'T': // Time as %H:%M:%S. 
0360:                            fmt.applyPattern("hh:mm:ss");
0361:                            fmt.format(date, result, fp);
0362:                            break;
0363:                        case 'u': // Weekday number (1 - 7) Sunday = 7. 
0364:                            int dayOfWeek17 = calendar
0365:                                    .get(Calendar.DAY_OF_WEEK);
0366:                            if (dayOfWeek17 == calendar.SUNDAY) {
0367:                                result.append(7);
0368:                            } else {
0369:                                result.append(dayOfWeek17 - Calendar.SUNDAY);
0370:                            }
0371:                            break;
0372:                        case 'U': // Week of year (01-52), Sunday is first day.
0373:                            int weekS = GetWeek(calendar, Calendar.SUNDAY,
0374:                                    false);
0375:                            result.append((weekS < 10 ? "0" : "") + weekS);
0376:                            break;
0377:                        case 'V': // ISO 8601 Week Of Year (01 - 53). 
0378:                            int isoWeek = GetWeek(calendar, Calendar.MONDAY,
0379:                                    true);
0380:                            result.append((isoWeek < 10 ? "0" : "") + isoWeek);
0381:                            break;
0382:                        case 'w': // Weekday number (0 - 6) Sunday = 0. 
0383:                            int dayOfWeek06 = calendar
0384:                                    .get(Calendar.DAY_OF_WEEK);
0385:                            result.append(dayOfWeek06 - calendar.SUNDAY);
0386:                            break;
0387:                        case 'W': // Week of year (01-52), Monday is first day. 
0388:                            int weekM = GetWeek(calendar, Calendar.MONDAY,
0389:                                    false);
0390:                            result.append((weekM < 10 ? "0" : "") + weekM);
0391:                            break;
0392:                        case 'x': // Locale specific date format. 
0393:                            locFmt = (SimpleDateFormat) DateFormat
0394:                                    .getDateInstance(DateFormat.SHORT);
0395:                            locFmt.setCalendar(calendar);
0396:                            locFmt.format(date, result, fp);
0397:                            break;
0398:                        case 'X': // Locale specific time format. 
0399:                            locFmt = (SimpleDateFormat) DateFormat
0400:                                    .getTimeInstance(DateFormat.SHORT);
0401:                            locFmt.setCalendar(calendar);
0402:                            locFmt.format(date, result, fp);
0403:                            break;
0404:                        case 'y': // Year without century (00 - 99). 
0405:                            fmt.applyPattern("yy");
0406:                            fmt.format(date, result, fp);
0407:                            break;
0408:                        case 'Y': // Year with century (e.g. 1990) 
0409:                            fmt.applyPattern("yyyy");
0410:                            fmt.format(date, result, fp);
0411:                            break;
0412:                        case 'Z': // Time zone name. 
0413:                            fmt.applyPattern("zzz");
0414:                            fmt.format(date, result, fp);
0415:                            break;
0416:                        default:
0417:                            result.append(format.charAt(ix));
0418:                            break;
0419:                        }
0420:                    } else {
0421:                        result.append(format.charAt(ix));
0422:                    }
0423:                }
0424:                interp.setResult(result.toString());
0425:            }
0426:
0427:            /**
0428:             *-----------------------------------------------------------------------------
0429:             *
0430:             * GetWeek --
0431:             *
0432:             *      Returns the week_of_year of the given date.
0433:             *	The weekday considered as start of the week is given as argument.
0434:             *	Specify iso as true to get the week_of_year accourding to ISO.
0435:             *
0436:             * Results:
0437:             *      Day of the week .
0438:             *
0439:             * Side effects:
0440:             *      The interpreter will contain the formatted string as result.
0441:             *
0442:             *-----------------------------------------------------------------------------
0443:             */
0444:
0445:            private int GetWeek(Calendar calendar, // Calendar containing Date.
0446:                    int firstDayOfWeek, // this day starts a week (MONDAY/SUNDAY).
0447:                    boolean iso) // evaluate according to ISO?
0448:            {
0449:                if (iso) {
0450:                    firstDayOfWeek = Calendar.MONDAY;
0451:                }
0452:
0453:                // After changing the firstDayOfWeek, we have to set the time value anew,
0454:                // so that the fields of the calendar are recalculated.
0455:
0456:                calendar.setFirstDayOfWeek(firstDayOfWeek);
0457:                calendar.setMinimalDaysInFirstWeek(iso ? 4 : 7);
0458:                calendar.setTime(calendar.getTime());
0459:                int week = calendar.get(Calendar.WEEK_OF_YEAR);
0460:
0461:                if (!iso) {
0462:                    // The week for the first days of the year may be 52 or 53.
0463:                    // But here we have to return 0, if we don't compute ISO week.
0464:                    // So any bigger than 50th week in January will become 00.
0465:
0466:                    if (calendar.get(Calendar.MONTH) == Calendar.JANUARY
0467:                            && week > 50) {
0468:                        week = 0;
0469:                    }
0470:                }
0471:
0472:                return week;
0473:            }
0474:
0475:            /**
0476:             *-----------------------------------------------------------------------------
0477:             *
0478:             * SetWeekday --
0479:             *
0480:             *      The date of the given calendar will be incremented, so that it will
0481:             *	match the weekday in the diff object. If dayOrdinal is bigger than 1,
0482:             *	additional weeks will be added.
0483:             *
0484:             * Results:
0485:             *      None.
0486:             *
0487:             * Side effects:
0488:             *      Modifies the given calendar.
0489:             *
0490:             *-----------------------------------------------------------------------------
0491:             */
0492:
0493:            private void SetWeekday(Calendar calendar, // Calendar containing Date.
0494:                    ClockRelTimespan diff) // time difference to evaluate
0495:            {
0496:                int weekday = diff.getWeekday();
0497:                int dayOrdinal = diff.getDayOrdinal();
0498:
0499:                while (calendar.get(Calendar.DAY_OF_WEEK) != weekday) {
0500:                    calendar.add(Calendar.DATE, 1);
0501:                }
0502:                if (dayOrdinal > 1) {
0503:                    calendar.add(Calendar.DATE, 7 * (dayOrdinal - 1));
0504:                }
0505:            }
0506:
0507:            /**
0508:             *-----------------------------------------------------------------------------
0509:             *
0510:             * SetOrdMonth --
0511:             *
0512:             *      The date of the given calendar will be incremented, so that it will
0513:             *	match the ordinal month in the diff object.
0514:             *
0515:             * Results:
0516:             *      None.
0517:             *
0518:             * Side effects:
0519:             *      Modifies the given calendar.
0520:             *
0521:             *-----------------------------------------------------------------------------
0522:             */
0523:
0524:            private void SetOrdMonth(Calendar calendar, // Calendar containing Date.
0525:                    ClockRelTimespan diff) // time difference to evaluate
0526:            {
0527:                int month = diff.getMonths();
0528:                int ordMonth = diff.getOrdMonth();
0529:
0530:                calendar.add(Calendar.MONTH, 1); /* we want to get the next month... */
0531:                while (calendar.get(Calendar.MONTH) != month) {
0532:                    calendar.add(Calendar.MONTH, 1);
0533:                }
0534:                if (ordMonth > 1) {
0535:                    calendar.add(Calendar.YEAR, ordMonth - 1);
0536:                }
0537:                calendar.set(Calendar.DAY_OF_MONTH, 1);
0538:                calendar.clear(Calendar.HOUR_OF_DAY);
0539:                calendar.clear(Calendar.MINUTE);
0540:                calendar.clear(Calendar.SECOND);
0541:            }
0542:
0543:            /**
0544:             *-----------------------------------------------------------------------------
0545:             *
0546:             * GetDate --
0547:             *
0548:             *      Scan a human readable date string and construct a Date.
0549:             *
0550:             * Results:
0551:             *      The scanned date (or null, if an error occured).
0552:             *
0553:             * Side effects:
0554:             *      None.
0555:             *
0556:             *-----------------------------------------------------------------------------
0557:             */
0558:
0559:            private Date GetDate(String dateString, // Date string to scan
0560:                    Date baseDate, // Date to use as base
0561:                    boolean useGMT) // Boolean
0562:            {
0563:                GregorianCalendar calendar = new GregorianCalendar();
0564:                Calendar now = Calendar.getInstance();
0565:                now.setTime(baseDate);
0566:                calendar.set(now.get(Calendar.YEAR), now.get(Calendar.MONTH),
0567:                        now.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
0568:                if (useGMT) {
0569:                    calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
0570:                }
0571:
0572:                ClockToken[] dt = GetTokens(dateString, false);
0573:
0574:                ParsePosition parsePos = new ParsePosition(0);
0575:                ClockRelTimespan diff = new ClockRelTimespan();
0576:                int hasTime = 0;
0577:                int hasZone = 0;
0578:                int hasDate = 0;
0579:                int hasDay = 0;
0580:                int hasOrdMonth = 0;
0581:                int hasRel = 0;
0582:
0583:                while (parsePos.getIndex() < dt.length) {
0584:                    if (ParseTime(dt, parsePos, calendar)) {
0585:                        hasTime++;
0586:                    } else if (ParseZone(dt, parsePos, calendar)) {
0587:                        hasZone++;
0588:                    } else if (ParseIso(dt, parsePos, calendar)) {
0589:                        hasDate++;
0590:                    } else if (ParseDate(dt, parsePos, calendar)) {
0591:                        hasDate++;
0592:                    } else if (ParseDay(dt, parsePos, diff)) {
0593:                        hasDay++;
0594:                    } else if (ParseOrdMonth(dt, parsePos, diff)) {
0595:                        hasOrdMonth++;
0596:                    } else if (ParseRelSpec(dt, parsePos, diff)) {
0597:                        hasRel++;
0598:                    } else if (ParseNumber(dt, parsePos, calendar, hasDate > 0
0599:                            && hasTime > 0 && hasRel == 0)) {
0600:                        if (hasDate == 0 || hasTime == 0 || hasRel > 0) {
0601:                            hasTime++;
0602:                        }
0603:                    } else if (ParseTrek(dt, parsePos, calendar)) {
0604:                        hasDate++;
0605:                        hasTime++;
0606:                    } else {
0607:                        return null;
0608:                    }
0609:                }
0610:
0611:                if (hasTime > 1 || hasZone > 1 || hasDate > 1 || hasDay > 1
0612:                        || hasOrdMonth > 1) {
0613:                    return null;
0614:                }
0615:
0616:                // The following line handles years that are specified using
0617:                // only two digits.  The line of code below implements a policy
0618:                // defined by the X/Open workgroup on the millinium rollover.
0619:                // Note: some of those dates may not actually be valid on some
0620:                // platforms.  The POSIX standard startes that the dates 70-99
0621:                // shall refer to 1970-1999 and 00-38 shall refer to 2000-2038.
0622:                // This later definition should work on all platforms.
0623:
0624:                int this Year = calendar.get(Calendar.YEAR);
0625:                if (this Year < 100) {
0626:                    if (this Year >= 69) {
0627:                        calendar.set(Calendar.YEAR, this Year + 1900);
0628:                    } else {
0629:                        calendar.set(Calendar.YEAR, this Year + 2000);
0630:                    }
0631:                }
0632:
0633:                if (hasRel > 0) {
0634:                    if (hasTime == 0 && hasDate == 0 && hasDay == 0) {
0635:                        calendar.setTime(baseDate);
0636:                    }
0637:                    // Certain JDK implementations are buggy WRT DST.
0638:                    // Work around this issue by adding a day instead
0639:                    // of a days worth of seconds.
0640:                    final int seconds_in_day = (60 * 60 * 24);
0641:                    int seconds = diff.getSeconds();
0642:                    boolean negative_seconds = (seconds < 0);
0643:                    int days = 0;
0644:                    if (negative_seconds)
0645:                        seconds *= -1;
0646:                    while (seconds >= seconds_in_day) {
0647:                        seconds -= seconds_in_day;
0648:                        days++;
0649:                    }
0650:                    if (negative_seconds) {
0651:                        seconds *= -1;
0652:                        days *= -1;
0653:                    }
0654:                    if (days != 0) {
0655:                        calendar.add(Calendar.DATE, days);
0656:                    }
0657:                    if (seconds != 0) {
0658:                        calendar.add(Calendar.SECOND, seconds);
0659:                    }
0660:                    calendar.add(Calendar.MONTH, diff.getMonths());
0661:                }
0662:
0663:                if (hasDay > 0 && hasDate == 0) {
0664:                    SetWeekday(calendar, diff);
0665:                }
0666:
0667:                if (hasOrdMonth > 0) {
0668:                    SetOrdMonth(calendar, diff);
0669:                }
0670:
0671:                return calendar.getTime();
0672:            }
0673:
0674:            /**
0675:             *-----------------------------------------------------------------------------
0676:             *
0677:             * ParseTime --
0678:             *
0679:             *      Parse a time string and sets the Calendar.
0680:             *	A time string is valid, if it confirms to the following yacc rule:
0681:             *	time    : tUNUMBER tMERIDIAN
0682:             *	        | tUNUMBER ':' tUNUMBER o_merid
0683:             *	        | tUNUMBER ':' tUNUMBER '-' tUNUMBER
0684:             *	        | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid
0685:             *	        | tUNUMBER ':' tUNUMBER ':' tUNUMBER '-' tUNUMBER
0686:             *	        ;
0687:             *
0688:             * Results:
0689:             *      True, if a time was read (parsePos was incremented and calendar
0690:             *	was set according to the read time); false otherwise.
0691:             *
0692:             * Side effects:
0693:             *      None.
0694:             *
0695:             *-----------------------------------------------------------------------------
0696:             */
0697:
0698:            private boolean ParseTime(ClockToken[] dt, // Input as scanned array of tokens
0699:                    ParsePosition parsePos, // Current position in input
0700:                    Calendar calendar) // calendar object to set
0701:            {
0702:                int pos = parsePos.getIndex();
0703:
0704:                if (pos + 6 < dt.length && dt[pos].isUNumber()
0705:                        && dt[pos + 1].is(':') && dt[pos + 2].isUNumber()
0706:                        && dt[pos + 3].is(':') && dt[pos + 4].isUNumber()
0707:                        && dt[pos + 5].is('-') && dt[pos + 6].isUNumber()) {
0708:                    ClockToken zone = GetTimeZoneFromRawOffset(-dt[pos + 6]
0709:                            .getInt() / 100);
0710:                    if (zone != null) {
0711:                        calendar.set(Calendar.HOUR_OF_DAY, dt[pos].getInt());
0712:                        calendar.set(Calendar.MINUTE, dt[pos + 2].getInt());
0713:                        calendar.set(Calendar.SECOND, dt[pos + 4].getInt());
0714:                        calendar.setTimeZone(zone.getZone());
0715:                        parsePos.setIndex(pos + 7);
0716:                        return true;
0717:                    }
0718:                }
0719:                if (pos + 4 < dt.length && dt[pos].isUNumber()
0720:                        && dt[pos + 1].is(':') && dt[pos + 2].isUNumber()
0721:                        && dt[pos + 3].is(':') && dt[pos + 4].isUNumber()) {
0722:                    parsePos.setIndex(pos + 5);
0723:                    ParseMeridianAndSetHour(dt, parsePos, calendar, dt[pos]
0724:                            .getInt());
0725:                    calendar.set(Calendar.MINUTE, dt[pos + 2].getInt());
0726:                    calendar.set(Calendar.SECOND, dt[pos + 4].getInt());
0727:                    return true;
0728:                }
0729:                if (pos + 4 < dt.length && dt[pos].isUNumber()
0730:                        && dt[pos + 1].is(':') && dt[pos + 2].isUNumber()
0731:                        && dt[pos + 3].is('-') && dt[pos + 4].isUNumber()) {
0732:                    ClockToken zone = GetTimeZoneFromRawOffset(-dt[pos + 4]
0733:                            .getInt() / 100);
0734:                    if (zone != null) {
0735:                        calendar.set(Calendar.HOUR_OF_DAY, dt[pos].getInt());
0736:                        calendar.set(Calendar.MINUTE, dt[pos + 2].getInt());
0737:                        calendar.setTimeZone(zone.getZone());
0738:                        parsePos.setIndex(pos + 5);
0739:                        return true;
0740:                    }
0741:                }
0742:                if (pos + 2 < dt.length && dt[pos].isUNumber()
0743:                        && dt[pos + 1].is(':') && dt[pos + 2].isUNumber()) {
0744:                    parsePos.setIndex(pos + 3);
0745:                    ParseMeridianAndSetHour(dt, parsePos, calendar, dt[pos]
0746:                            .getInt());
0747:                    calendar.set(Calendar.MINUTE, dt[pos + 2].getInt());
0748:                    return true;
0749:                }
0750:                if (pos + 1 < dt.length && dt[pos].isUNumber()
0751:                        && dt[pos + 1].is(ClockToken.MERIDIAN)) {
0752:                    parsePos.setIndex(pos + 1);
0753:                    ParseMeridianAndSetHour(dt, parsePos, calendar, dt[pos]
0754:                            .getInt());
0755:                    return true;
0756:                }
0757:                return false;
0758:            }
0759:
0760:            /**
0761:             *-----------------------------------------------------------------------------
0762:             *
0763:             * ParseZone --
0764:             *
0765:             *      Parse a timezone string and sets the Calendar.
0766:             *	A timezone string is valid, if it confirms to the following yacc rule:
0767:             *	zone    : tZONE tDST
0768:             *	        | tZONE
0769:             *	        | tDAYZONE
0770:             *	        ;
0771:             *
0772:             * Results:
0773:             *      True, if a timezone was read (parsePos was incremented and calendar
0774:             *	was set according to the read timezone); false otherwise.
0775:             *
0776:             * Side effects:
0777:             *      None.
0778:             *
0779:             *-----------------------------------------------------------------------------
0780:             */
0781:
0782:            private boolean ParseZone(ClockToken[] dt, // Input as scanned array of tokens
0783:                    ParsePosition parsePos, // Current position in input
0784:                    Calendar calendar) // calendar object to set
0785:            {
0786:                int pos = parsePos.getIndex();
0787:
0788:                if (pos + 1 < dt.length && dt[pos].is(ClockToken.ZONE)
0789:                        && dt[pos + 1].is(ClockToken.DST)) {
0790:                    calendar.setTimeZone(dt[pos].getZone());
0791:                    parsePos.setIndex(pos + 2);
0792:                    return true;
0793:                }
0794:                if (pos < dt.length && dt[pos].is(ClockToken.ZONE)) {
0795:                    calendar.setTimeZone(dt[pos].getZone());
0796:                    parsePos.setIndex(pos + 1);
0797:                    return true;
0798:                }
0799:                if (pos < dt.length && dt[pos].is(ClockToken.DAYZONE)) {
0800:                    calendar.setTimeZone(dt[pos].getZone());
0801:                    parsePos.setIndex(pos + 1);
0802:                    return true;
0803:                }
0804:                return false;
0805:            }
0806:
0807:            /**
0808:             *-----------------------------------------------------------------------------
0809:             *
0810:             * ParseDay --
0811:             *
0812:             *      Parse a day string and sets the Calendar.
0813:             *	A day string is valid, if it confirms to the following yacc rule:
0814:             *	day     : tDAY
0815:             *	        | tDAY ','
0816:             *	        | tUNUMBER tDAY
0817:             *	        | '+' tUNUMBER tDAY
0818:             *	        | '-' tUNUMBER tDAY
0819:             *	        | tNEXT tDAY
0820:             *	        ;
0821:             *
0822:             * Results:
0823:             *	True, if a day was read (parsePos was incremented and the time
0824:             *	difference was set according to the read day); false otherwise.
0825:             *
0826:             * Side effects:
0827:             *      None.
0828:             *
0829:             *-----------------------------------------------------------------------------
0830:             */
0831:
0832:            private boolean ParseDay(ClockToken[] dt, // Input as scanned array of tokens
0833:                    ParsePosition parsePos, // Current position in input
0834:                    ClockRelTimespan diff) // time difference to evaluate
0835:            {
0836:                int pos = parsePos.getIndex();
0837:
0838:                if (pos + 2 < dt.length && dt[pos].is('+')
0839:                        && dt[pos + 1].isUNumber()
0840:                        && dt[pos + 2].is(ClockToken.DAY)) {
0841:                    diff.setWeekday(dt[pos + 2].getInt(), dt[pos + 1].getInt());
0842:                    parsePos.setIndex(pos + 3);
0843:                    return true;
0844:                }
0845:                if (pos + 2 < dt.length && dt[pos].is('-')
0846:                        && dt[pos + 1].isUNumber()
0847:                        && dt[pos + 2].is(ClockToken.DAY)) {
0848:                    diff
0849:                            .setWeekday(dt[pos + 2].getInt(), -dt[pos + 1]
0850:                                    .getInt());
0851:                    parsePos.setIndex(pos + 3);
0852:                    return true;
0853:                }
0854:                if (pos + 1 < dt.length && dt[pos].is(ClockToken.NEXT)
0855:                        && dt[pos + 1].is(ClockToken.DAY)) {
0856:                    diff.setWeekday(dt[pos + 1].getInt(), 2);
0857:                    parsePos.setIndex(pos + 2);
0858:                    return true;
0859:                }
0860:                if (pos + 1 < dt.length && dt[pos].is(ClockToken.DAY)
0861:                        && dt[pos + 1].is(',')) {
0862:                    diff.setWeekday(dt[pos].getInt());
0863:                    parsePos.setIndex(pos + 2);
0864:                    return true;
0865:                }
0866:                if (pos + 1 < dt.length && dt[pos].isUNumber()
0867:                        && dt[pos + 1].is(ClockToken.DAY)) {
0868:                    diff.setWeekday(dt[pos + 1].getInt(), dt[pos].getInt());
0869:                    parsePos.setIndex(pos + 2);
0870:                    return true;
0871:                }
0872:                if (pos < dt.length && dt[pos].is(ClockToken.DAY)) {
0873:                    diff.setWeekday(dt[pos].getInt());
0874:                    parsePos.setIndex(pos + 1);
0875:                    return true;
0876:                }
0877:                return false;
0878:            }
0879:
0880:            /**
0881:             *-----------------------------------------------------------------------------
0882:             *
0883:             * ParseDate --
0884:             *
0885:             *      Parse a date string and sets the Calendar.
0886:             *	A date string is valid, if it confirms to the following yacc rule:
0887:             *	date	: tUNUMBER '/' tUNUMBER
0888:             *		| tUNUMBER '/' tUNUMBER '/' tUNUMBER
0889:             *		| tISOBASE
0890:             *	        | tUNUMBER '-' tMONTH '-' tUNUMBER
0891:             *	        | tUNUMBER '-' tUNUMBER '-' tUNUMBER
0892:             *		| tMONTH tUNUMBER
0893:             *		| tMONTH tUNUMBER ',' tUNUMBER
0894:             *		| tUNUMBER tMONTH
0895:             *		| tEPOCH
0896:             *		| tUNUMBER tMONTH tUNUMBER
0897:             *		;
0898:             *
0899:             * Results:
0900:             *      True, if a date was read (parsePos was incremented and calendar
0901:             *	was set according to the read day); false otherwise.
0902:             *
0903:             * Side effects:
0904:             *      None.
0905:             *
0906:             *-----------------------------------------------------------------------------
0907:             */
0908:
0909:            private boolean ParseDate(ClockToken[] dt, // Input as scanned array of tokens
0910:                    ParsePosition parsePos, // Current position in input
0911:                    Calendar calendar) // calendar object to set
0912:            {
0913:                int pos = parsePos.getIndex();
0914:
0915:                if (pos + 4 < dt.length && dt[pos].isUNumber()
0916:                        && dt[pos + 1].is('/') && dt[pos + 2].isUNumber()
0917:                        && dt[pos + 3].is('/') && dt[pos + 4].isUNumber()) {
0918:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos + 2].getInt());
0919:                    calendar.set(Calendar.MONTH, dt[pos].getInt() - 1);
0920:                    calendar.set(Calendar.YEAR, dt[pos + 4].getInt());
0921:                    parsePos.setIndex(pos + 5);
0922:                    return true;
0923:                }
0924:                if (pos + 4 < dt.length && dt[pos].isUNumber()
0925:                        && dt[pos + 1].is('-')
0926:                        && dt[pos + 2].is(ClockToken.MONTH)
0927:                        && dt[pos + 3].is('-') && dt[pos + 4].isUNumber()) {
0928:                    calendar.set(Calendar.YEAR, dt[pos + 4].getInt());
0929:                    calendar.set(Calendar.MONTH, dt[pos + 2].getInt());
0930:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos].getInt());
0931:                    parsePos.setIndex(pos + 5);
0932:                    return true;
0933:                }
0934:                if (pos + 4 < dt.length && dt[pos].isUNumber()
0935:                        && dt[pos + 1].is('-') && dt[pos + 2].isUNumber()
0936:                        && dt[pos + 3].is('-') && dt[pos + 4].isUNumber()) {
0937:                    calendar.set(Calendar.YEAR, dt[pos].getInt());
0938:                    calendar.set(Calendar.MONTH, dt[pos + 2].getInt() - 1);
0939:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos + 4].getInt());
0940:                    parsePos.setIndex(pos + 5);
0941:                    return true;
0942:                }
0943:                if (pos + 3 < dt.length && dt[pos].is(ClockToken.MONTH)
0944:                        && dt[pos + 1].isUNumber() && dt[pos + 2].is(',')
0945:                        && dt[pos + 3].isUNumber()) {
0946:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos + 1].getInt());
0947:                    calendar.set(Calendar.MONTH, dt[pos].getInt());
0948:                    calendar.set(Calendar.YEAR, dt[pos + 3].getInt());
0949:                    parsePos.setIndex(pos + 4);
0950:                    return true;
0951:                }
0952:                if (pos + 2 < dt.length && dt[pos].isUNumber()
0953:                        && dt[pos + 1].is('/') && dt[pos + 2].isUNumber()) {
0954:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos + 2].getInt());
0955:                    calendar.set(Calendar.MONTH, dt[pos].getInt() - 1);
0956:                    parsePos.setIndex(pos + 3);
0957:                    return true;
0958:                }
0959:                if (pos + 2 < dt.length && dt[pos].isUNumber()
0960:                        && dt[pos + 1].is(ClockToken.MONTH)
0961:                        && dt[pos + 2].isUNumber()) {
0962:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos].getInt());
0963:                    calendar.set(Calendar.MONTH, dt[pos + 1].getInt());
0964:                    calendar.set(Calendar.YEAR, dt[pos + 2].getInt());
0965:                    parsePos.setIndex(pos + 3);
0966:                    return true;
0967:                }
0968:                if (pos + 1 < dt.length && dt[pos].is(ClockToken.MONTH)
0969:                        && dt[pos + 1].isUNumber()) {
0970:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos + 1].getInt());
0971:                    calendar.set(Calendar.MONTH, dt[pos].getInt());
0972:                    parsePos.setIndex(pos + 2);
0973:                    return true;
0974:                }
0975:                if (pos + 1 < dt.length && dt[pos].isUNumber()
0976:                        && dt[pos + 1].is(ClockToken.MONTH)) {
0977:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos].getInt());
0978:                    calendar.set(Calendar.MONTH, dt[pos + 1].getInt());
0979:                    parsePos.setIndex(pos + 2);
0980:                    return true;
0981:                }
0982:                if (pos < dt.length && dt[pos].isIsoBase()) {
0983:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos].getInt() % 100);
0984:                    calendar.set(Calendar.MONTH,
0985:                            (dt[pos].getInt() % 10000) / 100 - 1);
0986:                    calendar.set(Calendar.YEAR, dt[pos].getInt() / 10000);
0987:                    parsePos.setIndex(pos + 1);
0988:                    return true;
0989:                }
0990:                if (pos < dt.length && dt[pos].is(ClockToken.EPOCH)) {
0991:                    calendar.set(Calendar.DAY_OF_MONTH, 1);
0992:                    calendar.set(Calendar.MONTH, 0);
0993:                    calendar.set(Calendar.YEAR, EPOCH_YEAR);
0994:                    parsePos.setIndex(pos + 1);
0995:                    return true;
0996:                }
0997:                return false;
0998:            }
0999:
1000:            /**
1001:             *-----------------------------------------------------------------------------
1002:             *
1003:             * ParseNumber --
1004:             *
1005:             *      Parse a number and sets the Calendar.
1006:             *	If argument mayBeYear is true, this number is conidered as year,
1007:             *	otherwise it is date and time in the form HHMM.
1008:             *
1009:             * Results:
1010:             *      True, if a number was read (parsePos was incremented and calendar
1011:             *	was set according to the read day); false otherwise.
1012:             *
1013:             * Side effects:
1014:             *      None.
1015:             *
1016:             *-----------------------------------------------------------------------------
1017:             */
1018:
1019:            private boolean ParseNumber(ClockToken[] dt, // Input as scanned array of tokens
1020:                    ParsePosition parsePos, // Current position in input
1021:                    Calendar calendar, // calendar object to set
1022:                    boolean mayBeYear) // number is considered to be year?
1023:            {
1024:                int pos = parsePos.getIndex();
1025:
1026:                if (pos < dt.length && dt[pos].isUNumber()) {
1027:                    parsePos.setIndex(pos + 1);
1028:                    if (mayBeYear) {
1029:                        calendar.set(Calendar.YEAR, dt[pos].getInt());
1030:                    } else {
1031:                        calendar.set(Calendar.HOUR_OF_DAY,
1032:                                dt[pos].getInt() / 100);
1033:                        calendar.set(Calendar.MINUTE, dt[pos].getInt() % 100);
1034:                        calendar.set(Calendar.SECOND, 0);
1035:                    }
1036:                    return true;
1037:                }
1038:                return false;
1039:            }
1040:
1041:            /**
1042:             *-----------------------------------------------------------------------------
1043:             *
1044:             * ParseRelSpec --
1045:             *
1046:             *      Parse a relative time specification and sets the time difference.
1047:             *	A relative time specification is valid, if it confirms to the
1048:             *	following yacc rule:
1049:             *	relspec : relunits tAGO
1050:             *		| relunits
1051:             *		;
1052:             *
1053:             * Results:
1054:             *      True, if a relative time specification was read (parsePos was
1055:             *	incremented and the time difference was set according to the read
1056:             *	relative time specification); false otherwise.
1057:             *
1058:             * Side effects:
1059:             *      None.
1060:             *
1061:             *-----------------------------------------------------------------------------
1062:             */
1063:
1064:            private boolean ParseRelSpec(ClockToken[] dt, // Input as scanned array of tokens
1065:                    ParsePosition parsePos, // Current position in input
1066:                    ClockRelTimespan diff) // time difference to evaluate
1067:            {
1068:                if (!ParseRelUnits(dt, parsePos, diff)) {
1069:                    return false;
1070:                }
1071:
1072:                int pos = parsePos.getIndex();
1073:                if (pos < dt.length && dt[pos].is(ClockToken.AGO)) {
1074:                    diff.negate();
1075:                    parsePos.setIndex(pos + 1);
1076:                }
1077:                return true;
1078:            }
1079:
1080:            /**
1081:             *-----------------------------------------------------------------------------
1082:             *
1083:             * ParseRelUnits --
1084:             *
1085:             *      Parse a relative time unit and sets the time difference.
1086:             *	A relative time unit is valid, if it confirms to the
1087:             *	following yacc rule:
1088:             *	relspec : '+' tUNUMBER unit
1089:             *		| '-' tUNUMBER unit
1090:             *	        | tUNUMBER unit
1091:             *	        | tNEXT unit
1092:             *	        | tNEXT tUNUMBER unit
1093:             *	        | unit
1094:             *		;
1095:             *
1096:             * Results:
1097:             *      True, if a relative time specification was read (parsePos was
1098:             *	incremented and the time difference was set according to the read
1099:             *	relative time specification); false otherwise.
1100:             *
1101:             * Side effects:
1102:             *      None.
1103:             *
1104:             *-----------------------------------------------------------------------------
1105:             */
1106:
1107:            private boolean ParseRelUnits(ClockToken[] dt, // Input as scanned array of tokens
1108:                    ParsePosition parsePos, // Current position in input
1109:                    ClockRelTimespan diff) // time difference to evaluate
1110:            {
1111:                int pos = parsePos.getIndex();
1112:
1113:                if (pos + 2 < dt.length && dt[pos].is('+')
1114:                        && dt[pos + 1].isUNumber() && dt[pos + 2].isUnit()) {
1115:                    diff.addUnit(dt[pos + 2], dt[pos + 1].getInt());
1116:                    parsePos.setIndex(pos + 3);
1117:                    return true;
1118:                }
1119:                if (pos + 2 < dt.length && dt[pos].is('-')
1120:                        && dt[pos + 1].isUNumber() && dt[pos + 2].isUnit()) {
1121:                    diff.addUnit(dt[pos + 2], -dt[pos + 1].getInt());
1122:                    parsePos.setIndex(pos + 3);
1123:                    return true;
1124:                }
1125:                if (pos + 1 < dt.length && dt[pos].isUNumber()
1126:                        && dt[pos + 1].isUnit()) {
1127:                    diff.addUnit(dt[pos + 1], dt[pos].getInt());
1128:                    parsePos.setIndex(pos + 2);
1129:                    return true;
1130:                } else if (pos + 2 < dt.length && dt[pos].is(ClockToken.NEXT)
1131:                        && dt[pos + 1].isUNumber() && dt[pos + 2].isUnit()) {
1132:                    diff.addUnit(dt[pos + 2], dt[pos + 1].getInt());
1133:                    parsePos.setIndex(pos + 3);
1134:                    return true;
1135:                }
1136:                if (pos + 1 < dt.length && dt[pos].is(ClockToken.NEXT)
1137:                        && dt[pos + 1].isUnit()) {
1138:                    diff.addUnit(dt[pos + 1]);
1139:                    parsePos.setIndex(pos + 2);
1140:                    return true;
1141:                }
1142:                if (pos < dt.length && dt[pos].isUnit()) {
1143:                    diff.addUnit(dt[pos]);
1144:                    parsePos.setIndex(pos + 1);
1145:                    return true;
1146:                }
1147:                return false;
1148:            }
1149:
1150:            /**
1151:             *-----------------------------------------------------------------------------
1152:             *
1153:             * ParseOrdMonth --
1154:             *
1155:             *      Parse a relative month and sets the date difference.
1156:             *	A relative month is valid, if it confirms to the
1157:             *	following yacc rule:
1158:             *	ordMonth: tNEXT tMONTH
1159:             *		| tNEXT tUNUMBER tMONTH
1160:             *		;
1161:             *
1162:             * Results:
1163:             *      True, if a relative month was read (parsePos was incremented and
1164:             *	the time difference was set according to the read relative time unit);
1165:             *	false otherwise.
1166:             *
1167:             * Side effects:
1168:             *      None.
1169:             *
1170:             *-----------------------------------------------------------------------------
1171:             */
1172:
1173:            private boolean ParseOrdMonth(ClockToken[] dt, // Input as scanned array of tokens
1174:                    ParsePosition parsePos, // Current position in input
1175:                    ClockRelTimespan diff) // time difference to evaluate
1176:            {
1177:                int pos = parsePos.getIndex();
1178:
1179:                if (pos + 2 < dt.length && dt[pos].is(ClockToken.NEXT)
1180:                        && dt[pos + 1].isUNumber()
1181:                        && dt[pos + 2].is(ClockToken.MONTH)) {
1182:                    diff
1183:                            .addOrdMonth(dt[pos + 2].getInt(), dt[pos + 1]
1184:                                    .getInt());
1185:                    parsePos.setIndex(pos + 3);
1186:                    return true;
1187:                }
1188:                if (pos + 1 < dt.length && dt[pos].is(ClockToken.NEXT)
1189:                        && dt[pos + 1].is(ClockToken.MONTH)) {
1190:                    diff.addOrdMonth(dt[pos + 1].getInt(), 1);
1191:                    parsePos.setIndex(pos + 2);
1192:                    return true;
1193:                }
1194:                return false;
1195:            }
1196:
1197:            /**
1198:             *-----------------------------------------------------------------------------
1199:             *
1200:             * ParseIso --
1201:             *
1202:             *      Parse an ISO 8601 point in time and sets the Calendar.
1203:             *	An ISO 8601 point in time is valid, if it confirms to the
1204:             *	following yacc rule:
1205:             *	iso     : tISOBASE tZONE tISOBASE
1206:             *	        | tISOBASE tZONE tUNUMBER ':' tUNUMBER ':' tUNUMBER
1207:             *		| tISOBASE tISOBASE
1208:             *		;
1209:             *
1210:             * Results:
1211:             *      True, if an ISO 8601 point in time was read (parsePos was incremented
1212:             *	and calendar was set according to the read point); false otherwise.
1213:             *
1214:             * Side effects:
1215:             *      None.
1216:             *
1217:             *-----------------------------------------------------------------------------
1218:             */
1219:
1220:            private boolean ParseIso(ClockToken[] dt, // Input as scanned array of tokens
1221:                    ParsePosition parsePos, // Current position in input
1222:                    Calendar calendar) // calendar object to set
1223:            {
1224:                int pos = parsePos.getIndex();
1225:
1226:                if (pos + 6 < dt.length && dt[pos].isIsoBase()
1227:                        && dt[pos + 1].is(ClockToken.ZONE)
1228:                        && dt[pos + 2].isUNumber() && dt[pos + 3].is(':')
1229:                        && dt[pos + 4].isUNumber() && dt[pos + 5].is(':')
1230:                        && dt[pos + 6].isUNumber()) {
1231:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos].getInt() % 100);
1232:                    calendar.set(Calendar.MONTH,
1233:                            (dt[pos].getInt() % 10000) / 100 - 1);
1234:                    calendar.set(Calendar.YEAR, dt[pos].getInt() / 10000);
1235:                    calendar.set(Calendar.HOUR_OF_DAY, dt[pos + 2].getInt());
1236:                    calendar.set(Calendar.MINUTE, dt[pos + 4].getInt());
1237:                    calendar.set(Calendar.SECOND, dt[pos + 6].getInt());
1238:                    parsePos.setIndex(pos + 7);
1239:                    return true;
1240:                }
1241:                if (pos + 2 < dt.length
1242:                        && dt[pos].isIsoBase()
1243:                        && dt[pos + 1].is(ClockToken.ZONE)
1244:                        && dt[pos + 1].getZone().getRawOffset() == -7
1245:                                * MILLIS_PER_HOUR && dt[pos + 2].isIsoBase()) {
1246:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos].getInt() % 100);
1247:                    calendar.set(Calendar.MONTH,
1248:                            (dt[pos].getInt() % 10000) / 100 - 1);
1249:                    calendar.set(Calendar.YEAR, dt[pos].getInt() / 10000);
1250:                    calendar.set(Calendar.HOUR_OF_DAY,
1251:                            dt[pos + 2].getInt() / 10000);
1252:                    calendar.set(Calendar.MINUTE,
1253:                            (dt[pos + 2].getInt() % 10000) / 100);
1254:                    calendar.set(Calendar.SECOND, dt[pos + 2].getInt() % 100);
1255:                    parsePos.setIndex(pos + 3);
1256:                    return true;
1257:                }
1258:                if (pos + 1 < dt.length && dt[pos].isIsoBase()
1259:                        && dt[pos + 1].isIsoBase()) {
1260:                    calendar.set(Calendar.DAY_OF_MONTH, dt[pos].getInt() % 100);
1261:                    calendar.set(Calendar.MONTH,
1262:                            (dt[pos].getInt() % 10000) / 100 - 1);
1263:                    calendar.set(Calendar.YEAR, dt[pos].getInt() / 10000);
1264:                    calendar.set(Calendar.HOUR_OF_DAY,
1265:                            dt[pos + 1].getInt() / 10000);
1266:                    calendar.set(Calendar.MINUTE,
1267:                            (dt[pos + 1].getInt() % 10000) / 100);
1268:                    calendar.set(Calendar.SECOND, dt[pos + 1].getInt() % 100);
1269:                    parsePos.setIndex(pos + 2);
1270:                    return true;
1271:                }
1272:                return false;
1273:            }
1274:
1275:            /**
1276:             *-----------------------------------------------------------------------------
1277:             *
1278:             * ParseTrek --
1279:             *
1280:             *      Parse a Stardate and sets the Calendar.
1281:             *	A Stardate is valid, if it confirms to the following yacc rule:
1282:             *	iso     : tSTARDATE tUNUMBER '.' tUNUMBER
1283:             *		;
1284:             *
1285:             * Results:
1286:             *      True, if a Stardate was read (parsePos was incremented
1287:             *	and calendar was set according to the read point); false otherwise.
1288:             *
1289:             * Side effects:
1290:             *      None.
1291:             *
1292:             *-----------------------------------------------------------------------------
1293:             */
1294:
1295:            private boolean ParseTrek(ClockToken[] dt, // Input as scanned array of tokens
1296:                    ParsePosition parsePos, // Current position in input
1297:                    GregorianCalendar calendar) // calendar object to set
1298:            {
1299:                int pos = parsePos.getIndex();
1300:
1301:                if (pos + 3 < dt.length && dt[pos].is(ClockToken.STARDATE)
1302:                        && dt[pos + 1].isUNumber() && dt[pos + 2].is('.')
1303:                        && dt[pos + 3].isUNumber()) {
1304:                    int trekYear = dt[pos + 1].getInt() / 1000 + 2323 - 377;
1305:                    int trekDay = 1 + ((dt[pos + 1].getInt() % 1000) * (calendar
1306:                            .isLeapYear(trekYear) ? 366 : 365)) / 1000;
1307:                    int trekSeconds = dt[pos + 3].getInt() * 144 * 60;
1308:                    calendar.set(Calendar.YEAR, trekYear);
1309:                    calendar.set(Calendar.DAY_OF_YEAR, trekDay);
1310:                    calendar.set(Calendar.SECOND, trekSeconds);
1311:                    parsePos.setIndex(pos + 4);
1312:                    return true;
1313:                }
1314:                return false;
1315:            }
1316:
1317:            /**
1318:             *-----------------------------------------------------------------------------
1319:             *
1320:             * ParseMeridianAndSetHour --
1321:             *
1322:             *      Parse a meridian and sets the hour field of the calendar.
1323:             *	A meridian is valid, if it confirms to the following yacc rule:
1324:             *	o_merid : // NULL
1325:             *		| tMERIDIAN
1326:             *		;
1327:             *
1328:             * Results:
1329:             *      None; parsePos was incremented and the claendar was set according
1330:             *	to the read meridian.
1331:             *
1332:             * Side effects:
1333:             *      None.
1334:             *
1335:             *-----------------------------------------------------------------------------
1336:             */
1337:
1338:            private void ParseMeridianAndSetHour(ClockToken[] dt, // Input as scanned array of tokens
1339:                    ParsePosition parsePos, // Current position in input
1340:                    Calendar calendar, // calendar object to set
1341:                    int hour) // hour value (1-12 or 0-23) to set.
1342:            {
1343:                int pos = parsePos.getIndex();
1344:                int hourField;
1345:
1346:                if (pos < dt.length && dt[pos].is(ClockToken.MERIDIAN)) {
1347:                    calendar.set(Calendar.AM_PM, dt[pos].getInt());
1348:                    parsePos.setIndex(pos + 1);
1349:                    hourField = Calendar.HOUR;
1350:                } else {
1351:                    hourField = Calendar.HOUR_OF_DAY;
1352:                }
1353:
1354:                if (hourField == Calendar.HOUR && hour == 12) {
1355:                    hour = 0;
1356:                }
1357:                calendar.set(hourField, hour);
1358:            }
1359:
1360:            /**
1361:             *-----------------------------------------------------------------------------
1362:             *
1363:             * GetTokens --
1364:             *
1365:             *      Lexical analysis of the input string.
1366:             *
1367:             * Results:
1368:             *      An array of ClockToken, representing the input string.
1369:             *
1370:             * Side effects:
1371:             *      None.
1372:             *
1373:             *-----------------------------------------------------------------------------
1374:             */
1375:
1376:            private ClockToken[] GetTokens(String in, // String to parse
1377:                    boolean debug) // Send the generated token list to stderr?
1378:            {
1379:                ParsePosition parsePos = new ParsePosition(0);
1380:                ClockToken dt;
1381:                ArrayList tokens = new ArrayList(in.length());
1382:
1383:                while ((dt = GetNextToken(in, parsePos)) != null) {
1384:                    tokens.add(dt);
1385:                }
1386:
1387:                ClockToken[] tokenArray = { (ClockToken) null };
1388:                tokenArray = (ClockToken[]) tokens.toArray(tokenArray);
1389:
1390:                if (debug) {
1391:                    for (int ix = 0; ix < tokenArray.length; ix++) {
1392:                        if (ix != 0) {
1393:                            System.err.print(",");
1394:                        }
1395:                        System.err.print(tokenArray[ix].toString());
1396:                    }
1397:                    System.err.println("");
1398:                }
1399:
1400:                return tokenArray;
1401:            }
1402:
1403:            /**
1404:             *-----------------------------------------------------------------------------
1405:             *
1406:             * GetNextToken --
1407:             *
1408:             *      Lexical analysis of the next token of input string.
1409:             *
1410:             * Results:
1411:             *      A ClockToken representing the next token of the input string,
1412:             *	(parsePos was incremented accordingly), if one was found.
1413:             *	null otherwise (e.g. at end of input).
1414:             *
1415:             * Side effects:
1416:             *      None.
1417:             *
1418:             *-----------------------------------------------------------------------------
1419:             */
1420:
1421:            private ClockToken GetNextToken(String in, // String to parse
1422:                    ParsePosition parsePos) // Current position in input
1423:            {
1424:                int pos = parsePos.getIndex();
1425:                int sign;
1426:
1427:                while (true) {
1428:                    while (pos < in.length()
1429:                            && Character.isSpaceChar(in.charAt(pos))) {
1430:                        pos++;
1431:                    }
1432:                    if (pos >= in.length()) {
1433:                        break;
1434:                    }
1435:
1436:                    char c = in.charAt(pos);
1437:                    if (Character.isDigit(c)) {
1438:                        int number = 0;
1439:                        int count = 0;
1440:                        while (pos < in.length()
1441:                                && Character.isDigit(c = in.charAt(pos))) {
1442:                            number = 10 * number + c - '0';
1443:                            pos++;
1444:                            count++;
1445:                        }
1446:                        parsePos.setIndex(pos);
1447:                        return new ClockToken(number, count >= 6);
1448:                    }
1449:                    if (Character.isLetter(c)) {
1450:                        int beginPos = pos;
1451:                        while (++pos < in.length()) {
1452:                            c = in.charAt(pos);
1453:                            if (!Character.isLetter(c) && c != '.') {
1454:                                break;
1455:                            }
1456:                        }
1457:                        parsePos.setIndex(pos);
1458:                        return LookupWord(in.substring(beginPos, pos));
1459:                    }
1460:                    parsePos.setIndex(pos + 1);
1461:                    return new ClockToken(in.charAt(pos));
1462:                }
1463:                parsePos.setIndex(pos + 1);
1464:                return null;
1465:            }
1466:
1467:            /**
1468:             *-----------------------------------------------------------------------------
1469:             *
1470:             * LookupWord --
1471:             *
1472:             *      Construct a ClockToken for the given word.
1473:             *
1474:             * Results:
1475:             *      A ClockToken representing the given word.
1476:             *
1477:             * Side effects:
1478:             *      None.
1479:             *
1480:             *-----------------------------------------------------------------------------
1481:             */
1482:
1483:            private ClockToken LookupWord(String word) // word to lookup
1484:            {
1485:                int ix;
1486:                String[] names;
1487:                String[][] zones;
1488:
1489:                if (word.equalsIgnoreCase("am")
1490:                        || word.equalsIgnoreCase("a.m.")) {
1491:                    return new ClockToken(ClockToken.MERIDIAN, Calendar.AM);
1492:                }
1493:                if (word.equalsIgnoreCase("pm")
1494:                        || word.equalsIgnoreCase("p.m.")) {
1495:                    return new ClockToken(ClockToken.MERIDIAN, Calendar.PM);
1496:                }
1497:
1498:                // See if we have an abbreviation for a day or month.
1499:
1500:                boolean abbrev;
1501:                if (word.length() == 3) {
1502:                    abbrev = true;
1503:                } else if (word.length() == 4 && word.charAt(3) == '.') {
1504:                    abbrev = true;
1505:                    word = word.substring(0, 3);
1506:                } else {
1507:                    abbrev = false;
1508:                }
1509:
1510:                DateFormatSymbols symbols = new DateFormatSymbols(Locale.US);
1511:                if (abbrev) {
1512:                    names = symbols.getShortMonths();
1513:                } else {
1514:                    names = symbols.getMonths();
1515:                }
1516:                for (ix = 0; ix < names.length; ix++) {
1517:                    if (word.equalsIgnoreCase(names[ix])) {
1518:                        return new ClockToken(ClockToken.MONTH, ix);
1519:                    }
1520:                }
1521:                if (abbrev) {
1522:                    names = symbols.getShortWeekdays();
1523:                } else {
1524:                    names = symbols.getWeekdays();
1525:                }
1526:                for (ix = 0; ix < names.length; ix++) {
1527:                    if (word.equalsIgnoreCase(names[ix])) {
1528:                        return new ClockToken(ClockToken.DAY, ix);
1529:                    }
1530:                }
1531:
1532:                // Drop out any periods and try the timezone table.
1533:
1534:                StringBuffer withoutDotsBuf = new StringBuffer(word.length());
1535:                for (ix = 0; ix < word.length(); ix++) {
1536:                    if (word.charAt(ix) != '.') {
1537:                        withoutDotsBuf.append(word.charAt(ix));
1538:                    }
1539:                }
1540:
1541:                String withoutDots = new String(withoutDotsBuf);
1542:                zones = symbols.getZoneStrings();
1543:
1544:                for (ix = 0; ix < zones.length; ix++) {
1545:                    if (withoutDots.equalsIgnoreCase(zones[ix][2])
1546:                            || withoutDots.equalsIgnoreCase(zones[ix][4])) {
1547:                        TimeZone zone = TimeZone.getTimeZone(zones[ix][0]);
1548:                        return new ClockToken(ClockToken.ZONE, zone);
1549:                    }
1550:                }
1551:                if (withoutDots.equalsIgnoreCase("dst")) {
1552:                    return new ClockToken(ClockToken.DST, null);
1553:                }
1554:
1555:                // Strip off any plural and try the units.
1556:
1557:                String singular;
1558:                if (word.endsWith("s")) {
1559:                    singular = word.substring(0, word.length() - 1);
1560:                } else {
1561:                    singular = word;
1562:                }
1563:                if (singular.equalsIgnoreCase("year")) {
1564:                    return new ClockToken(ClockToken.MONTH_UNIT, 12);
1565:                } else if (singular.equalsIgnoreCase("month")) {
1566:                    return new ClockToken(ClockToken.MONTH_UNIT, 1);
1567:                } else if (singular.equalsIgnoreCase("fortnight")) {
1568:                    return new ClockToken(ClockToken.MINUTE_UNIT, 14 * 24 * 60);
1569:                } else if (singular.equalsIgnoreCase("week")) {
1570:                    return new ClockToken(ClockToken.MINUTE_UNIT, 7 * 24 * 60);
1571:                } else if (singular.equalsIgnoreCase("day")) {
1572:                    return new ClockToken(ClockToken.MINUTE_UNIT, 24 * 60);
1573:                } else if (singular.equalsIgnoreCase("hour")) {
1574:                    return new ClockToken(ClockToken.MINUTE_UNIT, 60);
1575:                } else if (singular.equalsIgnoreCase("minute")) {
1576:                    return new ClockToken(ClockToken.MINUTE_UNIT, 1);
1577:                } else if (singular.equalsIgnoreCase("min")) {
1578:                    return new ClockToken(ClockToken.MINUTE_UNIT, 1);
1579:                } else if (singular.equalsIgnoreCase("second")) {
1580:                    return new ClockToken(ClockToken.SEC_UNIT, 1);
1581:                } else if (singular.equalsIgnoreCase("sec")) {
1582:                    return new ClockToken(ClockToken.SEC_UNIT, 1);
1583:                }
1584:
1585:                if (singular.equalsIgnoreCase("tomorrow")) {
1586:                    return new ClockToken(ClockToken.MINUTE_UNIT, 1 * 24 * 60);
1587:                } else if (singular.equalsIgnoreCase("yesterday")) {
1588:                    return new ClockToken(ClockToken.MINUTE_UNIT, -1 * 24 * 60);
1589:                } else if (singular.equalsIgnoreCase("today")) {
1590:                    return new ClockToken(ClockToken.MINUTE_UNIT, 0);
1591:                } else if (singular.equalsIgnoreCase("now")) {
1592:                    return new ClockToken(ClockToken.MINUTE_UNIT, 0);
1593:                } else if (singular.equalsIgnoreCase("last")) {
1594:                    return new ClockToken(-1, false);
1595:                } else if (singular.equalsIgnoreCase("this")) {
1596:                    return new ClockToken(ClockToken.MINUTE_UNIT, 0);
1597:                } else if (singular.equalsIgnoreCase("next")) {
1598:                    return new ClockToken(ClockToken.NEXT, 1);
1599:                } else if (singular.equalsIgnoreCase("ago")) {
1600:                    return new ClockToken(ClockToken.AGO, 1);
1601:                } else if (singular.equalsIgnoreCase("epoch")) {
1602:                    return new ClockToken(ClockToken.EPOCH, 0);
1603:                } else if (singular.equalsIgnoreCase("stardate")) {
1604:                    return new ClockToken(ClockToken.STARDATE, 0);
1605:                }
1606:
1607:                // Since a military timezone (T) is used in the clock test of 8.3,
1608:                // we can't ignore these timezones any longer...
1609:
1610:                if (withoutDots.length() == 1) {
1611:                    int rawOffset = 0;
1612:                    boolean found = true;
1613:                    char milTz = Character.toLowerCase(withoutDots.charAt(0));
1614:
1615:                    if (milTz >= 'a' && milTz <= 'm') {
1616:                        rawOffset = milTz - 'a' + 1;
1617:                    } else if (milTz >= 'n' && milTz < 'z') {
1618:                        rawOffset = 'n' - milTz - 1;
1619:                    } else if (milTz != 'z') {
1620:                        found = false;
1621:                    }
1622:                    if (found) {
1623:                        ClockToken zone = GetTimeZoneFromRawOffset(rawOffset);
1624:                        if (zone != null) {
1625:                            return zone;
1626:                        }
1627:                    }
1628:                }
1629:
1630:                return new ClockToken(word);
1631:            }
1632:
1633:            /**
1634:             *-----------------------------------------------------------------------------
1635:             *
1636:             * GetTimeZoneFromRawOffset --
1637:             *
1638:             *      Look for a timezone with the given offset (in hours) from gmt.
1639:             *
1640:             * Results:
1641:             *      A ClockToken representing the specified timezone.
1642:             *
1643:             * Side effects:
1644:             *      None.
1645:             *
1646:             *-----------------------------------------------------------------------------
1647:             */
1648:
1649:            private ClockToken GetTimeZoneFromRawOffset(int rawOffset // an offset to GMT (in hours).
1650:            ) {
1651:                String tzNames[] = TimeZone.getAvailableIDs(rawOffset
1652:                        * MILLIS_PER_HOUR);
1653:
1654:                if (tzNames.length > 0) {
1655:                    TimeZone zone = TimeZone.getTimeZone(tzNames[0]);
1656:                    return new ClockToken(ClockToken.ZONE, zone);
1657:                }
1658:                return null;
1659:            }
1660:
1661:        } // end ClockCmd
1662:
1663:        /**
1664:         *-----------------------------------------------------------------------------
1665:         *
1666:         * CLASS ClockToken --
1667:         *
1668:         *	An object of this class represents a lexical unit of the human
1669:         *	readable date string. It can be one of the following variants:
1670:         *
1671:         *	- unsigned number,
1672:         *	  = occurence can be asked by isUNumber(),
1673:         *	  = value can be retrieved by means of getInt();
1674:         *	- iso base date,
1675:         *	  = occurence can be asked by isIsoBase(),
1676:         *	  = value can be retrieved by means of getInt();
1677:         *	- a single character (delimiters like ':' or '/'),
1678:         *	  = occurence can be asked by is(), e.g. is('/');
1679:         *	- a word (like "January" or "DST")
1680:         *	  = occurence can be asked by is(), e.g. is(ClockToken.AGO);
1681:         *	  = value can be retrieved by means of getInt() or getZone().
1682:         *
1683:         *-----------------------------------------------------------------------------
1684:         */
1685:
1686:        class ClockToken {
1687:            final static int ISOBASE = 1;
1688:            final static int UNUMBER = 2;
1689:            final static int WORD = 3;
1690:            final static int CHAR = 4;
1691:            final static int MONTH = 5;
1692:            final static int DAY = 6;
1693:            final static int MONTH_UNIT = 7;
1694:            final static int MINUTE_UNIT = 8;
1695:            final static int SEC_UNIT = 9;
1696:            final static int AGO = 10;
1697:            final static int EPOCH = 11;
1698:            final static int ZONE = 12;
1699:            final static int DAYZONE = 13;
1700:            final static int DST = 14;
1701:            final static int MERIDIAN = 15;
1702:            final static int NEXT = 16;
1703:            final static int STARDATE = 17;
1704:
1705:            ClockToken(int number, boolean isIsoBase) {
1706:                this .kind = isIsoBase ? ISOBASE : UNUMBER;
1707:                this .number = number;
1708:            }
1709:
1710:            ClockToken(int kind, int number) {
1711:                this .kind = kind;
1712:                this .number = number;
1713:            }
1714:
1715:            ClockToken(int kind, TimeZone zone) {
1716:                this .kind = kind;
1717:                this .zone = zone;
1718:            }
1719:
1720:            ClockToken(String word) {
1721:                this .kind = WORD;
1722:                this .word = word;
1723:            }
1724:
1725:            ClockToken(char c) {
1726:                this .kind = CHAR;
1727:                this .c = c;
1728:            }
1729:
1730:            public boolean isUNumber() {
1731:                return kind == UNUMBER;
1732:            }
1733:
1734:            public boolean isIsoBase() {
1735:                return kind == ISOBASE;
1736:            }
1737:
1738:            public boolean is(char c) {
1739:                return this .kind == CHAR && this .c == c;
1740:            }
1741:
1742:            public boolean is(int kind) {
1743:                return this .kind == kind;
1744:            }
1745:
1746:            public boolean isUnit() {
1747:                return kind == MINUTE_UNIT || kind == MONTH_UNIT
1748:                        || kind == SEC_UNIT;
1749:            }
1750:
1751:            int getInt() {
1752:                return number;
1753:            }
1754:
1755:            TimeZone getZone() {
1756:                return zone;
1757:            }
1758:
1759:            public String toString() {
1760:                if (isUNumber()) {
1761:                    return "U" + Integer.toString(getInt());
1762:                } else if (isIsoBase()) {
1763:                    return "I" + Integer.toString(getInt());
1764:                } else if (kind == WORD) {
1765:                    return word;
1766:                } else if (kind == CHAR) {
1767:                    return new Character(c).toString();
1768:                } else if (kind == ZONE || kind == DAYZONE) {
1769:                    return zone.getID();
1770:                } else {
1771:                    return "(" + kind + "," + getInt() + ")";
1772:                }
1773:            }
1774:
1775:            private int kind;
1776:            private int number;
1777:            private String word;
1778:            private char c;
1779:            private TimeZone zone;
1780:        } // end ClockToken
1781:
1782:        /**
1783:         *-----------------------------------------------------------------------------
1784:         *
1785:         * CLASS ClockRelTimespan --
1786:         *
1787:         *	An object of this class can be used to track the time difference during
1788:         *	the analysis of a relative time specification.
1789:         *
1790:         *	It has four read only properties seconds, months, weekday and dayOrdinal,
1791:         *	which are set to 0 during initialization and which can be modified by
1792:         *	means of the addSeconds(), addMonths(), setWeekday() and negate() methods.
1793:         *
1794:         *-----------------------------------------------------------------------------
1795:         */
1796:
1797:        class ClockRelTimespan {
1798:            ClockRelTimespan() {
1799:                seconds = 0;
1800:                months = 0;
1801:                ordMonth = 0;
1802:                weekday = 0;
1803:                dayOrdinal = 0;
1804:            }
1805:
1806:            void addSeconds(int s) {
1807:                seconds += s;
1808:            }
1809:
1810:            void addMonths(int m) {
1811:                months += m;
1812:            }
1813:
1814:            void addOrdMonth(int m, int c) {
1815:                months = m;
1816:                ordMonth += c;
1817:            }
1818:
1819:            void addUnit(ClockToken unit, int amount) {
1820:                if (unit.is(ClockToken.SEC_UNIT)) {
1821:                    addSeconds(unit.getInt() * amount);
1822:                } else if (unit.is(ClockToken.MINUTE_UNIT)) {
1823:                    addSeconds(unit.getInt() * 60 * amount);
1824:                } else if (unit.is(ClockToken.MONTH_UNIT)) {
1825:                    addMonths(unit.getInt() * amount);
1826:                }
1827:            }
1828:
1829:            void addUnit(ClockToken unit) {
1830:                addUnit(unit, 1);
1831:            }
1832:
1833:            void setWeekday(int w, int ord) {
1834:                weekday = w;
1835:                dayOrdinal = ord;
1836:            }
1837:
1838:            void setWeekday(int w) {
1839:                setWeekday(w, 1);
1840:            }
1841:
1842:            void negate() {
1843:                seconds = -seconds;
1844:                months = -months;
1845:            }
1846:
1847:            int getSeconds() {
1848:                return seconds;
1849:            }
1850:
1851:            int getMonths() {
1852:                return months;
1853:            }
1854:
1855:            int getOrdMonth() {
1856:                return ordMonth;
1857:            }
1858:
1859:            int getWeekday() {
1860:                return weekday;
1861:            }
1862:
1863:            int getDayOrdinal() {
1864:                return dayOrdinal;
1865:            }
1866:
1867:            private int seconds;
1868:            private int months;
1869:            private int ordMonth;
1870:            private int weekday;
1871:            private int dayOrdinal;
1872:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.