libroot: implement timegm calling the ICU backend

Change-Id: Ib4de4288e061670acbc2edea3671cee029305d33
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3748
Reviewed-by: Axel Dörfler <[email protected]>
This commit is contained in:
Jérôme Duval
2021-02-24 05:51:44 +00:00
parent 02ccdc6fa1
commit c1e6e51a05
7 changed files with 82 additions and 22 deletions
@@ -73,6 +73,8 @@ public:
virtual status_t Mktime(struct tm* inOutTm, time_t& timeOut);
virtual status_t Timegm(struct tm* inOutTm, time_t& timeOut);
private:
const char* _QueryLocale(int category);
const char* _SetPosixLocale(int category);
@@ -34,11 +34,17 @@ public:
status_t Mktime(struct tm* inOutTm, time_t& timeOut);
status_t Timegm(struct tm* inOutTm, time_t& timeOut);
private:
status_t _FillTmValues(const U_NAMESPACE_QUALIFIER
TimeZone* icuTimeZone,
const time_t* inTime, struct tm* tmOut);
status_t _Mktime(const U_NAMESPACE_QUALIFIER
TimeZone* icuTimeZone,
struct tm* inOutTm, time_t& timeOut);
const ICUTimeData& fTimeData;
TimeConversionDataBridge* fDataBridge;
@@ -157,6 +157,8 @@ public:
struct tm* tmOut) = 0;
virtual status_t Mktime(struct tm* inOutTm, time_t& timeOut) = 0;
virtual status_t Timegm(struct tm* inOutTm, time_t& timeOut) = 0;
virtual void Initialize(LocaleDataBridge* dataBridge) = 0;
static status_t LoadBackend();
@@ -353,6 +353,15 @@ ICULocaleBackend::Mktime(struct tm* inOutTm, time_t& timeOut)
}
status_t
ICULocaleBackend::Timegm(struct tm* inOutTm, time_t& timeOut)
{
ErrnoMaintainer errnoMaintainer;
return fTimeConversion.Timegm(inOutTm, timeOut);
}
const char*
ICULocaleBackend::_QueryLocale(int category)
{
@@ -166,25 +166,15 @@ ICUTimeConversion::Gmtime(const time_t* inTime, struct tm* tmOut)
status_t
ICUTimeConversion::Mktime(struct tm* inOutTm, time_t& timeOut)
{
if (fTimeZone == NULL)
return B_NO_INIT;
return _Mktime(fTimeZone, inOutTm, timeOut);
}
UErrorCode icuStatus = U_ZERO_ERROR;
GregorianCalendar calendar(*fTimeZone, fTimeData.ICULocale(),
icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
calendar.setLenient(TRUE);
calendar.set(inOutTm->tm_year + 1900, inOutTm->tm_mon, inOutTm->tm_mday,
inOutTm->tm_hour, inOutTm->tm_min, inOutTm->tm_sec);
UDate timeInMillis = calendar.getTime(icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
timeOut = (time_t)((int64_t)timeInMillis / 1000);
return _FillTmValues(fTimeZone, &timeOut, inOutTm);
status_t
ICUTimeConversion::Timegm(struct tm* inOutTm, time_t& timeOut)
{
const TimeZone* icuTimeZone = TimeZone::getGMT();
return _Mktime(icuTimeZone, inOutTm, timeOut);
}
@@ -238,5 +228,31 @@ ICUTimeConversion::_FillTmValues(const TimeZone* icuTimeZone,
}
status_t
ICUTimeConversion::_Mktime(const TimeZone* icuTimeZone,
struct tm* inOutTm, time_t& timeOut)
{
if (icuTimeZone == NULL)
return B_NO_INIT;
UErrorCode icuStatus = U_ZERO_ERROR;
GregorianCalendar calendar(*icuTimeZone, fTimeData.ICULocale(),
icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
calendar.setLenient(TRUE);
calendar.set(inOutTm->tm_year + 1900, inOutTm->tm_mon, inOutTm->tm_mday,
inOutTm->tm_hour, inOutTm->tm_min, inOutTm->tm_sec);
UDate timeInMillis = calendar.getTime(icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
timeOut = (time_t)((int64_t)timeInMillis / 1000);
return _FillTmValues(icuTimeZone, &timeOut, inOutTm);
}
} // namespace Libroot
} // namespace BPrivate
+28 -1
View File
@@ -33,10 +33,11 @@ long timezone = 0;
int daylight = 0;
// These two functions are used as a fallback when the locale backend could not
// These three functions are used as a fallback when the locale backend could not
// be loaded. They are implemented in localtime_fading_out.c.
extern "C" struct tm* __gmtime_r_fallback(const time_t* timep, struct tm* tmp);
extern "C" time_t __mktime_fallback(struct tm* tmp);
extern "C" time_t __timegm_fallback(struct tm* tmp);
extern "C" void
@@ -143,3 +144,29 @@ mktime(struct tm* inTm)
// implementation.
return __mktime_fallback(inTm);
}
extern "C" time_t
timegm(struct tm* inTm)
{
if (inTm == NULL) {
__set_errno(EINVAL);
return -1;
}
tzset();
if (gLocaleBackend != NULL) {
time_t timeOut;
status_t status = gLocaleBackend->Timegm(inTm, timeOut);
if (status != B_OK) {
__set_errno(EOVERFLOW);
return -1;
}
return timeOut;
}
// without a locale backend, we fall back to using a basic timegm
// implementation.
return __timegm_fallback(inTm);
}
@@ -169,7 +169,7 @@ static int tmcomp P((const struct tm * atmp,
*/
struct tm* __gmtime_r_fallback(const time_t* timep, struct tm* tmp);
time_t __mktime_fallback(struct tm* tmp);
time_t timegm(struct tm* const tmp);
time_t __timegm_fallback(struct tm* const tmp);
static struct state lclmem;
static struct state gmtmem;
@@ -831,10 +831,8 @@ __mktime_fallback(struct tm* tmp)
}
time_t
timegm(tmp)
struct tm * const tmp;
__timegm_fallback(struct tm* const tmp)
{
tmp->tm_isdst = 0;
return time1(tmp, gmtsub, 0L);