Implement tzset(), gmtime(), localtime() and mktime() on top of ICU

* no longer keep a separate time-backend, since the implementation needs to
  access (data of) the locale backend anyway
* moved more stuff from localtime_fading_out.c to localtime.cpp
* added respective tests to locale_test
* added two more tests copied from glibc, test_time.c and tst-mktime.c


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38162 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Tappe
2010-08-16 21:14:23 +00:00
parent 6e23be561a
commit 560b10ff88
31 changed files with 1002 additions and 355 deletions
@@ -16,6 +16,7 @@
#include "ICUMessagesData.h"
#include "ICUMonetaryData.h"
#include "ICUNumericData.h"
#include "ICUTimeConversion.h"
#include "ICUTimeData.h"
@@ -44,6 +45,13 @@ public:
virtual status_t Strxfrm(char* out, const char* in, size_t size,
size_t& outSize);
virtual status_t TZSet(const char* timeZoneID);
virtual status_t Localtime(const time_t* inTime,
struct tm* tmOut);
virtual status_t Gmtime(const time_t* inTime, struct tm* tmOut);
virtual status_t Mktime(struct tm* inOutTm, time_t& timeOut);
private:
const char* _QueryLocale(int category);
const char* _SetPosixLocale(int category);
@@ -62,6 +70,7 @@ private:
ICUMonetaryData fMonetaryData;
ICUNumericData fNumericData;
ICUTimeData fTimeData;
ICUTimeConversion fTimeConversion;
// static posix langinfo data
const char** fPosixLanginfo;
@@ -0,0 +1,49 @@
/*
* Copyright 2010, Oliver Tappe, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _ICU_TIME_CONVERSION_H
#define _ICU_TIME_CONVERSION_H
#include <time.h>
#include "ICUTimeData.h"
#include "LocaleBackend.h"
namespace BPrivate {
class ICUTimeConversion {
public:
ICUTimeConversion(const ICUTimeData& timeData);
virtual ~ICUTimeConversion();
virtual void Initialize(
TimeConversionDataBridge* dataBridge);
status_t TZSet(const char* timeZoneID);
status_t Localtime(const time_t* inTime,
struct tm* tmOut);
status_t Gmtime(const time_t* inTime, struct tm* tmOut);
status_t Mktime(struct tm* inOutTm, time_t& timeOut);
private:
status_t _FillTmValues(const TimeZone* icuTimeZone,
const time_t* inTime, struct tm* tmOut);
const ICUTimeData& fTimeData;
TimeConversionDataBridge* fDataBridge;
char fTimeZoneID[64];
};
} // namespace BPrivate
#endif // _ICU_TIME_BACKEND_H
+5 -1
View File
@@ -21,6 +21,7 @@ class ICUTimeData : public ICUCategoryData {
typedef ICUCategoryData inherited;
public:
ICUTimeData(struct lc_time_t& lcTimeInfo);
~ICUTimeData();
void Initialize(LocaleTimeDataBridge* dataBridge);
@@ -30,6 +31,8 @@ public:
const char* GetLanginfo(int index);
const Locale& ICULocale() const;
private:
status_t _SetLCTimeEntries(const UnicodeString* strings,
char* destination, int entrySize,
@@ -52,7 +55,8 @@ private:
char fAmPmFormat[32];
struct lc_time_t& fLCTimeInfo;
const struct lc_time_t* fPosixLCTimeInfo;
LocaleTimeDataBridge* fDataBridge;
};
@@ -8,6 +8,7 @@
#include <SupportDefs.h>
#include <time.h>
#include <wctype.h>
@@ -64,12 +65,22 @@ struct LocaleTimeDataBridge {
};
struct TimeConversionDataBridge {
int* addrOfDaylight;
long* addrOfTimezone;
char** addrOfTZName;
TimeConversionDataBridge();
};
struct LocaleDataBridge {
LocaleCtypeDataBridge ctypeDataBridge;
LocaleMessagesDataBridge messagesDataBridge;
LocaleMonetaryDataBridge monetaryDataBridge;
LocaleNumericDataBridge numericDataBridge;
LocaleTimeDataBridge timeDataBridge;
TimeConversionDataBridge timeConversionDataBridge;
const char** posixLanginfo;
LocaleDataBridge();
@@ -96,6 +107,13 @@ public:
virtual status_t Strxfrm(char* out, const char* in, size_t size,
size_t& outSize) = 0;
virtual status_t TZSet(const char* timeZoneID) = 0;
virtual status_t Localtime(const time_t* inTime,
struct tm* tmOut) = 0;
virtual status_t Gmtime(const time_t* inTime,
struct tm* tmOut) = 0;
virtual status_t Mktime(struct tm* inOutTm, time_t& timeOut) = 0;
virtual void Initialize(LocaleDataBridge* dataBridge) = 0;
static status_t LoadBackend();
@@ -1,32 +0,0 @@
/*
* Copyright 2010, Oliver Tappe, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _ICU_TIME_BACKEND_H
#define _ICU_TIME_BACKEND_H
#include <TimeBackend.h>
namespace BPrivate {
class ICUTimeBackend : public TimeBackend {
public:
ICUTimeBackend();
virtual ~ICUTimeBackend();
virtual const status_t TZSet();
virtual void Initialize(TimeDataBridge* dataBridge);
private:
TimeDataBridge fDataBridge;
};
} // namespace BPrivate
#endif // _ICU_TIME_BACKEND_H
@@ -1,43 +0,0 @@
/*
* Copyright 2010, Oliver Tappe, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _TIME_BACKEND_H
#define _TIME_BACKEND_H
#include <SupportDefs.h>
namespace BPrivate {
struct TimeDataBridge {
int* addrOfDaylight;
long* addrOfTimezone;
char** addrOfTZName;
TimeDataBridge();
};
class TimeBackend {
public:
TimeBackend();
virtual ~TimeBackend();
virtual const status_t TZSet() = 0;
virtual void Initialize(TimeDataBridge* dataBridge) = 0;
static status_t LoadBackend();
};
extern TimeBackend* gTimeBackend;
} // namespace BPrivate
#endif // _TIME_BACKEND_H
-30
View File
@@ -1,30 +0,0 @@
/*
* Copyright 2010, Oliver Tappe, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _LOCALTIME_H
#define _LOCALTIME_H
#include <SupportDefs.h>
namespace BPrivate {
static const char* skPosixTimeZoneInfoFile = "libroot_timezone_info";
static const int skTimeZoneInfoNameMax = 32;
// holds persistent info set by Time preflet
struct time_zone_info {
char short_std_name[skTimeZoneInfoNameMax];
char short_dst_name[skTimeZoneInfoNameMax];
uint32 offset_from_gmt;
bool uses_daylight_saving;
};
} // namespace BPrivate
#endif // _LOCALTIME_H
@@ -29,7 +29,8 @@ ICULocaleBackend::ICULocaleBackend()
:
fMonetaryData(fLocaleConv),
fNumericData(fLocaleConv),
fTimeData(fLCTimeInfo)
fTimeData(fLCTimeInfo),
fTimeConversion(fTimeData)
{
}
@@ -49,6 +50,7 @@ ICULocaleBackend::Initialize(LocaleDataBridge* dataBridge)
fMonetaryData.Initialize(&dataBridge->monetaryDataBridge);
fNumericData.Initialize(&dataBridge->numericDataBridge);
fTimeData.Initialize(&dataBridge->timeDataBridge);
fTimeConversion.Initialize(&dataBridge->timeConversionDataBridge);
fPosixLanginfo = dataBridge->posixLanginfo;
@@ -242,6 +244,42 @@ ICULocaleBackend::Strxfrm(char* out, const char* in, size_t size,
}
status_t
ICULocaleBackend::TZSet(const char* timeZoneID)
{
ErrnoMaintainer errnoMaintainer;
return fTimeConversion.TZSet(timeZoneID);
}
status_t
ICULocaleBackend::Localtime(const time_t* inTime, struct tm* tmOut)
{
ErrnoMaintainer errnoMaintainer;
return fTimeConversion.Localtime(inTime, tmOut);
}
status_t
ICULocaleBackend::Gmtime(const time_t* inTime, struct tm* tmOut)
{
ErrnoMaintainer errnoMaintainer;
return fTimeConversion.Gmtime(inTime, tmOut);
}
status_t
ICULocaleBackend::Mktime(struct tm* inOutTm, time_t& timeOut)
{
ErrnoMaintainer errnoMaintainer;
return fTimeConversion.Mktime(inOutTm, timeOut);
}
const char*
ICULocaleBackend::_QueryLocale(int category)
{
@@ -0,0 +1,188 @@
/*
* Copyright 2010, Oliver Tappe, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "ICUTimeConversion.h"
#include <math.h>
#include <strings.h>
#include <unicode/gregocal.h>
#include <AutoDeleter.h>
namespace BPrivate {
ICUTimeConversion::ICUTimeConversion(const ICUTimeData& timeData)
:
fTimeData(timeData),
fDataBridge(NULL)
{
fTimeZoneID[0] = '\0';
}
ICUTimeConversion::~ICUTimeConversion()
{
}
void
ICUTimeConversion::Initialize(TimeConversionDataBridge* dataBridge)
{
fDataBridge = dataBridge;
}
status_t
ICUTimeConversion::TZSet(const char* timeZoneID)
{
// nothing to do if the given name matches any name of the current timezone
if (strcasecmp(fTimeZoneID, timeZoneID) == 0)
return B_OK;
strlcpy(fTimeZoneID, timeZoneID, sizeof(fTimeZoneID));
ObjectDeleter<TimeZone> icuTimeZone = TimeZone::createTimeZone(fTimeZoneID);
if (icuTimeZone.Get() == NULL)
return B_NO_MEMORY;
int32_t rawOffset;
int32_t dstOffset;
UDate nowMillis = 1000 * (UDate)time(NULL);
UErrorCode icuStatus = U_ZERO_ERROR;
icuTimeZone->getOffset(nowMillis, FALSE, rawOffset, dstOffset, icuStatus);
if (!U_SUCCESS(icuStatus)) {
*fDataBridge->addrOfTimezone = 0;
*fDataBridge->addrOfDaylight = false;
strcpy(fDataBridge->addrOfTZName[0], "GMT");
strcpy(fDataBridge->addrOfTZName[1], "GMT");
return B_ERROR;
}
*fDataBridge->addrOfTimezone = (rawOffset + dstOffset) / 1000;
// we want seconds, not ms (which ICU gives us)
*fDataBridge->addrOfDaylight = icuTimeZone->useDaylightTime();
for (int i = 0; i < 2; ++i) {
UnicodeString icuString;
icuTimeZone->getDisplayName(i == 1, TimeZone::SHORT_COMMONLY_USED,
fTimeData.ICULocale(), icuString);
CheckedArrayByteSink byteSink(fDataBridge->addrOfTZName[i],
sizeof(fTimeZoneID));
icuString.toUTF8(byteSink);
// make sure to canonicalize "GMT+00:00" to just "GMT"
if (strcmp(fDataBridge->addrOfTZName[i], "GMT+00:00") == 0)
fDataBridge->addrOfTZName[i][3] = '\0';
}
return B_OK;
}
status_t
ICUTimeConversion::Localtime(const time_t* inTime, struct tm* tmOut)
{
ObjectDeleter<TimeZone> icuTimeZone = TimeZone::createTimeZone(fTimeZoneID);
if (icuTimeZone.Get() == NULL)
return B_NO_MEMORY;
tmOut->tm_zone = fTimeZoneID;
return _FillTmValues(icuTimeZone.Get(), inTime, tmOut);
}
status_t
ICUTimeConversion::Gmtime(const time_t* inTime, struct tm* tmOut)
{
const TimeZone* icuTimeZone = TimeZone::getGMT();
// no delete - doesn't belong to us
return _FillTmValues(icuTimeZone, inTime, tmOut);
}
status_t
ICUTimeConversion::Mktime(struct tm* inOutTm, time_t& timeOut)
{
ObjectDeleter<TimeZone> icuTimeZone = TimeZone::createTimeZone(fTimeZoneID);
if (icuTimeZone.Get() == NULL)
return B_NO_MEMORY;
UErrorCode icuStatus = U_ZERO_ERROR;
GregorianCalendar calendar(*icuTimeZone.Get(), 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.Get(), &timeOut, inOutTm);
}
status_t
ICUTimeConversion::_FillTmValues(const TimeZone* icuTimeZone,
const time_t* inTime, struct tm* tmOut)
{
UErrorCode icuStatus = U_ZERO_ERROR;
GregorianCalendar calendar(*icuTimeZone, fTimeData.ICULocale(), icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
calendar.setTime(1000 * (UDate)*inTime, icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_sec = calendar.get(UCAL_SECOND, icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_min = calendar.get(UCAL_MINUTE, icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_hour = calendar.get(UCAL_HOUR_OF_DAY, icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_mday = calendar.get(UCAL_DAY_OF_MONTH, icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_mon = calendar.get(UCAL_MONTH, icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_year = calendar.get(UCAL_YEAR, icuStatus) - 1900;
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_wday = calendar.get(UCAL_DAY_OF_WEEK, icuStatus) - 1;
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_yday = calendar.get(UCAL_DAY_OF_YEAR, icuStatus) - 1;
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_isdst = calendar.inDaylightTime(icuStatus);
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_gmtoff = (calendar.get(UCAL_ZONE_OFFSET, icuStatus)
+ calendar.get(UCAL_DST_OFFSET, icuStatus)) / 1000;
if (!U_SUCCESS(icuStatus))
return B_ERROR;
tmOut->tm_zone = fDataBridge->addrOfTZName[tmOut->tm_isdst ? 1 : 0];
return B_OK;
}
} // namespace BPrivate
@@ -10,8 +10,11 @@
#include <strings.h>
#include <unicode/dtfmtsym.h>
#include <unicode/gregocal.h>
#include <unicode/smpdtfmt.h>
#include <AutoDeleter.h>
namespace BPrivate {
@@ -19,7 +22,7 @@ namespace BPrivate {
ICUTimeData::ICUTimeData(struct lc_time_t& lcTimeInfo)
:
fLCTimeInfo(lcTimeInfo),
fPosixLCTimeInfo(NULL)
fDataBridge(NULL)
{
for (int i = 0; i < 12; ++i) {
fLCTimeInfo.mon[i] = fMon[i];
@@ -41,10 +44,15 @@ ICUTimeData::ICUTimeData(struct lc_time_t& lcTimeInfo)
}
ICUTimeData::~ICUTimeData()
{
}
void
ICUTimeData::Initialize(LocaleTimeDataBridge* dataBridge)
{
fPosixLCTimeInfo = dataBridge->posixLCTimeInfo;
fDataBridge = dataBridge;
}
@@ -140,7 +148,7 @@ ICUTimeData::SetTo(const Locale& locale, const char* posixLocaleName)
count, 12);
}
strcpy(fAmPmFormat, fPosixLCTimeInfo->ampm_fmt);
strcpy(fAmPmFormat, fDataBridge->posixLCTimeInfo->ampm_fmt);
// ICU does not provide anything for this (and that makes sense, too)
return result;
@@ -154,22 +162,22 @@ ICUTimeData::SetToPosix()
if (result == B_OK) {
for (int i = 0; i < 12; ++i) {
strcpy(fMon[i], fPosixLCTimeInfo->mon[i]);
strcpy(fMonth[i], fPosixLCTimeInfo->month[i]);
strcpy(fAltMonth[i], fPosixLCTimeInfo->alt_month[i]);
strcpy(fMon[i], fDataBridge->posixLCTimeInfo->mon[i]);
strcpy(fMonth[i], fDataBridge->posixLCTimeInfo->month[i]);
strcpy(fAltMonth[i], fDataBridge->posixLCTimeInfo->alt_month[i]);
}
for (int i = 0; i < 7; ++i) {
strcpy(fWday[i], fPosixLCTimeInfo->wday[i]);
strcpy(fWeekday[i], fPosixLCTimeInfo->weekday[i]);
strcpy(fWday[i], fDataBridge->posixLCTimeInfo->wday[i]);
strcpy(fWeekday[i], fDataBridge->posixLCTimeInfo->weekday[i]);
}
strcpy(fTimeFormat, fPosixLCTimeInfo->X_fmt);
strcpy(fDateFormat, fPosixLCTimeInfo->x_fmt);
strcpy(fDateTimeFormat, fPosixLCTimeInfo->c_fmt);
strcpy(fAm, fPosixLCTimeInfo->am);
strcpy(fPm, fPosixLCTimeInfo->pm);
strcpy(fDateTimeZoneFormat, fPosixLCTimeInfo->date_fmt);
strcpy(fMonthDayOrder, fPosixLCTimeInfo->md_order);
strcpy(fAmPmFormat, fPosixLCTimeInfo->ampm_fmt);
strcpy(fTimeFormat, fDataBridge->posixLCTimeInfo->X_fmt);
strcpy(fDateFormat, fDataBridge->posixLCTimeInfo->x_fmt);
strcpy(fDateTimeFormat, fDataBridge->posixLCTimeInfo->c_fmt);
strcpy(fAm, fDataBridge->posixLCTimeInfo->am);
strcpy(fPm, fDataBridge->posixLCTimeInfo->pm);
strcpy(fDateTimeZoneFormat, fDataBridge->posixLCTimeInfo->date_fmt);
strcpy(fMonthDayOrder, fDataBridge->posixLCTimeInfo->md_order);
strcpy(fAmPmFormat, fDataBridge->posixLCTimeInfo->ampm_fmt);
}
return result;
@@ -397,4 +405,12 @@ ICUTimeData::_SetLCTimePattern(DateFormat* format, char* destination,
}
const Locale&
ICUTimeData::ICULocale() const
{
return fLocale;
}
} // namespace BPrivate
+24 -5
View File
@@ -1,14 +1,33 @@
SubDir HAIKU_TOP src system libroot add-ons icu ;
local addonIcuObjects =
addon_icu_locale.o
UsePrivateHeaders
libroot
[ FDirName libroot locale ]
[ FDirName libroot time ]
shared
;
local sources =
ICUCategoryData.cpp
ICUCollateData.cpp
ICUCtypeData.cpp
ICULocaleBackend.cpp
ICULocaleconvData.cpp
ICUMessagesData.cpp
ICUMonetaryData.cpp
ICUNumericData.cpp
ICUTimeConversion.cpp
ICUTimeData.cpp
;
SubDirSysHdrs $(HAIKU_ICU_HEADERS) ;
Includes [ FGristFiles $(sources) ] : $(HAIKU_ICU_HEADERS_DEPENDENCY) ;
# Dependency needed to trigger downloading/unzipping the package before
# compiling the files.
SharedLibrary libroot-addon-icu.so
: $(sources)
:
:
$(addonIcuObjects:G=nogrist)
$(TARGET_LIBSTDC++) $(HAIKU_ICU_LIBS)
;
SubInclude HAIKU_TOP src system libroot add-ons icu locale ;
@@ -1,26 +0,0 @@
SubDir HAIKU_TOP src system libroot add-ons icu locale ;
UsePrivateHeaders
libroot
[ FDirName libroot locale ]
[ FDirName libroot time ]
;
local sources =
ICUCategoryData.cpp
ICUCollateData.cpp
ICUCtypeData.cpp
ICULocaleBackend.cpp
ICULocaleconvData.cpp
ICUMessagesData.cpp
ICUMonetaryData.cpp
ICUNumericData.cpp
ICUTimeData.cpp
;
SubDirSysHdrs $(HAIKU_ICU_HEADERS) ;
Includes [ FGristFiles $(sources) ] : $(HAIKU_ICU_HEADERS_DEPENDENCY) ;
# Dependency needed to trigger downloading/unzipping the package before
# compiling the files.
MergeObject addon_icu_locale.o : $(sources) ;
@@ -1,85 +0,0 @@
/*
* Copyright 2010, Oliver Tappe, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "ICUTimeBackend.h"
#include <new>
#include <string.h>
#include <unicode/timezone.h>
#include <ErrnoMaintainer.h>
namespace BPrivate {
extern "C" TimeBackend*
CreateInstance()
{
return new(std::nothrow) ICUTimeBackend();
}
ICUTimeBackend::ICUTimeBackend()
{
}
ICUTimeBackend::~ICUTimeBackend()
{
}
void
ICUTimeBackend::Initialize(TimeDataBridge* dataBridge)
{
fDataBridge = dataBridge;
}
void
ICUTimeBackend::TZSet(void)
{
ErrnoMaintainer errnoMaintainer;
TimeZone* icuTimeZone;
if (zoneCode == NULL || zoneCode[0] == '\0')
icuTimeZone = TimeZone::createDefault();
else
icuTimeZone = TimeZone::createTimeZone(zoneCode);
UnicodeString unicodeString;
icuTimeZone->getID(unicodeString);
BStringByteSink converter(&fCode);
unicodeString.toUTF8(converter);
unicodeString.remove();
icuTimeZone->getDisplayName(unicodeString);
converter.SetTo(&fName);
unicodeString.toUTF8(converter);
int32_t rawOffset;
int32_t dstOffset;
UDate nowMillis = 1000 * (double)time(NULL);
UErrorCode error = U_ZERO_ERROR;
icuTimeZone->getOffset(nowMillis, FALSE, rawOffset, dstOffset, error);
if (!U_SUCCESS(error)) {
fOffsetFromGMT = 0;
fInitStatus = B_ERROR;
} else {
fOffsetFromGMT = (rawOffset + dstOffset) / 1000;
// we want seconds, not ms (which ICU gives us)
fInitStatus = B_OK;
}
delete icuTimeZone;
}
} // namespace BPrivate
+4 -2
View File
@@ -1,7 +1,9 @@
SubDir HAIKU_TOP src system libroot posix locale ;
UsePrivateHeaders [ FDirName libroot locale ] ;
UsePrivateHeaders [ FDirName libroot time ] ;
UsePrivateHeaders
[ FDirName libroot locale ]
[ FDirName libroot time ]
;
MergeObject posix_locale.o :
ctype.cpp
@@ -8,6 +8,7 @@
#include <ctype.h>
#include <langinfo.h>
#include <time.h>
#include <PosixCtype.h>
#include <PosixLanginfo.h>
@@ -85,6 +86,15 @@ LocaleTimeDataBridge::LocaleTimeDataBridge()
}
TimeConversionDataBridge::TimeConversionDataBridge()
:
addrOfDaylight(&daylight),
addrOfTimezone(&timezone),
addrOfTZName(tzname)
{
}
LocaleDataBridge::LocaleDataBridge()
:
posixLanginfo(gPosixLanginfo)
+4 -2
View File
@@ -4,8 +4,10 @@ SubDir HAIKU_TOP src system libroot posix time ;
SubDirCcFlags -DNOID -DTZDIR='get_timezones_directory()' -DUSG_COMPAT
-DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone -DPCTS=1 -DSTD_INSPIRED ;
UsePrivateHeaders [ FDirName libroot locale ] ;
UsePrivateHeaders [ FDirName libroot time ] ;
UsePrivateHeaders
[ FDirName libroot locale ]
[ FDirName libroot time ]
;
UsePrivateSystemHeaders ;
MergeObject posix_time.o :
@@ -1,63 +0,0 @@
/*
* Copyright 2010, Oliver Tappe, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "TimeBackend.h"
#include <dlfcn.h>
#include <pthread.h>
namespace BPrivate {
TimeBackend* gTimeBackend = NULL;
static TimeDataBridge sTimeDataBridge;
static pthread_once_t sBackendInitOnce = PTHREAD_ONCE_INIT;
static void
LoadBackend()
{
void* imageHandle = dlopen("libroot-addon-icu.so", RTLD_LAZY);
if (imageHandle == NULL)
return;
typedef TimeBackend* (*symbolType)();
symbolType createInstanceFunc
= (symbolType)dlsym(imageHandle, "CreateInstance");
if (createInstanceFunc == NULL)
return;
gTimeBackend = createInstanceFunc();
}
TimeBackend::TimeBackend()
{
}
TimeBackend::~TimeBackend()
{
}
status_t
TimeBackend::LoadBackend()
{
if (gTimeBackend == NULL) {
pthread_once(&sBackendInitOnce, &BPrivate::LoadBackend);
if (gTimeBackend != NULL)
gTimeBackend->Initialize(&sTimeDataBridge);
}
return gTimeBackend != NULL ? B_OK : B_ERROR;
}
} // namespace BPrivate
@@ -1,22 +0,0 @@
/*
* Copyright 2010, Oliver Tappe, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "TimeBackend.h"
namespace BPrivate {
TimeDataBridge::TimeDataBridge()
:
addrOfDaylight(&daylight),
addrOfTimezone(&timezone),
addrOfTZName(tzname)
{
}
} // namespace BPrivate
+129 -27
View File
@@ -4,51 +4,153 @@
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <localtime.h>
#include <time.h>
#include <FindDirectory.h>
#include <StorageDefs.h>
#include "LocaleBackend.h"
char* tzname[2] = { "???", "???" };
using BPrivate::gLocaleBackend;
using BPrivate::LocaleBackend;
static char sStandardTZName[64] = { "???" };
static char sDaylightSavingTZName[64] = { "???" };
char* tzname[2] = {
sStandardTZName,
sDaylightSavingTZName
};
long timezone = 0;
int daylight = 0;
namespace BPrivate {
static time_zone_info tzInfo;
extern "C" void
tzset(void)
{
char path[B_PATH_NAME_LENGTH];
if (find_directory(B_COMMON_SETTINGS_DIRECTORY, -1, false, path,
sizeof(path)) < 0)
return;
strlcat(path, "/", sizeof(path));
strlcat(path, skPosixTimeZoneInfoFile, sizeof(path));
FILE* tzInfoFile = fopen(path, "r");
if (tzInfoFile == NULL)
if (gLocaleBackend == NULL && LocaleBackend::LoadBackend() != B_OK)
return;
size_t numRead = fread(&tzInfo, sizeof(tzInfo), 1, tzInfoFile);
fclose(tzInfoFile);
char timeZoneID[64] = { "GMT" };
if (numRead != 1)
return;
const char* tz = getenv("TZ");
if (tz != NULL)
strlcpy(timeZoneID, tz, sizeof(timeZoneID));
else {
do {
char path[B_PATH_NAME_LENGTH];
if (find_directory(B_COMMON_SETTINGS_DIRECTORY, -1, false, path,
sizeof(path)) < 0)
break;
strlcat(path, "/libroot_timezone_info", sizeof(path));
tzname[0] = tzInfo.short_std_name;
tzname[1] = tzInfo.short_dst_name;
timezone = tzInfo.offset_from_gmt;
daylight = tzInfo.uses_daylight_saving;
FILE* tzInfoFile = fopen(path, "r");
if (tzInfoFile == NULL)
break;
fgets(timeZoneID, sizeof(timeZoneID), tzInfoFile);
fclose(tzInfoFile);
} while(0);
}
if (gLocaleBackend != NULL) {
gLocaleBackend->TZSet(timeZoneID);
}
}
} // namespace BPrivate
extern "C" struct tm*
localtime(const time_t* inTime)
{
static tm tm;
return localtime_r(inTime, &tm);
}
extern "C" struct tm*
localtime_r(const time_t* inTime, struct tm* tmOut)
{
if (inTime == NULL) {
errno = EINVAL;
return NULL;
}
tzset();
if (gLocaleBackend != NULL) {
status_t status = gLocaleBackend->Localtime(inTime, tmOut);
if (status != B_OK)
errno = EOVERFLOW;
return tmOut;
}
errno = ENOSYS;
return NULL;
}
extern "C" struct tm*
gmtime(const time_t* inTime)
{
static tm tm;
return gmtime_r(inTime, &tm);
}
extern "C" struct tm*
gmtime_r(const time_t* inTime, struct tm* tmOut)
{
if (inTime == NULL) {
errno = EINVAL;
return NULL;
}
tzset();
if (gLocaleBackend != NULL) {
status_t status = gLocaleBackend->Gmtime(inTime, tmOut);
if (status != B_OK)
errno = EOVERFLOW;
return tmOut;
}
errno = ENOSYS;
return NULL;
}
extern "C" time_t
mktime(struct tm* inTm)
{
if (inTm == NULL) {
errno = EINVAL;
return -1;
}
tzset();
if (gLocaleBackend != NULL) {
time_t timeOut;
status_t status = gLocaleBackend->Mktime(inTm, timeOut);
if (status != B_OK) {
errno = EOVERFLOW;
return -1;
}
return timeOut;
}
errno = ENOSYS;
return -1;
}
@@ -1321,6 +1321,7 @@ struct tm * const tmp;
return result;
}
#if 0
struct tm *
localtime(timep)
const time_t * const timep;
@@ -1340,6 +1341,7 @@ struct tm * tmp;
{
return localsub(timep, 0L, tmp);
}
#endif
/*
** gmtsub is to gmtime as localsub is to localtime.
@@ -1384,6 +1386,7 @@ struct tm * const tmp;
return result;
}
#if 0
struct tm *
gmtime(timep)
const time_t * const timep;
@@ -1403,6 +1406,8 @@ struct tm * tmp;
return gmtsub(timep, 0L, tmp);
}
#endif
#ifdef STD_INSPIRED
struct tm *
@@ -1932,6 +1937,7 @@ const long offset;
return WRONG;
}
#if 0
time_t
mktime(tmp)
struct tm * const tmp;
@@ -1939,6 +1945,7 @@ struct tm * const tmp;
tzset();
return time1(tmp, localsub, 0L);
}
#endif
#ifndef STD_INSPIRED
#pragma weak timelocal=mktime
+2
View File
@@ -24,6 +24,8 @@ SimpleTest signal_in_allocator_test : signal_in_allocator_test.cpp ;
SimpleTest signal_in_allocator_test2 : signal_in_allocator_test2.cpp ;
SimpleTest signal_test : signal_test.cpp ;
SimpleTest sigsetjmp_test : sigsetjmp_test.c ;
SimpleTest test_time : test_time.c ;
SimpleTest tst-mktime : tst-mktime.c ;
SimpleTest <test>truncate : truncate.cpp ;
SimpleTest init_rld_after_fork_test : init_rld_after_fork_test.cpp ;
@@ -1545,6 +1545,303 @@ test_collation()
}
// #pragma mark - time conversion ----------------------------------------------
void
test_localtime(const char* tz, time_t nowSecs, const tm& expected)
{
setenv("TZ", tz, 1);
printf("localtime for '%s'\n", tz);
tm now;
tm* result = localtime_r(&nowSecs, &now);
int problemCount = 0;
if (result == NULL) {
printf("\tPROBLEM: localtime(\"%ld\") = NULL\n", nowSecs);
problemCount++;
}
if (now.tm_year != expected.tm_year) {
printf("\tPROBLEM: localtime().tm_year = %d (expected %d)\n",
now.tm_year, expected.tm_year);
problemCount++;
}
if (now.tm_mon != expected.tm_mon) {
printf("\tPROBLEM: localtime().tm_mon = %d (expected %d)\n",
now.tm_mon, expected.tm_mon);
problemCount++;
}
if (now.tm_mday != expected.tm_mday) {
printf("\tPROBLEM: localtime().tm_mday = %d (expected %d)\n",
now.tm_mday, expected.tm_mday);
problemCount++;
}
if (now.tm_hour != expected.tm_hour) {
printf("\tPROBLEM: localtime().tm_hour = %d (expected %d)\n",
now.tm_hour, expected.tm_hour);
problemCount++;
}
if (now.tm_min != expected.tm_min) {
printf("\tPROBLEM: localtime().tm_min = %d (expected %d)\n",
now.tm_min, expected.tm_min);
problemCount++;
}
if (now.tm_sec != expected.tm_sec) {
printf("\tPROBLEM: localtime().tm_sec = %d (expected %d)\n",
now.tm_sec, expected.tm_sec);
problemCount++;
}
if (now.tm_wday != expected.tm_wday) {
printf("\tPROBLEM: localtime().tm_wday = %d (expected %d)\n",
now.tm_wday, expected.tm_wday);
problemCount++;
}
if (now.tm_yday != expected.tm_yday) {
printf("\tPROBLEM: localtime().tm_yday = %d (expected %d)\n",
now.tm_yday, expected.tm_yday);
problemCount++;
}
if (now.tm_isdst != expected.tm_isdst) {
printf("\tPROBLEM: localtime().tm_isdst = %d (expected %d)\n",
now.tm_isdst, expected.tm_isdst);
problemCount++;
}
if (now.tm_gmtoff != expected.tm_gmtoff) {
printf("\tPROBLEM: localtime().tm_gmtoff = %d (expected %d)\n",
now.tm_gmtoff, expected.tm_gmtoff);
problemCount++;
}
if (strcasecmp(now.tm_zone, expected.tm_zone) != 0) {
printf("\tPROBLEM: localtime().tm_zone = '%s' (expected '%s')\n",
now.tm_zone, expected.tm_zone);
problemCount++;
}
if (problemCount)
printf("\t%d problem(s) found!\n", problemCount);
else
printf("\tall fine\n");
}
void
test_gmtime(const char* tz, time_t nowSecs, const tm& expected)
{
setenv("TZ", tz, 1);
printf("gmtime for '%s'\n", tz);
tm now;
tm* result = gmtime_r(&nowSecs, &now);
int problemCount = 0;
if (result == NULL) {
printf("\tPROBLEM: localtime(\"%ld\") = NULL\n", nowSecs);
problemCount++;
}
if (now.tm_year != expected.tm_year) {
printf("\tPROBLEM: localtime().tm_year = %d (expected %d)\n",
now.tm_year, expected.tm_year);
problemCount++;
}
if (now.tm_mon != expected.tm_mon) {
printf("\tPROBLEM: localtime().tm_mon = %d (expected %d)\n",
now.tm_mon, expected.tm_mon);
problemCount++;
}
if (now.tm_mday != expected.tm_mday) {
printf("\tPROBLEM: localtime().tm_mday = %d (expected %d)\n",
now.tm_mday, expected.tm_mday);
problemCount++;
}
if (now.tm_hour != expected.tm_hour) {
printf("\tPROBLEM: localtime().tm_hour = %d (expected %d)\n",
now.tm_hour, expected.tm_hour);
problemCount++;
}
if (now.tm_min != expected.tm_min) {
printf("\tPROBLEM: localtime().tm_min = %d (expected %d)\n",
now.tm_min, expected.tm_min);
problemCount++;
}
if (now.tm_sec != expected.tm_sec) {
printf("\tPROBLEM: localtime().tm_sec = %d (expected %d)\n",
now.tm_sec, expected.tm_sec);
problemCount++;
}
if (now.tm_wday != expected.tm_wday) {
printf("\tPROBLEM: localtime().tm_wday = %d (expected %d)\n",
now.tm_wday, expected.tm_wday);
problemCount++;
}
if (now.tm_yday != expected.tm_yday) {
printf("\tPROBLEM: localtime().tm_yday = %d (expected %d)\n",
now.tm_yday, expected.tm_yday);
problemCount++;
}
if (now.tm_isdst != expected.tm_isdst) {
printf("\tPROBLEM: localtime().tm_isdst = %d (expected %d)\n",
now.tm_isdst, expected.tm_isdst);
problemCount++;
}
if (now.tm_gmtoff != expected.tm_gmtoff) {
printf("\tPROBLEM: localtime().tm_gmtoff = %d (expected %d)\n",
now.tm_gmtoff, expected.tm_gmtoff);
problemCount++;
}
if (strcasecmp(now.tm_zone, expected.tm_zone) != 0) {
printf("\tPROBLEM: localtime().tm_zone = '%s' (expected '%s')\n",
now.tm_zone, expected.tm_zone);
problemCount++;
}
if (problemCount)
printf("\t%d problem(s) found!\n", problemCount);
else
printf("\tall fine\n");
}
void
test_mktime(const char* tz, tm& tm, time_t expected, int expectedWeekDay,
int expectedYearDay)
{
setenv("TZ", tz, 1);
printf("mktime for '%s'\n", tz);
time_t result = mktime(&tm);
int problemCount = 0;
if (result != expected) {
printf("\tPROBLEM: mktime() = %ld (expected %ld)\n", result, expected);
problemCount++;
}
if (tm.tm_wday != expectedWeekDay) {
printf("\tPROBLEM: mktime().tm_wday = %d (expected %d)\n",
tm.tm_wday, expectedWeekDay);
problemCount++;
}
if (tm.tm_yday != expectedYearDay) {
printf("\tPROBLEM: mktime().tm_yday = %d (expected %d)\n",
tm.tm_yday, expectedYearDay);
problemCount++;
}
if (problemCount)
printf("\t%d problem(s) found!\n", problemCount);
else
printf("\tall fine\n");
}
void
test_timeconversions()
{
setlocale(LC_ALL, "");
{
time_t testTime = 1279391169; // Sat Jul 17 18:26:09 GMT 2010
tm gtm = {
9, 26, 18, 17, 6, 110, 6, 197, 0, 0, (char*)"GMT"
};
test_localtime("GMT", testTime, gtm);
test_gmtime("GMT", testTime, gtm);
gtm.tm_wday = -1;
gtm.tm_yday = -1;
test_mktime("GMT", gtm, testTime, 6, 197);
tm btm = {
9, 26, 20, 17, 6, 110, 6, 197, 1, 2 * 3600, (char*)"CEST"
};
test_localtime("Europe/Berlin", testTime, btm);
test_gmtime("Europe/Berlin", testTime, gtm);
btm.tm_wday = -1;
btm.tm_yday = -1;
test_mktime("Europe/Berlin", btm, testTime, 6, 197);
tm latm = {
9, 26, 11, 17, 6, 110, 6, 197, 1, -7 * 3600, (char*)"PDT"
};
test_localtime("America/Los_Angeles", testTime, latm);
test_gmtime("America/Los_Angeles", testTime, gtm);
latm.tm_wday = -1;
latm.tm_yday = -1;
test_mktime("America/Los_Angeles", latm, testTime, 6, 197);
tm ttm = {
9, 26, 3, 18, 6, 110, 0, 198, 0, 9 * 3600, (char*)"JST"
};
test_localtime("Asia/Tokyo", testTime, ttm);
test_gmtime("Asia/Tokyo", testTime, gtm);
ttm.tm_wday = -1;
ttm.tm_yday = -1;
test_mktime("Asia/Tokyo", ttm, testTime, 0, 198);
}
{
time_t testTime = 1268159169; // Tue Mar 9 18:26:09 GMT 2010
tm gtm = {
9, 26, 18, 9, 2, 110, 2, 67, 0, 0, (char*)"GMT"
};
test_localtime("GMT", testTime, gtm);
test_gmtime("GMT", testTime, gtm);
gtm.tm_wday = -1;
gtm.tm_yday = -1;
test_mktime("GMT", gtm, testTime, 2, 67);
tm btm = {
9, 26, 19, 9, 2, 110, 2, 67, 0, 3600, (char*)"CET"
};
test_localtime("Europe/Berlin", testTime, btm);
test_gmtime("Europe/Berlin", testTime, gtm);
btm.tm_wday = -1;
btm.tm_yday = -1;
test_mktime("Europe/Berlin", btm, testTime, 2, 67);
tm latm = {
9, 26, 10, 9, 2, 110, 2, 67, 0, -8 * 3600, (char*)"PST"
};
test_localtime("America/Los_Angeles", testTime, latm);
test_gmtime("America/Los_Angeles", testTime, gtm);
latm.tm_wday = -1;
latm.tm_yday = -1;
test_mktime("America/Los_Angeles", latm, testTime, 2, 67);
tm ttm = {
9, 26, 3, 10, 2, 110, 3, 68, 0, 9 * 3600, (char*)"JST"
};
test_localtime("Asia/Tokyo", testTime, ttm);
test_gmtime("Asia/Tokyo", testTime, gtm);
ttm.tm_wday = -1;
ttm.tm_yday = -1;
test_mktime("Asia/Tokyo", ttm, testTime, 3, 68);
}
{
time_t testTime = 0; // Thu Jan 1 00:00:00 GMT 1970
tm gtm = {
0, 0, 0, 1, 0, 70, 4, 0, 0, 0, (char*)"GMT"
};
test_localtime("GMT", testTime, gtm);
test_gmtime("GMT", testTime, gtm);
gtm.tm_wday = -1;
gtm.tm_yday = -1;
test_mktime("GMT", gtm, testTime, 4, 0);
tm btm = {
0, 0, 1, 1, 0, 70, 4, 0, 0, 1 * 3600, (char*)"CET"
};
test_localtime("Europe/Berlin", testTime, btm);
test_gmtime("Europe/Berlin", testTime, gtm);
btm.tm_wday = -1;
btm.tm_yday = -1;
test_mktime("Europe/Berlin", btm, testTime, 4, 0);
tm latm = {
0, 0, 16, 31, 11, 69, 3, 364, 0, -8 * 3600, (char*)"PST"
};
test_localtime("America/Los_Angeles", testTime, latm);
test_gmtime("America/Los_Angeles", testTime, gtm);
latm.tm_wday = -1;
latm.tm_yday = -1;
test_mktime("America/Los_Angeles", latm, testTime, 3, 364);
tm ttm = {
0, 0, 9, 1, 0, 70, 4, 0, 0, 9 * 3600, (char*)"JST"
};
test_localtime("Asia/Tokyo", testTime, ttm);
test_gmtime("Asia/Tokyo", testTime, gtm);
ttm.tm_wday = -1;
ttm.tm_yday = -1;
test_mktime("Asia/Tokyo", ttm, testTime, 4, 0);
}
}
// #pragma mark - main ---------------------------------------------------------
@@ -1563,6 +1860,7 @@ main(void)
test_wctrans();
test_langinfo();
test_collation();
test_timeconversions();
return 0;
}
+116
View File
@@ -0,0 +1,116 @@
/* Copyright (C) 1991, 1992, 1994, 1997 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int
main (int argc, char **argv)
{
time_t t;
register struct tm *tp;
struct tm tbuf;
int lose = 0;
--argc;
++argv;
do
{
char buf[BUFSIZ];
if (argc > 0)
{
static char buf[BUFSIZ];
sprintf(buf, "TZ=%s", *argv);
if (putenv(buf))
{
puts("putenv failed.");
lose = 1;
}
else
puts (buf);
}
tzset();
tbuf.tm_year = 72;
tbuf.tm_mon = 0;
tbuf.tm_mday = 31;
tbuf.tm_hour = 6;
tbuf.tm_min = 14;
tbuf.tm_sec = 50;
tbuf.tm_isdst = -1;
doit:;
t = mktime(&tbuf);
if (t == (time_t) -1)
{
puts("mktime() failed?");
lose = 1;
}
tp = localtime(&t);
if (tp == NULL)
{
puts("localtime() failed.");
lose = 1;
}
else if (strftime(buf, sizeof(buf), "%a %b %d %X %Z %Y", tp) == 0)
{
puts("strftime() failed.");
lose = 1;
}
else
puts(buf);
if (tbuf.tm_year == 101)
{
tbuf.tm_year = 97;
tbuf.tm_mon = 0;
goto doit;
}
++argv;
} while (--argc > 0);
{
#define SIZE 256
char buffer[SIZE];
time_t curtime;
struct tm *loctime;
curtime = time (NULL);
loctime = localtime (&curtime);
fputs (asctime (loctime), stdout);
strftime (buffer, SIZE, "Today is %A, %B %d.\n", loctime);
fputs (buffer, stdout);
strftime (buffer, SIZE, "The time is %I:%M %p.\n", loctime);
fputs (buffer, stdout);
loctime->tm_year = 72;
loctime->tm_mon = 8;
loctime->tm_mday = 12;
loctime->tm_hour = 20;
loctime->tm_min = 49;
loctime->tm_sec = 05;
curtime = mktime (loctime);
strftime (buffer, SIZE, "%D %T was %w the %jth.\n", loctime);
fputs (buffer, stdout);
}
return (lose ? EXIT_FAILURE : EXIT_SUCCESS);
}
@@ -0,0 +1,68 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
int
main (void)
{
struct tm time_str, *tm;
time_t t;
char daybuf[20];
int result;
time_str.tm_year = 2001 - 1900;
time_str.tm_mon = 7 - 1;
time_str.tm_mday = 4;
time_str.tm_hour = 0;
time_str.tm_min = 0;
time_str.tm_sec = 1;
time_str.tm_isdst = -1;
if (mktime (&time_str) == -1)
{
(void) puts ("-unknown-");
result = 1;
}
else
{
(void) strftime (daybuf, sizeof (daybuf), "%A", &time_str);
(void) puts (daybuf);
result = strcmp (daybuf, "Wednesday") != 0;
}
setenv ("TZ", "EST+5", 1);
#define EVENING69 1 * 60 * 60 + 2 * 60 + 29
t = EVENING69;
tm = localtime (&t);
if (tm == NULL)
{
(void) puts ("localtime returned NULL");
result = 1;
}
else
{
time_str = *tm;
t = mktime (&time_str);
if (t != EVENING69)
{
printf ("mktime returned %ld, expected %d\n",
(long) t, EVENING69);
result = 1;
}
else
(void) puts ("Dec 31 1969 EST test passed");
setenv ("TZ", "CET-1", 1);
t = mktime (&time_str);
if (t != (time_t) -1)
{
printf ("mktime returned %ld, expected -1\n", (long) t);
result = 1;
}
else
(void) puts ("Dec 31 1969 CET test passed");
}
return result;
}