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