1 /*
   2  * Copyright (c) 2000, 2011, 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 
  26 import java.util.Locale;
  27 import sun.util.calendar.CalendarDate;
  28 import sun.util.calendar.CalendarSystem;
  29 import sun.util.calendar.Gregorian;
  30 
  31 /**
  32  * Time class represents the "AT" field and other time related information.
  33  *
  34  * @since 1.4
  35  */
  36 class 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 }