1 #include "TimeUtils.h"
2 #include <stdio.h>
3 #include <cutils/tztime.h>
4
5 namespace android {
6
7 static void
dump(const Time & t)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
Time()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
compare(Time & a,Time & b)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
days_this_month(int year,int month)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
switchTimezone(const char * timezone)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
format(const char * format,const struct strftime_locale * locale) const88 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
tochar(int n)100 tochar(int n)
101 {
102 return (n >= 0 && n <= 9) ? ('0'+n) : ' ';
103 }
104
105 static inline short
next_char(int * m,int k)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
format2445(short * buf,bool hasTime) const114 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
toString() const154 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
setToNow()172 Time::setToNow()
173 {
174 time_t seconds;
175 time(&seconds);
176 localtime_tz(&seconds, &(this->t), this->timezone);
177 }
178
179 int64_t
toMillis(bool ignoreDst)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
set(int64_t millis)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
200