Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.util;
     18 
     19 import android.os.SystemClock;
     20 
     21 import libcore.util.TimeZoneFinder;
     22 import libcore.util.ZoneInfoDB;
     23 
     24 import java.io.PrintWriter;
     25 import java.text.SimpleDateFormat;
     26 import java.util.Calendar;
     27 import java.util.Date;
     28 /**
     29  * A class containing utility methods related to time zones.
     30  */
     31 public class TimeUtils {
     32     /** @hide */ public TimeUtils() {}
     33     /** {@hide} */
     34     private static SimpleDateFormat sLoggingFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     35 
     36     /**
     37      * Tries to return a time zone that would have had the specified offset
     38      * and DST value at the specified moment in the specified country.
     39      * Returns null if no suitable zone could be found.
     40      */
     41     public static java.util.TimeZone getTimeZone(
     42             int offset, boolean dst, long when, String country) {
     43 
     44         android.icu.util.TimeZone icuTimeZone = getIcuTimeZone(offset, dst, when, country);
     45         // We must expose a java.util.TimeZone here for API compatibility because this is a public
     46         // API method.
     47         return icuTimeZone != null ? java.util.TimeZone.getTimeZone(icuTimeZone.getID()) : null;
     48     }
     49 
     50     /**
     51      * Tries to return a frozen ICU time zone that would have had the specified offset
     52      * and DST value at the specified moment in the specified country.
     53      * Returns null if no suitable zone could be found.
     54      */
     55     private static android.icu.util.TimeZone getIcuTimeZone(
     56             int offset, boolean dst, long when, String country) {
     57         if (country == null) {
     58             return null;
     59         }
     60 
     61         android.icu.util.TimeZone bias = android.icu.util.TimeZone.getDefault();
     62         return TimeZoneFinder.getInstance()
     63                 .lookupTimeZoneByCountryAndOffset(country, offset, dst, when, bias);
     64     }
     65 
     66     /**
     67      * Returns a String indicating the version of the time zone database currently
     68      * in use.  The format of the string is dependent on the underlying time zone
     69      * database implementation, but will typically contain the year in which the database
     70      * was updated plus a letter from a to z indicating changes made within that year.
     71      *
     72      * <p>Time zone database updates should be expected to occur periodically due to
     73      * political and legal changes that cannot be anticipated in advance.  Therefore,
     74      * when computing the UTC time for a future event, applications should be aware that
     75      * the results may differ following a time zone database update.  This method allows
     76      * applications to detect that a database change has occurred, and to recalculate any
     77      * cached times accordingly.
     78      *
     79      * <p>The time zone database may be assumed to change only when the device runtime
     80      * is restarted.  Therefore, it is not necessary to re-query the database version
     81      * during the lifetime of an activity.
     82      */
     83     public static String getTimeZoneDatabaseVersion() {
     84         return ZoneInfoDB.getInstance().getVersion();
     85     }
     86 
     87     /** @hide Field length that can hold 999 days of time */
     88     public static final int HUNDRED_DAY_FIELD_LEN = 19;
     89 
     90     private static final int SECONDS_PER_MINUTE = 60;
     91     private static final int SECONDS_PER_HOUR = 60 * 60;
     92     private static final int SECONDS_PER_DAY = 24 * 60 * 60;
     93 
     94     /** @hide */
     95     public static final long NANOS_PER_MS = 1000000;
     96 
     97     private static final Object sFormatSync = new Object();
     98     private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+10];
     99     private static char[] sTmpFormatStr = new char[HUNDRED_DAY_FIELD_LEN+10];
    100 
    101     static private int accumField(int amt, int suffix, boolean always, int zeropad) {
    102         if (amt > 999) {
    103             int num = 0;
    104             while (amt != 0) {
    105                 num++;
    106                 amt /= 10;
    107             }
    108             return num + suffix;
    109         } else {
    110             if (amt > 99 || (always && zeropad >= 3)) {
    111                 return 3+suffix;
    112             }
    113             if (amt > 9 || (always && zeropad >= 2)) {
    114                 return 2+suffix;
    115             }
    116             if (always || amt > 0) {
    117                 return 1+suffix;
    118             }
    119         }
    120         return 0;
    121     }
    122 
    123     static private int printFieldLocked(char[] formatStr, int amt, char suffix, int pos,
    124             boolean always, int zeropad) {
    125         if (always || amt > 0) {
    126             final int startPos = pos;
    127             if (amt > 999) {
    128                 int tmp = 0;
    129                 while (amt != 0 && tmp < sTmpFormatStr.length) {
    130                     int dig = amt % 10;
    131                     sTmpFormatStr[tmp] = (char)(dig + '0');
    132                     tmp++;
    133                     amt /= 10;
    134                 }
    135                 tmp--;
    136                 while (tmp >= 0) {
    137                     formatStr[pos] = sTmpFormatStr[tmp];
    138                     pos++;
    139                     tmp--;
    140                 }
    141             } else {
    142                 if ((always && zeropad >= 3) || amt > 99) {
    143                     int dig = amt/100;
    144                     formatStr[pos] = (char)(dig + '0');
    145                     pos++;
    146                     amt -= (dig*100);
    147                 }
    148                 if ((always && zeropad >= 2) || amt > 9 || startPos != pos) {
    149                     int dig = amt/10;
    150                     formatStr[pos] = (char)(dig + '0');
    151                     pos++;
    152                     amt -= (dig*10);
    153                 }
    154                 formatStr[pos] = (char)(amt + '0');
    155                 pos++;
    156             }
    157             formatStr[pos] = suffix;
    158             pos++;
    159         }
    160         return pos;
    161     }
    162 
    163     private static int formatDurationLocked(long duration, int fieldLen) {
    164         if (sFormatStr.length < fieldLen) {
    165             sFormatStr = new char[fieldLen];
    166         }
    167 
    168         char[] formatStr = sFormatStr;
    169 
    170         if (duration == 0) {
    171             int pos = 0;
    172             fieldLen -= 1;
    173             while (pos < fieldLen) {
    174                 formatStr[pos++] = ' ';
    175             }
    176             formatStr[pos] = '0';
    177             return pos+1;
    178         }
    179 
    180         char prefix;
    181         if (duration > 0) {
    182             prefix = '+';
    183         } else {
    184             prefix = '-';
    185             duration = -duration;
    186         }
    187 
    188         int millis = (int)(duration%1000);
    189         int seconds = (int) Math.floor(duration / 1000);
    190         int days = 0, hours = 0, minutes = 0;
    191 
    192         if (seconds >= SECONDS_PER_DAY) {
    193             days = seconds / SECONDS_PER_DAY;
    194             seconds -= days * SECONDS_PER_DAY;
    195         }
    196         if (seconds >= SECONDS_PER_HOUR) {
    197             hours = seconds / SECONDS_PER_HOUR;
    198             seconds -= hours * SECONDS_PER_HOUR;
    199         }
    200         if (seconds >= SECONDS_PER_MINUTE) {
    201             minutes = seconds / SECONDS_PER_MINUTE;
    202             seconds -= minutes * SECONDS_PER_MINUTE;
    203         }
    204 
    205         int pos = 0;
    206 
    207         if (fieldLen != 0) {
    208             int myLen = accumField(days, 1, false, 0);
    209             myLen += accumField(hours, 1, myLen > 0, 2);
    210             myLen += accumField(minutes, 1, myLen > 0, 2);
    211             myLen += accumField(seconds, 1, myLen > 0, 2);
    212             myLen += accumField(millis, 2, true, myLen > 0 ? 3 : 0) + 1;
    213             while (myLen < fieldLen) {
    214                 formatStr[pos] = ' ';
    215                 pos++;
    216                 myLen++;
    217             }
    218         }
    219 
    220         formatStr[pos] = prefix;
    221         pos++;
    222 
    223         int start = pos;
    224         boolean zeropad = fieldLen != 0;
    225         pos = printFieldLocked(formatStr, days, 'd', pos, false, 0);
    226         pos = printFieldLocked(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0);
    227         pos = printFieldLocked(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0);
    228         pos = printFieldLocked(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0);
    229         pos = printFieldLocked(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0);
    230         formatStr[pos] = 's';
    231         return pos + 1;
    232     }
    233 
    234     /** @hide Just for debugging; not internationalized. */
    235     public static void formatDuration(long duration, StringBuilder builder) {
    236         synchronized (sFormatSync) {
    237             int len = formatDurationLocked(duration, 0);
    238             builder.append(sFormatStr, 0, len);
    239         }
    240     }
    241 
    242     /** @hide Just for debugging; not internationalized. */
    243     public static void formatDuration(long duration, StringBuilder builder, int fieldLen) {
    244         synchronized (sFormatSync) {
    245             int len = formatDurationLocked(duration, fieldLen);
    246             builder.append(sFormatStr, 0, len);
    247         }
    248     }
    249 
    250     /** @hide Just for debugging; not internationalized. */
    251     public static void formatDuration(long duration, PrintWriter pw, int fieldLen) {
    252         synchronized (sFormatSync) {
    253             int len = formatDurationLocked(duration, fieldLen);
    254             pw.print(new String(sFormatStr, 0, len));
    255         }
    256     }
    257 
    258     /** @hide Just for debugging; not internationalized. */
    259     public static String formatDuration(long duration) {
    260         synchronized (sFormatSync) {
    261             int len = formatDurationLocked(duration, 0);
    262             return new String(sFormatStr, 0, len);
    263         }
    264     }
    265 
    266     /** @hide Just for debugging; not internationalized. */
    267     public static void formatDuration(long duration, PrintWriter pw) {
    268         formatDuration(duration, pw, 0);
    269     }
    270 
    271     /** @hide Just for debugging; not internationalized. */
    272     public static void formatDuration(long time, long now, PrintWriter pw) {
    273         if (time == 0) {
    274             pw.print("--");
    275             return;
    276         }
    277         formatDuration(time-now, pw, 0);
    278     }
    279 
    280     /** @hide Just for debugging; not internationalized. */
    281     public static String formatUptime(long time) {
    282         final long diff = time - SystemClock.uptimeMillis();
    283         if (diff > 0) {
    284             return time + " (in " + diff + " ms)";
    285         }
    286         if (diff < 0) {
    287             return time + " (" + -diff + " ms ago)";
    288         }
    289         return time + " (now)";
    290     }
    291 
    292     /**
    293      * Convert a System.currentTimeMillis() value to a time of day value like
    294      * that printed in logs. MM-DD HH:MM:SS.MMM
    295      *
    296      * @param millis since the epoch (1/1/1970)
    297      * @return String representation of the time.
    298      * @hide
    299      */
    300     public static String logTimeOfDay(long millis) {
    301         Calendar c = Calendar.getInstance();
    302         if (millis >= 0) {
    303             c.setTimeInMillis(millis);
    304             return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c);
    305         } else {
    306             return Long.toString(millis);
    307         }
    308     }
    309 
    310     /** {@hide} */
    311     public static String formatForLogging(long millis) {
    312         if (millis <= 0) {
    313             return "unknown";
    314         } else {
    315             return sLoggingFormat.format(new Date(millis));
    316         }
    317     }
    318 }
    319