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:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
+39
-1
@@ -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
|
||||
+32
-16
@@ -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
|
||||
@@ -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
|
||||
@@ -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,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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user