2 * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
3 * Distributed under the terms of the MIT License.
7 #include "ICUTimeConversion.h"
13 #include <unicode/gregocal.h>
20 ICUTimeConversion::ICUTimeConversion(const ICUTimeData
& timeData
)
26 fTimeZoneID
[0] = '\0';
30 ICUTimeConversion::~ICUTimeConversion()
37 ICUTimeConversion::Initialize(TimeConversionDataBridge
* dataBridge
)
39 fDataBridge
= dataBridge
;
44 ICUTimeConversion::TZSet(const char* timeZoneID
, const char* tz
)
46 bool offsetHasBeenSet
= false;
48 // The given TZ environment variable's content overrides the default
51 // If the value given in the TZ env-var starts with a colon, that
52 // value is implementation specific, we expect a full timezone ID.
54 // nothing to do if the given name matches the current timezone
55 if (strcasecmp(fTimeZoneID
, tz
+ 1) == 0)
58 strlcpy(fTimeZoneID
, tz
+ 1, sizeof(fTimeZoneID
));
61 strlcpy(fTimeZoneID
, tz
, sizeof(fTimeZoneID
));
63 // nothing to do if the given name matches the current timezone
64 if (strcasecmp(fTimeZoneID
, fDataBridge
->addrOfTZName
[0]) == 0)
67 // parse TZ variable (only <std> and <offset> supported)
68 const char* tzNameEnd
= tz
;
69 while(isalpha(*tzNameEnd
))
71 if (*tzNameEnd
== '-' || *tzNameEnd
== '+') {
75 sscanf(tzNameEnd
+ 1, "%2d:%2d:%2d", &hours
, &minutes
,
77 hours
= min_c(24, max_c(0, hours
));
78 minutes
= min_c(59, max_c(0, minutes
));
79 seconds
= min_c(59, max_c(0, seconds
));
81 *fDataBridge
->addrOfTimezone
= (*tzNameEnd
== '-' ? -1 : 1)
82 * (hours
* 3600 + minutes
* 60 + seconds
);
83 offsetHasBeenSet
= true;
87 // nothing to do if the given name matches the current timezone
88 if (strcasecmp(fTimeZoneID
, timeZoneID
) == 0)
91 strlcpy(fTimeZoneID
, timeZoneID
, sizeof(fTimeZoneID
));
95 fTimeZone
= TimeZone::createTimeZone(fTimeZoneID
);
96 if (fTimeZone
== NULL
)
99 if (offsetHasBeenSet
) {
100 fTimeZone
->setRawOffset(*fDataBridge
->addrOfTimezone
* -1 * 1000);
104 UDate nowMillis
= 1000 * (UDate
)time(NULL
);
105 UErrorCode icuStatus
= U_ZERO_ERROR
;
106 fTimeZone
->getOffset(nowMillis
, FALSE
, rawOffset
, dstOffset
, icuStatus
);
107 if (!U_SUCCESS(icuStatus
)) {
108 *fDataBridge
->addrOfTimezone
= 0;
109 *fDataBridge
->addrOfDaylight
= false;
110 strcpy(fDataBridge
->addrOfTZName
[0], "GMT");
111 strcpy(fDataBridge
->addrOfTZName
[1], "GMT");
115 *fDataBridge
->addrOfTimezone
= -1 * (rawOffset
+ dstOffset
) / 1000;
116 // we want seconds, not the ms that ICU gives us
119 *fDataBridge
->addrOfDaylight
= fTimeZone
->useDaylightTime();
121 for (int i
= 0; i
< 2; ++i
) {
122 if (tz
!= NULL
&& *tz
!= ':' && i
== 0) {
123 strcpy(fDataBridge
->addrOfTZName
[0], fTimeZoneID
);
125 UnicodeString icuString
;
126 fTimeZone
->getDisplayName(i
== 1, TimeZone::SHORT
,
127 fTimeData
.ICULocaleForStrings(), icuString
);
128 CheckedArrayByteSink
byteSink(fDataBridge
->addrOfTZName
[i
],
129 sizeof(fTimeZoneID
));
130 icuString
.toUTF8(byteSink
);
132 // make sure to canonicalize "GMT+00:00" to just "GMT"
133 if (strcmp(fDataBridge
->addrOfTZName
[i
], "GMT+00:00") == 0)
134 fDataBridge
->addrOfTZName
[i
][3] = '\0';
143 ICUTimeConversion::Localtime(const time_t* inTime
, struct tm
* tmOut
)
145 if (fTimeZone
== NULL
)
148 tmOut
->tm_zone
= fTimeZoneID
;
149 return _FillTmValues(fTimeZone
, inTime
, tmOut
);
154 ICUTimeConversion::Gmtime(const time_t* inTime
, struct tm
* tmOut
)
156 const TimeZone
* icuTimeZone
= TimeZone::getGMT();
157 // no delete - doesn't belong to us
159 return _FillTmValues(icuTimeZone
, inTime
, tmOut
);
164 ICUTimeConversion::Mktime(struct tm
* inOutTm
, time_t& timeOut
)
166 if (fTimeZone
== NULL
)
169 UErrorCode icuStatus
= U_ZERO_ERROR
;
170 GregorianCalendar
calendar(*fTimeZone
, fTimeData
.ICULocale(),
172 if (!U_SUCCESS(icuStatus
))
175 calendar
.setLenient(TRUE
);
176 calendar
.set(inOutTm
->tm_year
+ 1900, inOutTm
->tm_mon
, inOutTm
->tm_mday
,
177 inOutTm
->tm_hour
, inOutTm
->tm_min
, inOutTm
->tm_sec
);
179 UDate timeInMillis
= calendar
.getTime(icuStatus
);
180 if (!U_SUCCESS(icuStatus
))
182 timeOut
= (time_t)((int64_t)timeInMillis
/ 1000);
184 return _FillTmValues(fTimeZone
, &timeOut
, inOutTm
);
189 ICUTimeConversion::_FillTmValues(const TimeZone
* icuTimeZone
,
190 const time_t* inTime
, struct tm
* tmOut
)
192 UErrorCode icuStatus
= U_ZERO_ERROR
;
193 GregorianCalendar
calendar(*icuTimeZone
, fTimeData
.ICULocale(), icuStatus
);
194 if (!U_SUCCESS(icuStatus
))
197 calendar
.setTime(1000 * (UDate
)*inTime
, icuStatus
);
198 if (!U_SUCCESS(icuStatus
))
201 tmOut
->tm_sec
= calendar
.get(UCAL_SECOND
, icuStatus
);
202 if (!U_SUCCESS(icuStatus
))
204 tmOut
->tm_min
= calendar
.get(UCAL_MINUTE
, icuStatus
);
205 if (!U_SUCCESS(icuStatus
))
207 tmOut
->tm_hour
= calendar
.get(UCAL_HOUR_OF_DAY
, icuStatus
);
208 if (!U_SUCCESS(icuStatus
))
210 tmOut
->tm_mday
= calendar
.get(UCAL_DAY_OF_MONTH
, icuStatus
);
211 if (!U_SUCCESS(icuStatus
))
213 tmOut
->tm_mon
= calendar
.get(UCAL_MONTH
, icuStatus
);
214 if (!U_SUCCESS(icuStatus
))
216 tmOut
->tm_year
= calendar
.get(UCAL_YEAR
, icuStatus
) - 1900;
217 if (!U_SUCCESS(icuStatus
))
219 tmOut
->tm_wday
= calendar
.get(UCAL_DAY_OF_WEEK
, icuStatus
) - 1;
220 if (!U_SUCCESS(icuStatus
))
222 tmOut
->tm_yday
= calendar
.get(UCAL_DAY_OF_YEAR
, icuStatus
) - 1;
223 if (!U_SUCCESS(icuStatus
))
225 tmOut
->tm_isdst
= calendar
.inDaylightTime(icuStatus
);
226 if (!U_SUCCESS(icuStatus
))
228 tmOut
->tm_gmtoff
= (calendar
.get(UCAL_ZONE_OFFSET
, icuStatus
)
229 + calendar
.get(UCAL_DST_OFFSET
, icuStatus
)) / 1000;
230 if (!U_SUCCESS(icuStatus
))
232 tmOut
->tm_zone
= fDataBridge
->addrOfTZName
[tmOut
->tm_isdst
? 1 : 0];
238 } // namespace Libroot
239 } // namespace BPrivate