The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | #include <utils/TimeUtils.h> |
| 2 | #include <stdio.h> |
| 3 | #include <cutils/tztime.h> |
| 4 | |
| 5 | namespace android { |
| 6 | |
| 7 | static void |
| 8 | dump(const Time& t) |
| 9 | { |
| 10 | #ifdef HAVE_TM_GMTOFF |
| 11 | long tm_gmtoff = t.t.tm_gmtoff; |
| 12 | #else |
| 13 | long tm_gmtoff = 0; |
| 14 | #endif |
| 15 | printf("%04d-%02d-%02d %02d:%02d:%02d (%d,%ld,%d,%d)\n", |
| 16 | t.t.tm_year+1900, t.t.tm_mon+1, t.t.tm_mday, |
| 17 | t.t.tm_hour, t.t.tm_min, t.t.tm_sec, |
| 18 | t.t.tm_isdst, tm_gmtoff, t.t.tm_wday, t.t.tm_yday); |
| 19 | } |
| 20 | |
| 21 | Time::Time() |
| 22 | { |
| 23 | t.tm_sec = 0; |
| 24 | t.tm_min = 0; |
| 25 | t.tm_hour = 0; |
| 26 | t.tm_mday = 0; |
| 27 | t.tm_mon = 0; |
| 28 | t.tm_year = 0; |
| 29 | t.tm_wday = 0; |
| 30 | t.tm_yday = 0; |
| 31 | t.tm_isdst = -1; // we don't know, so let the C library determine |
| 32 | #ifdef HAVE_TM_GMTOFF |
| 33 | t.tm_gmtoff = 0; |
| 34 | #endif |
| 35 | } |
| 36 | |
| 37 | |
| 38 | #define COMPARE_FIELD(field) do { \ |
| 39 | int diff = a.t.field - b.t.field; \ |
| 40 | if (diff != 0) return diff; \ |
| 41 | } while(0) |
| 42 | |
| 43 | int |
| 44 | Time::compare(Time& a, Time& b) |
| 45 | { |
| 46 | if (0 == strcmp(a.timezone, b.timezone)) { |
| 47 | // if the timezones are the same, we can easily compare the two |
| 48 | // times. Otherwise, convert to milliseconds and compare that. |
| 49 | // This requires that object be normalized. |
| 50 | COMPARE_FIELD(tm_year); |
| 51 | COMPARE_FIELD(tm_mon); |
| 52 | COMPARE_FIELD(tm_mday); |
| 53 | COMPARE_FIELD(tm_hour); |
| 54 | COMPARE_FIELD(tm_min); |
| 55 | COMPARE_FIELD(tm_sec); |
| 56 | return 0; |
| 57 | } else { |
| 58 | int64_t am = a.toMillis(false /* use isDst */); |
| 59 | int64_t bm = b.toMillis(false /* use isDst */); |
| 60 | int64_t diff = am-bm; |
| 61 | return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0); |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | static const int DAYS_PER_MONTH[] = { |
| 66 | 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
| 67 | }; |
| 68 | |
| 69 | static inline int days_this_month(int year, int month) |
| 70 | { |
| 71 | int n = DAYS_PER_MONTH[month]; |
| 72 | if (n != 28) { |
| 73 | return n; |
| 74 | } else { |
| 75 | int y = year; |
| 76 | return ((y%4)==0&&((y%100)!=0||(y%400)==0)) ? 29 : 28; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | void |
| 81 | Time::switchTimezone(const char* timezone) |
| 82 | { |
| 83 | time_t seconds = mktime_tz(&(this->t), this->timezone); |
| 84 | localtime_tz(&seconds, &(this->t), timezone); |
| 85 | } |
| 86 | |
| 87 | String8 |
| 88 | Time::format(const char *format, const struct strftime_locale *locale) const |
| 89 | { |
| 90 | char buf[257]; |
| 91 | int n = strftime_tz(buf, 257, format, &(this->t), locale); |
| 92 | if (n > 0) { |
| 93 | return String8(buf); |
| 94 | } else { |
| 95 | return String8(); |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | static inline short |
| 100 | tochar(int n) |
| 101 | { |
| 102 | return (n >= 0 && n <= 9) ? ('0'+n) : ' '; |
| 103 | } |
| 104 | |
| 105 | static inline short |
| 106 | next_char(int *m, int k) |
| 107 | { |
| 108 | int n = *m / k; |
| 109 | *m = *m % k; |
| 110 | return tochar(n); |
| 111 | } |
| 112 | |
| 113 | void |
| 114 | Time::format2445(short* buf, bool hasTime) const |
| 115 | { |
| 116 | int n; |
| 117 | |
| 118 | n = t.tm_year+1900; |
| 119 | buf[0] = next_char(&n, 1000); |
| 120 | buf[1] = next_char(&n, 100); |
| 121 | buf[2] = next_char(&n, 10); |
| 122 | buf[3] = tochar(n); |
| 123 | |
| 124 | n = t.tm_mon+1; |
| 125 | buf[4] = next_char(&n, 10); |
| 126 | buf[5] = tochar(n); |
| 127 | |
| 128 | n = t.tm_mday; |
| 129 | buf[6] = next_char(&n, 10); |
| 130 | buf[7] = tochar(n); |
| 131 | |
| 132 | if (hasTime) { |
| 133 | buf[8] = 'T'; |
| 134 | |
| 135 | n = t.tm_hour; |
| 136 | buf[9] = next_char(&n, 10); |
| 137 | buf[10] = tochar(n); |
| 138 | |
| 139 | n = t.tm_min; |
| 140 | buf[11] = next_char(&n, 10); |
| 141 | buf[12] = tochar(n); |
| 142 | |
| 143 | n = t.tm_sec; |
| 144 | buf[13] = next_char(&n, 10); |
| 145 | buf[14] = tochar(n); |
| 146 | bool inUtc = strcmp("UTC", timezone) == 0; |
| 147 | if (inUtc) { |
| 148 | buf[15] = 'Z'; |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | String8 |
| 154 | Time::toString() const |
| 155 | { |
| 156 | String8 str; |
| 157 | char* s = str.lockBuffer(150); |
| 158 | #ifdef HAVE_TM_GMTOFF |
| 159 | long tm_gmtoff = t.tm_gmtoff; |
| 160 | #else |
| 161 | long tm_gmtoff = 0; |
| 162 | #endif |
| 163 | sprintf(s, "%04d%02d%02dT%02d%02d%02d%s(%d,%d,%ld,%d,%d)", |
| 164 | t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, |
| 165 | t.tm_sec, timezone, t.tm_wday, t.tm_yday, tm_gmtoff, t.tm_isdst, |
| 166 | (int)(((Time*)this)->toMillis(false /* use isDst */)/1000)); |
| 167 | str.unlockBuffer(); |
| 168 | return str; |
| 169 | } |
| 170 | |
| 171 | void |
| 172 | Time::setToNow() |
| 173 | { |
| 174 | time_t seconds; |
| 175 | time(&seconds); |
| 176 | localtime_tz(&seconds, &(this->t), this->timezone); |
| 177 | } |
| 178 | |
| 179 | int64_t |
| 180 | Time::toMillis(bool ignoreDst) |
| 181 | { |
| 182 | if (ignoreDst) { |
| 183 | this->t.tm_isdst = -1; |
| 184 | } |
| 185 | int64_t r = mktime_tz(&(this->t), this->timezone); |
| 186 | if (r == -1) |
| 187 | return -1; |
| 188 | return r * 1000; |
| 189 | } |
| 190 | |
| 191 | void |
| 192 | Time::set(int64_t millis) |
| 193 | { |
| 194 | time_t seconds = millis / 1000; |
| 195 | localtime_tz(&seconds, &(this->t), this->timezone); |
| 196 | } |
| 197 | |
| 198 | }; // namespace android |
| 199 | |