001    /* ============================================================
002     * JRobin : Pure java implementation of RRDTool's functionality
003     * ============================================================
004     *
005     * Project Info:  http://www.jrobin.org
006     * Project Lead:  Sasa Markovic (saxon@jrobin.org);
007     *
008     * (C) Copyright 2003-2005, by Sasa Markovic.
009     *
010     * Developers:    Sasa Markovic (saxon@jrobin.org)
011     *
012     *
013     * This library is free software; you can redistribute it and/or modify it under the terms
014     * of the GNU Lesser General Public License as published by the Free Software Foundation;
015     * either version 2.1 of the License, or (at your option) any later version.
016     *
017     * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
018     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
019     * See the GNU Lesser General Public License for more details.
020     *
021     * You should have received a copy of the GNU Lesser General Public License along with this
022     * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
023     * Boston, MA 02111-1307, USA.
024     */
025    
026    package org.jrobin.core.timespec;
027    
028    import org.jrobin.core.RrdException;
029    import org.jrobin.core.Util;
030    
031    import java.util.Calendar;
032    import java.util.Date;
033    import java.util.GregorianCalendar;
034    
035    /**
036     * Simple class to represent time obtained by parsing at-style date specification (described
037     * in detail on the rrdfetch man page. See javadoc for {@link org.jrobin.core.timespec.TimeParser}
038     * for more information.
039     */
040    public class TimeSpec {
041            static final int TYPE_ABSOLUTE = 0;
042            static final int TYPE_START = 1;
043            static final int TYPE_END = 2;
044    
045            int type = TYPE_ABSOLUTE;
046            int year, month, day, hour, min, sec;
047            int wday;
048            int dyear, dmonth, dday, dhour, dmin, dsec;
049    
050            String dateString;
051    
052            TimeSpec context;
053    
054            TimeSpec(String dateString) {
055                    this.dateString = dateString;
056            }
057    
058            void localtime(long timestamp) {
059                    GregorianCalendar date = new GregorianCalendar();
060                    date.setTime(new Date(timestamp * 1000L));
061                    year = date.get(Calendar.YEAR) - 1900;
062                    month = date.get(Calendar.MONTH);
063                    day = date.get(Calendar.DAY_OF_MONTH);
064                    hour = date.get(Calendar.HOUR_OF_DAY);
065                    min = date.get(Calendar.MINUTE);
066                    sec = date.get(Calendar.SECOND);
067                    wday = date.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY;
068            }
069    
070            GregorianCalendar getTime() throws RrdException {
071                    GregorianCalendar gc;
072                    // absoulte time, this is easy
073                    if (type == TYPE_ABSOLUTE) {
074                            gc = new GregorianCalendar(year + 1900, month, day, hour, min, sec);
075                    }
076                    // relative time, we need a context to evaluate it
077                    else if (context != null && context.type == TYPE_ABSOLUTE) {
078                            gc = context.getTime();
079                    }
080                    // how would I guess what time it was?
081                    else {
082                            throw new RrdException("Relative times like '" +
083                                            dateString + "' require proper absolute context to be evaluated");
084                    }
085                    gc.add(Calendar.YEAR, dyear);
086                    gc.add(Calendar.MONTH, dmonth);
087                    gc.add(Calendar.DAY_OF_MONTH, dday);
088                    gc.add(Calendar.HOUR_OF_DAY, dhour);
089                    gc.add(Calendar.MINUTE, dmin);
090                    gc.add(Calendar.SECOND, dsec);
091                    return gc;
092            }
093    
094            /**
095             * Returns the corresponding timestamp (seconds since Epoch). Example:<p>
096             * <pre>
097             * TimeParser p = new TimeParser("now-1day");
098             * TimeSpec ts = p.parse();
099             * System.out.println("Timestamp was: " + ts.getTimestamp();
100             * </pre>
101             *
102             * @return Timestamp (in seconds, no milliseconds)
103             * @throws RrdException Thrown if this TimeSpec object does not represent absolute time.
104             */
105            public long getTimestamp() throws RrdException {
106                    return Util.getTimestamp(getTime());
107            }
108    
109            String dump() {
110                    return (type == TYPE_ABSOLUTE ? "ABSTIME" : type == TYPE_START ? "START" : "END") +
111                                    ": " + year + "/" + month + "/" + day +
112                                    "/" + hour + "/" + min + "/" + sec + " (" +
113                                    dyear + "/" + dmonth + "/" + dday +
114                                    "/" + dhour + "/" + dmin + "/" + dsec + ")";
115            }
116    
117            /**
118             * Use this static method to resolve relative time references and obtain the corresponding
119             * Calendar objects. Example:<p>
120             * <pre>
121             * TimeParser pStart = new TimeParser("now-1month"); // starting time
122             * TimeParser pEnd = new TimeParser("start+1week");  // ending time
123             * TimeSpec specStart = pStart.parse();
124             * TimeSpec specEnd = pEnd.parse();
125             * GregorianCalendar[] gc = TimeSpec.getTimes(specStart, specEnd);
126             * </pre>
127             *
128             * @param spec1 Starting time specification
129             * @param spec2 Ending time specification
130             * @return Two element array containing Calendar objects
131             * @throws RrdException Thrown if relative time references cannot be resolved
132             */
133            public static Calendar[] getTimes(TimeSpec spec1, TimeSpec spec2) throws RrdException {
134                    if (spec1.type == TYPE_START || spec2.type == TYPE_END) {
135                            throw new RrdException("Recursive time specifications not allowed");
136                    }
137                    spec1.context = spec2;
138                    spec2.context = spec1;
139                    return new Calendar[] {
140                                    spec1.getTime(),
141                                    spec2.getTime()
142                    };
143            }
144    
145            /**
146             * Use this static method to resolve relative time references and obtain the corresponding
147             * timestamps (seconds since epoch). Example:<p>
148             * <pre>
149             * TimeParser pStart = new TimeParser("now-1month"); // starting time
150             * TimeParser pEnd = new TimeParser("start+1week");  // ending time
151             * TimeSpec specStart = pStart.parse();
152             * TimeSpec specEnd = pEnd.parse();
153             * long[] ts = TimeSpec.getTimestamps(specStart, specEnd);
154             * </pre>
155             *
156             * @param spec1 Starting time specification
157             * @param spec2 Ending time specification
158             * @return array containing two timestamps (in seconds since epoch)
159             * @throws RrdException Thrown if relative time references cannot be resolved
160             */
161            public static long[] getTimestamps(TimeSpec spec1, TimeSpec spec2) throws RrdException {
162                    Calendar[] gcs = getTimes(spec1, spec2);
163                    return new long[] {
164                                    Util.getTimestamp(gcs[0]), Util.getTimestamp(gcs[1])
165                    };
166            }
167    }
168