1/*
2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26import java.util.Locale;
27import sun.util.calendar.CalendarDate;
28import sun.util.calendar.CalendarSystem;
29import sun.util.calendar.Gregorian;
30
31/**
32 * Time class represents the "AT" field and other time related information.
33 *
34 * @since 1.4
35 */
36class Time {
37
38    static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
39
40    // type is wall clock time
41    private static final int WALL = 1;
42
43    // type is standard time
44    private static final int STD = 2;
45
46    // type is UTC
47    private static final int UTC = 3;
48
49    // type of representing time
50    private int type;
51
52    /**
53     * Time from the EPOCH in milliseconds
54     */
55    private long time;
56
57    /**
58     * Current time in milliseconds
59     */
60    private static final long currentTime = System.currentTimeMillis();
61
62    Time() {
63        time = 0L;
64    }
65
66    Time(long time) {
67        this.time = time;
68    }
69
70    void setType(int type) {
71        this.type = type;
72    }
73
74    long getTime() {
75        return time;
76    }
77
78    int getType() {
79        return type;
80    }
81
82    static long getCurrentTime() {
83        return currentTime;
84    }
85
86    /**
87     * @return true if the time is represented in wall-clock time.
88     */
89    boolean isWall() {
90        return type == WALL;
91    }
92
93    /**
94     * @return true if the time is represented in standard time.
95     */
96    boolean isSTD() {
97        return type == STD;
98    }
99
100    /**
101     * @return true if the time is represented in UTC time.
102     */
103    boolean isUTC() {
104        return type == UTC;
105    }
106
107    /**
108     * Converts the type to a string that represents the type in the
109     * SimpleTimeZone time mode. (e.g., "SimpleTimeZone.WALL_TIME").
110     * @return the converted string or null if the type is undefined.
111     */
112    String getTypeForSimpleTimeZone() {
113        String  stz = "SimpleTimeZone.";
114        if (isWall()) {
115            return stz+"WALL_TIME";
116        }
117        else if (isSTD()) {
118            return stz+"STANDARD_TIME";
119        }
120        else if (isUTC()) {
121            return stz+"UTC_TIME";
122        }
123        else {
124            return null;
125        }
126    }
127
128    /**
129     * Converts the given Gregorian calendar field values to local time.
130     * Local time is represented by the amount of milliseconds from
131     * January 1, 1970 0:00 GMT.
132     * @param year the year value
133     * @param month the Month value
134     * @param day the day represented by {@link RuleDay}
135     * @param save the amount of daylight time in milliseconds
136     * @param gmtOffset the GMT offset in milliseconds
137     * @param time the time of the day represented by {@link Time}
138     * @return local time
139     */
140    static long getLocalTime(int year, Month month, RuleDay day, int save,
141                             int gmtOffset, Time time) {
142        long    t = time.getTime();
143
144        if (time.isSTD())
145            t = time.getTime() + save;
146        else if (time.isUTC())
147            t = time.getTime() + save + gmtOffset;
148
149        return getLocalTime(year, month, day, t);
150    }
151
152    /**
153     * Converts the given Gregorian calendar field values to local time.
154     * Local time is represented by the amount of milliseconds from
155     * January 1, 1970 0:00 GMT.
156     * @param year the year value
157     * @param month the Month value
158     * @param day the day value
159     * @param time the time of the day in milliseconds
160     * @return local time
161     */
162    static long getLocalTime(int year, Month month, int day, long time) {
163        CalendarDate date = gcal.newCalendarDate(null);
164        date.setDate(year, month.value(), day);
165        long millis = gcal.getTime(date);
166        return millis + time;
167    }
168
169    /**
170     * Equivalent to <code>getLocalTime(year, month, day, (long)time)</code>.
171     * @param year the year value
172     * @param month the Month value
173     * @param day the day value
174     * @param time the time of the day in milliseconds
175     * @return local time
176     */
177    static long getLocalTime(int year, Month month, int day, int time) {
178        return getLocalTime(year, month, day, (long)time);
179    }
180
181    /**
182     * Equivalent to {@link #getLocalTime(int, Month, RuleDay, int)
183     * getLocalTime(year, month, day, (int) time)}.
184     * @param year the year value
185     * @param month the Month value
186     * @param day the day represented by {@link RuleDay}
187     * @param time the time of the day represented by {@link Time}
188     * @return local time
189     */
190    static long getLocalTime(int year, Month month, RuleDay day, long time) {
191        return getLocalTime(year, month, day, (int) time);
192    }
193
194    /**
195     * Converts the given Gregorian calendar field values to local time.
196     * Local time is represented by the amount of milliseconds from
197     * January 1, 1970 0:00 GMT.
198     * @param year the year value
199     * @param month the Month value
200     * @param day the day represented by {@link RuleDay}
201     * @param time the time of the day represented by {@link Time}
202     * @return local time
203     */
204    static long getLocalTime(int year, Month month, RuleDay day, int time) {
205        CalendarDate cdate = gcal.newCalendarDate(null);
206        int monthValue = month.value();
207
208        if (day.isLast()) {     // e.g., "lastSun"
209            cdate.setDate(year, monthValue, 1);
210            cdate.setDayOfMonth(gcal.getMonthLength(cdate));
211            cdate = gcal.getNthDayOfWeek(-1, day.getDayOfWeekNum(), cdate);
212        } else if (day.isLater()) { // e.g., "Sun>=1"
213            cdate.setDate(year, monthValue, day.getDay());
214            cdate = gcal.getNthDayOfWeek(1, day.getDayOfWeekNum(), cdate);
215        } else if (day.isExact()) {
216            cdate.setDate(year, monthValue, day.getDay());
217        } else if (day.isEarlier()) {   // e.g., "Sun<=15"
218            cdate.setDate(year, monthValue, day.getDay());
219            cdate = gcal.getNthDayOfWeek(-1, day.getDayOfWeekNum(), cdate);
220        } else {
221            Main.panic("invalid day type: " + day);
222        }
223        return gcal.getTime(cdate) + time;
224    }
225
226    /**
227     * Parses the given "AT" field and constructs a Time object.
228     * @param the "AT" field string
229     * @return the Time object
230     */
231    static Time parse(String time) {
232        int sign;
233        int index = 0;
234        Time tm;
235
236        if (time.charAt(0) == '-') {
237            sign = -1;
238            index++;
239        } else {
240            sign = 1;
241        }
242        int val = 0;
243        int num = 0;
244        int countDelim = 0;
245        while (index < time.length()) {
246            char c = time.charAt(index++);
247            if (c == ':') {
248                val = val * 60 + num;
249                countDelim++;
250                num = 0;
251                continue;
252            }
253            int d = Character.digit(c, 10);
254            if (d == -1) {
255                --index;
256                break;
257            }
258            num = num * 10 + d;
259        }
260        val = val * 60 + num;
261        // convert val to second
262        for (; countDelim < 2; countDelim++) {
263            val *= 60;
264        }
265        tm = new Time((long)val * 1000 * sign);
266        if (index < time.length()) {
267            char c = time.charAt(index++);
268            if (c == 's') {
269                tm.setType(Time.STD);
270            } else if (c == 'u' || c == 'g' || c == 'z') {
271                tm.setType(Time.UTC);
272            } else if (c == 'w') {
273                tm.setType(Time.WALL);
274            } else {
275                Main.panic("unknown time mode: "+c);
276            }
277        } else {
278            tm.setType(Time.WALL);
279        }
280        return tm;
281    }
282
283    /**
284     * Converts the given milliseconds string to a "[+-]hh:mm" string.
285     * @param ms the milliseconds string
286     */
287    static String toGMTFormat(String ms) {
288        long sec = Long.parseLong(ms) / 1000;
289        char sign;
290        if (sec < 0) {
291            sign = '-';
292            sec = -sec;
293        } else {
294            sign = '+';
295        }
296        return String.format((Locale)null, "%c%02d:%02d",
297                             sign, sec/3600, (sec%3600)/60);
298    }
299
300    /**
301     * Converts the given millisecond value to a string for a
302     * SimpleTimeZone parameter.
303     * @param ms the millisecond value
304     * @return the string in a human readable form
305     */
306    static String toFormedString(int ms) {
307        StringBuilder s = new StringBuilder();
308        boolean minus = false;
309
310        if (ms < 0) {
311            s.append("-");
312            minus = true;
313            ms = -ms;
314        } else if (ms == 0) {
315            return "0";
316        }
317
318        int hour = ms / (60 * 60 * 1000);
319        ms %= (60 * 60 * 1000);
320        int minute = ms / (60 * 1000);
321
322        if (hour != 0) {
323            if (minus && minute != 0) {
324                s.append("(");
325            }
326            s.append(Integer.toString(hour) + "*ONE_HOUR");
327        }
328
329        if (minute != 0) {
330            if (hour != 0) {
331                s.append("+");
332            }
333            s.append(Integer.toString(minute) + "*ONE_MINUTE");
334            if (minus && hour != 0) {
335                s.append(")");
336            }
337        }
338
339        return s.toString();
340    }
341}
342