diff --git a/headers/private/libroot/locale/ICULocaleBackend.h b/headers/private/libroot/locale/ICULocaleBackend.h index bd19899281..f740369028 100644 --- a/headers/private/libroot/locale/ICULocaleBackend.h +++ b/headers/private/libroot/locale/ICULocaleBackend.h @@ -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; diff --git a/headers/private/libroot/locale/ICUTimeConversion.h b/headers/private/libroot/locale/ICUTimeConversion.h new file mode 100644 index 0000000000..a5065c5b8b --- /dev/null +++ b/headers/private/libroot/locale/ICUTimeConversion.h @@ -0,0 +1,49 @@ +/* + * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _ICU_TIME_CONVERSION_H +#define _ICU_TIME_CONVERSION_H + + +#include + +#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 diff --git a/headers/private/libroot/locale/ICUTimeData.h b/headers/private/libroot/locale/ICUTimeData.h index b8647956fe..c858f25112 100644 --- a/headers/private/libroot/locale/ICUTimeData.h +++ b/headers/private/libroot/locale/ICUTimeData.h @@ -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; }; diff --git a/headers/private/libroot/locale/LocaleBackend.h b/headers/private/libroot/locale/LocaleBackend.h index b12de25e9d..1393a6b959 100644 --- a/headers/private/libroot/locale/LocaleBackend.h +++ b/headers/private/libroot/locale/LocaleBackend.h @@ -8,6 +8,7 @@ #include +#include #include @@ -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(); diff --git a/headers/private/libroot/time/ICUTimeBackend.h b/headers/private/libroot/time/ICUTimeBackend.h deleted file mode 100644 index 92190dd6a9..0000000000 --- a/headers/private/libroot/time/ICUTimeBackend.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de. - * Distributed under the terms of the MIT License. - */ -#ifndef _ICU_TIME_BACKEND_H -#define _ICU_TIME_BACKEND_H - - -#include - - -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 diff --git a/headers/private/libroot/time/TimeBackend.h b/headers/private/libroot/time/TimeBackend.h deleted file mode 100644 index e4256a396c..0000000000 --- a/headers/private/libroot/time/TimeBackend.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de. - * Distributed under the terms of the MIT License. - */ -#ifndef _TIME_BACKEND_H -#define _TIME_BACKEND_H - - -#include - - -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 diff --git a/headers/private/libroot/time/localtime.h b/headers/private/libroot/time/localtime.h deleted file mode 100644 index d512f84224..0000000000 --- a/headers/private/libroot/time/localtime.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de. - * Distributed under the terms of the MIT License. - */ -#ifndef _LOCALTIME_H -#define _LOCALTIME_H - - -#include - - -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 diff --git a/src/system/libroot/add-ons/icu/locale/ICUCategoryData.cpp b/src/system/libroot/add-ons/icu/ICUCategoryData.cpp similarity index 100% rename from src/system/libroot/add-ons/icu/locale/ICUCategoryData.cpp rename to src/system/libroot/add-ons/icu/ICUCategoryData.cpp diff --git a/src/system/libroot/add-ons/icu/locale/ICUCollateData.cpp b/src/system/libroot/add-ons/icu/ICUCollateData.cpp similarity index 100% rename from src/system/libroot/add-ons/icu/locale/ICUCollateData.cpp rename to src/system/libroot/add-ons/icu/ICUCollateData.cpp diff --git a/src/system/libroot/add-ons/icu/locale/ICUCtypeData.cpp b/src/system/libroot/add-ons/icu/ICUCtypeData.cpp similarity index 100% rename from src/system/libroot/add-ons/icu/locale/ICUCtypeData.cpp rename to src/system/libroot/add-ons/icu/ICUCtypeData.cpp diff --git a/src/system/libroot/add-ons/icu/locale/ICULocaleBackend.cpp b/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp similarity index 90% rename from src/system/libroot/add-ons/icu/locale/ICULocaleBackend.cpp rename to src/system/libroot/add-ons/icu/ICULocaleBackend.cpp index 844a5aa5cb..c9459480e9 100644 --- a/src/system/libroot/add-ons/icu/locale/ICULocaleBackend.cpp +++ b/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp @@ -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) { diff --git a/src/system/libroot/add-ons/icu/locale/ICULocaleconvData.cpp b/src/system/libroot/add-ons/icu/ICULocaleconvData.cpp similarity index 100% rename from src/system/libroot/add-ons/icu/locale/ICULocaleconvData.cpp rename to src/system/libroot/add-ons/icu/ICULocaleconvData.cpp diff --git a/src/system/libroot/add-ons/icu/locale/ICUMessagesData.cpp b/src/system/libroot/add-ons/icu/ICUMessagesData.cpp similarity index 100% rename from src/system/libroot/add-ons/icu/locale/ICUMessagesData.cpp rename to src/system/libroot/add-ons/icu/ICUMessagesData.cpp diff --git a/src/system/libroot/add-ons/icu/locale/ICUMonetaryData.cpp b/src/system/libroot/add-ons/icu/ICUMonetaryData.cpp similarity index 100% rename from src/system/libroot/add-ons/icu/locale/ICUMonetaryData.cpp rename to src/system/libroot/add-ons/icu/ICUMonetaryData.cpp diff --git a/src/system/libroot/add-ons/icu/locale/ICUNumericData.cpp b/src/system/libroot/add-ons/icu/ICUNumericData.cpp similarity index 100% rename from src/system/libroot/add-ons/icu/locale/ICUNumericData.cpp rename to src/system/libroot/add-ons/icu/ICUNumericData.cpp diff --git a/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp b/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp new file mode 100644 index 0000000000..0b84c1e872 --- /dev/null +++ b/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp @@ -0,0 +1,188 @@ +/* + * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ICUTimeConversion.h" + +#include +#include + +#include + +#include + + +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 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 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 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 diff --git a/src/system/libroot/add-ons/icu/locale/ICUTimeData.cpp b/src/system/libroot/add-ons/icu/ICUTimeData.cpp similarity index 89% rename from src/system/libroot/add-ons/icu/locale/ICUTimeData.cpp rename to src/system/libroot/add-ons/icu/ICUTimeData.cpp index 77185996b8..7fddb086d9 100644 --- a/src/system/libroot/add-ons/icu/locale/ICUTimeData.cpp +++ b/src/system/libroot/add-ons/icu/ICUTimeData.cpp @@ -10,8 +10,11 @@ #include #include +#include #include +#include + 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 diff --git a/src/system/libroot/add-ons/icu/Jamfile b/src/system/libroot/add-ons/icu/Jamfile index b43ff2d977..2ab0ec9d76 100644 --- a/src/system/libroot/add-ons/icu/Jamfile +++ b/src/system/libroot/add-ons/icu/Jamfile @@ -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 ; diff --git a/src/system/libroot/add-ons/icu/locale/Jamfile b/src/system/libroot/add-ons/icu/locale/Jamfile deleted file mode 100644 index 470e093440..0000000000 --- a/src/system/libroot/add-ons/icu/locale/Jamfile +++ /dev/null @@ -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) ; diff --git a/src/system/libroot/add-ons/icu/time/ICUTimeBackend.cpp b/src/system/libroot/add-ons/icu/time/ICUTimeBackend.cpp deleted file mode 100644 index b3961eb71c..0000000000 --- a/src/system/libroot/add-ons/icu/time/ICUTimeBackend.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de. - * Distributed under the terms of the MIT License. - */ - - -#include "ICUTimeBackend.h" - -#include - -#include - -#include - -#include - - -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 diff --git a/src/system/libroot/posix/locale/Jamfile b/src/system/libroot/posix/locale/Jamfile index f019e58f69..b35c6eea14 100644 --- a/src/system/libroot/posix/locale/Jamfile +++ b/src/system/libroot/posix/locale/Jamfile @@ -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 diff --git a/src/system/libroot/posix/locale/LocaleDataBridge.cpp b/src/system/libroot/posix/locale/LocaleDataBridge.cpp index 1b848f7c62..57b3a3ed8a 100644 --- a/src/system/libroot/posix/locale/LocaleDataBridge.cpp +++ b/src/system/libroot/posix/locale/LocaleDataBridge.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -85,6 +86,15 @@ LocaleTimeDataBridge::LocaleTimeDataBridge() } +TimeConversionDataBridge::TimeConversionDataBridge() + : + addrOfDaylight(&daylight), + addrOfTimezone(&timezone), + addrOfTZName(tzname) +{ +} + + LocaleDataBridge::LocaleDataBridge() : posixLanginfo(gPosixLanginfo) diff --git a/src/system/libroot/posix/time/Jamfile b/src/system/libroot/posix/time/Jamfile index 5384ec2b35..a27f922174 100644 --- a/src/system/libroot/posix/time/Jamfile +++ b/src/system/libroot/posix/time/Jamfile @@ -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 : diff --git a/src/system/libroot/posix/time/TimeBackend.cpp b/src/system/libroot/posix/time/TimeBackend.cpp deleted file mode 100644 index 5736665fac..0000000000 --- a/src/system/libroot/posix/time/TimeBackend.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de. - * Distributed under the terms of the MIT License. - */ - - -#include "TimeBackend.h" - -#include -#include - - -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 diff --git a/src/system/libroot/posix/time/TimeDataBridge.cpp b/src/system/libroot/posix/time/TimeDataBridge.cpp deleted file mode 100644 index 938ade1c4e..0000000000 --- a/src/system/libroot/posix/time/TimeDataBridge.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de. - * Distributed under the terms of the MIT License. - */ - - -#include "TimeBackend.h" - - -namespace BPrivate { - - -TimeDataBridge::TimeDataBridge() - : - addrOfDaylight(&daylight), - addrOfTimezone(&timezone), - addrOfTZName(tzname) -{ -} - - -} // namespace BPrivate diff --git a/src/system/libroot/posix/time/localtime.cpp b/src/system/libroot/posix/time/localtime.cpp index 5392f03433..26db09f6c5 100644 --- a/src/system/libroot/posix/time/localtime.cpp +++ b/src/system/libroot/posix/time/localtime.cpp @@ -4,51 +4,153 @@ */ +#include #include +#include #include - -#include +#include #include #include +#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; +} diff --git a/src/system/libroot/posix/time/localtime_fading_out.c b/src/system/libroot/posix/time/localtime_fading_out.c index 3ad9106f78..2560776521 100644 --- a/src/system/libroot/posix/time/localtime_fading_out.c +++ b/src/system/libroot/posix/time/localtime_fading_out.c @@ -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 diff --git a/src/tests/system/libroot/posix/Jamfile b/src/tests/system/libroot/posix/Jamfile index 79cbd75c7c..4b83b2f42e 100644 --- a/src/tests/system/libroot/posix/Jamfile +++ b/src/tests/system/libroot/posix/Jamfile @@ -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 truncate : truncate.cpp ; SimpleTest init_rld_after_fork_test : init_rld_after_fork_test.cpp ; diff --git a/src/tests/system/libroot/posix/locale_test.cpp b/src/tests/system/libroot/posix/locale_test.cpp index 28928b19f6..3e2586358c 100644 --- a/src/tests/system/libroot/posix/locale_test.cpp +++ b/src/tests/system/libroot/posix/locale_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; } diff --git a/src/tests/system/libroot/posix/test_time.c b/src/tests/system/libroot/posix/test_time.c new file mode 100644 index 0000000000..20216ed9d2 --- /dev/null +++ b/src/tests/system/libroot/posix/test_time.c @@ -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 +#include +#include + + +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); +} diff --git a/src/tests/system/libroot/posix/tst-mktime.c b/src/tests/system/libroot/posix/tst-mktime.c new file mode 100644 index 0000000000..8bc7631461 --- /dev/null +++ b/src/tests/system/libroot/posix/tst-mktime.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +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; +}