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 Mktime(struct tm* inOutTm, time_t& timeOut);
virtual status_t Timegm(struct tm* inOutTm, time_t& timeOut);
private: private:
const char* _QueryLocale(int category); const char* _QueryLocale(int category);
const char* _SetPosixLocale(int category); const char* _SetPosixLocale(int category);
@@ -34,11 +34,17 @@ public:
status_t Mktime(struct tm* inOutTm, time_t& timeOut); status_t Mktime(struct tm* inOutTm, time_t& timeOut);
status_t Timegm(struct tm* inOutTm, time_t& timeOut);
private: private:
status_t _FillTmValues(const U_NAMESPACE_QUALIFIER status_t _FillTmValues(const U_NAMESPACE_QUALIFIER
TimeZone* icuTimeZone, TimeZone* icuTimeZone,
const time_t* inTime, struct tm* tmOut); 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; const ICUTimeData& fTimeData;
TimeConversionDataBridge* fDataBridge; TimeConversionDataBridge* fDataBridge;
@@ -157,6 +157,8 @@ public:
struct tm* tmOut) = 0; struct tm* tmOut) = 0;
virtual status_t Mktime(struct tm* inOutTm, time_t& timeOut) = 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; virtual void Initialize(LocaleDataBridge* dataBridge) = 0;
static status_t LoadBackend(); 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* const char*
ICULocaleBackend::_QueryLocale(int category) ICULocaleBackend::_QueryLocale(int category)
{ {
@@ -166,25 +166,15 @@ ICUTimeConversion::Gmtime(const time_t* inTime, struct tm* tmOut)
status_t status_t
ICUTimeConversion::Mktime(struct tm* inOutTm, time_t& timeOut) ICUTimeConversion::Mktime(struct tm* inOutTm, time_t& timeOut)
{ {
if (fTimeZone == NULL) return _Mktime(fTimeZone, inOutTm, timeOut);
return B_NO_INIT; }
UErrorCode icuStatus = U_ZERO_ERROR;
GregorianCalendar calendar(*fTimeZone, fTimeData.ICULocale(),
icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
calendar.setLenient(TRUE); status_t
calendar.set(inOutTm->tm_year + 1900, inOutTm->tm_mon, inOutTm->tm_mday, ICUTimeConversion::Timegm(struct tm* inOutTm, time_t& timeOut)
inOutTm->tm_hour, inOutTm->tm_min, inOutTm->tm_sec); {
const TimeZone* icuTimeZone = TimeZone::getGMT();
UDate timeInMillis = calendar.getTime(icuStatus); return _Mktime(icuTimeZone, inOutTm, timeOut);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
timeOut = (time_t)((int64_t)timeInMillis / 1000);
return _FillTmValues(fTimeZone, &timeOut, inOutTm);
} }
@@ -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 Libroot
} // namespace BPrivate } // namespace BPrivate
+28 -1
View File
@@ -33,10 +33,11 @@ long timezone = 0;
int daylight = 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. // 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" 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 __mktime_fallback(struct tm* tmp);
extern "C" time_t __timegm_fallback(struct tm* tmp);
extern "C" void extern "C" void
@@ -143,3 +144,29 @@ mktime(struct tm* inTm)
// implementation. // implementation.
return __mktime_fallback(inTm); 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); struct tm* __gmtime_r_fallback(const time_t* timep, struct tm* tmp);
time_t __mktime_fallback(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 lclmem;
static struct state gmtmem; static struct state gmtmem;
@@ -831,10 +831,8 @@ __mktime_fallback(struct tm* tmp)
} }
time_t time_t
timegm(tmp) __timegm_fallback(struct tm* const tmp)
struct tm * const tmp;
{ {
tmp->tm_isdst = 0; tmp->tm_isdst = 0;
return time1(tmp, gmtsub, 0L); return time1(tmp, gmtsub, 0L);