10#include <unicode/ucal.h>
20
21
22
23
28#include <BasicServicesKit/time_service.h>
32static QByteArray ucalDefaultTimeZoneId()
35 char tzBuffer[32] = { 0 };
36 TimeService_ErrCode err = OH_TimeService_GetTimeZone(tzBuffer,
sizeof(tzBuffer));
38 if (err == TIMESERVICE_ERR_OK)
39 return QByteArray(tzBuffer);
42 QString result(size, Qt::Uninitialized);
43 UErrorCode status = U_ZERO_ERROR;
46 size = ucal_getDefaultTimeZone(
reinterpret_cast<UChar *>(result.data()), size, &status);
49 if (status == U_BUFFER_OVERFLOW_ERROR) {
51 status = U_ZERO_ERROR;
52 size = ucal_getDefaultTimeZone(
reinterpret_cast<UChar *>(result.data()), size, &status);
56 if (U_SUCCESS(status)) {
58 return std::move(result).toUtf8();
66 int *utcOffset,
int *dstOffset)
72 UErrorCode status = U_ZERO_ERROR;
73 UCalendar *ucal = ucal_clone(m_ucal, &status);
74 if (!U_SUCCESS(status))
78 status = U_ZERO_ERROR;
79 ucal_setMillis(ucal, atMSecsSinceEpoch, &status);
82 if (U_SUCCESS(status)) {
83 status = U_ZERO_ERROR;
85 utc = ucal_get(ucal, UCAL_ZONE_OFFSET, &status) / 1000;
89 if (U_SUCCESS(status)) {
90 status = U_ZERO_ERROR;
92 dst = ucal_get(ucal, UCAL_DST_OFFSET, &status) / 1000;
96 if (U_SUCCESS(status)) {
104#if U_ICU_VERSION_MAJOR_NUM
>= 50
106static QTimeZonePrivate::Data ucalTimeZoneTransition(UCalendar *m_ucal,
107 UTimeZoneTransitionType type,
108 qint64 atMSecsSinceEpoch)
110 QTimeZonePrivate::Data tran;
113 UErrorCode status = U_ZERO_ERROR;
114 UCalendar *ucal = ucal_clone(m_ucal, &status);
115 if (!U_SUCCESS(status))
119 status = U_ZERO_ERROR;
120 const UDate when = UDate(atMSecsSinceEpoch);
121 ucal_setMillis(ucal, when, &status);
125 status = U_ZERO_ERROR;
126 bool ok = ucal_getTimeZoneTransitionDate(ucal, type, &tranMSecs, &status);
129 if (U_SUCCESS(status) && ok && type == UCAL_TZ_TRANSITION_NEXT) {
133 ok = tranMSecs > when;
137 if (U_SUCCESS(status) && ok) {
138 status = U_ZERO_ERROR;
139 ucal_setMillis(ucal, tranMSecs, &status);
143 if (U_SUCCESS(status) && ok) {
144 status = U_ZERO_ERROR;
145 utc = ucal_get(ucal, UCAL_ZONE_OFFSET, &status) / 1000;
149 if (U_SUCCESS(status) && ok) {
150 status = U_ZERO_ERROR;
151 dst = ucal_get(ucal, UCAL_DST_OFFSET, &status) / 1000;
155 if (!U_SUCCESS(status) || !ok)
157 tran.atMSecsSinceEpoch = qint64(tranMSecs);
158 tran.offsetFromUtc = utc + dst;
159 tran.standardTimeOffset = utc;
160 tran.daylightTimeOffset = dst;
162 QTimeZone::TimeType timeType = dst == 0 ? QTimeZone::StandardTime : QTimeZone::DaylightTime;
164 tran.abbreviation = ucalTimeZoneDisplayName(m_ucal, timeType,
165 QTimeZone::ShortName, QLocale().name().toUtf8());
173 QList<QByteArray> list;
175 UErrorCode status = U_ZERO_ERROR;
177 QByteArray result = uenum_next(uenum, &size, &status);
178 while (U_SUCCESS(status) && !result.isEmpty()) {
181 const QByteArrayView zone = QTimeZonePrivate::aliasToIana(result);
182 if (!zone.isEmpty()) {
183 list << zone.toByteArray();
184 Q_ASSERT(QTimeZonePrivate::aliasToIana(zone).isEmpty());
186 status = U_ZERO_ERROR;
187 result = uenum_next(uenum, &size, &status);
190 std::sort(list.begin(), list.end());
191 list.erase(
std::unique(list.begin(), list.end()), list.end());
198 UErrorCode status = U_ZERO_ERROR;
199 const QString utf16 = QString::fromLatin1(id);
200 const int32_t dstMSecs = ucal_getDSTSavings(
201 reinterpret_cast<
const UChar *>(utf16.data()), &status);
202 return U_SUCCESS(status) ? dstMSecs / 1000 : 0;
206QIcuTimeZonePrivate::QIcuTimeZonePrivate()
210 init(ucalDefaultTimeZoneId());
214QIcuTimeZonePrivate::QIcuTimeZonePrivate(
const QByteArray &ianaId)
218 if (isTimeZoneIdAvailable(ianaId))
222QIcuTimeZonePrivate::QIcuTimeZonePrivate(
const QIcuTimeZonePrivate &other)
223 : QTimeZonePrivate(other), m_ucal(
nullptr)
226 UErrorCode status = U_ZERO_ERROR;
227 m_ucal = ucal_clone(other.m_ucal, &status);
228 if (!U_SUCCESS(status)) {
234QIcuTimeZonePrivate::~QIcuTimeZonePrivate()
239QIcuTimeZonePrivate *QIcuTimeZonePrivate::clone()
const
241 return new QIcuTimeZonePrivate(*
this);
244void QIcuTimeZonePrivate::init(
const QByteArray &ianaId)
248 const QString id = QString::fromUtf8(m_id);
249 UErrorCode status = U_ZERO_ERROR;
251 m_ucal = ucal_open(
reinterpret_cast<
const UChar *>(id.data()), id.size(),
252 QLocale().name().toUtf8(), UCAL_GREGORIAN, &status);
254 if (!U_SUCCESS(status)) {
260QString QIcuTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
261 QTimeZone::NameType nameType,
262 const QLocale &locale)
const
265 if (nameType == QTimeZone::OffsetName) {
266 int offset = standardTimeOffset(QDateTime::currentMSecsSinceEpoch());
269 if (timeType == QTimeZone::DaylightTime)
270 offset += ucalDaylightOffset(m_id);
276 return isoOffsetFormat(offset);
280 using namespace QtTimeZoneLocale;
281 return ucalTimeZoneDisplayName(m_ucal, timeType, nameType, locale.name().toUtf8());
284int QIcuTimeZonePrivate::offsetFromUtc(qint64 atMSecsSinceEpoch)
const
288 ucalOffsetsAtTime(m_ucal, atMSecsSinceEpoch, &stdOffset, & dstOffset);
289 return stdOffset + dstOffset;
292int QIcuTimeZonePrivate::standardTimeOffset(qint64 atMSecsSinceEpoch)
const
296 ucalOffsetsAtTime(m_ucal, atMSecsSinceEpoch, &stdOffset, & dstOffset);
300int QIcuTimeZonePrivate::daylightTimeOffset(qint64 atMSecsSinceEpoch)
const
304 ucalOffsetsAtTime(m_ucal, atMSecsSinceEpoch, &stdOffset, & dstOffset);
308bool QIcuTimeZonePrivate::hasDaylightTime()
const
310 if (ucalDaylightOffset(m_id) != 0)
312#if U_ICU_VERSION_MAJOR_NUM
>= 50
313 for (qint64 when = minMSecs(); when != invalidMSecs(); ) {
314 auto data = nextTransition(when);
315 if (data.daylightTimeOffset && data.daylightTimeOffset != invalidSeconds())
317 when = data.atMSecsSinceEpoch;
323bool QIcuTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch)
const
326 UErrorCode status = U_ZERO_ERROR;
327 UCalendar *ucal = ucal_clone(m_ucal, &status);
328 if (!U_SUCCESS(status))
332 status = U_ZERO_ERROR;
333 ucal_setMillis(ucal, atMSecsSinceEpoch, &status);
336 if (U_SUCCESS(status)) {
337 status = U_ZERO_ERROR;
338 result = ucal_inDaylightTime(ucal, &status);
345QTimeZonePrivate::Data QIcuTimeZonePrivate::data(qint64 forMSecsSinceEpoch)
const
349#if U_ICU_VERSION_MAJOR_NUM
>= 50
350 data = ucalTimeZoneTransition(m_ucal, UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE,
352 if (data.atMSecsSinceEpoch == invalidMSecs())
355 ucalOffsetsAtTime(m_ucal, forMSecsSinceEpoch, &data.standardTimeOffset,
356 &data.daylightTimeOffset);
357 data.offsetFromUtc = data.standardTimeOffset + data.daylightTimeOffset;
359 using namespace QtTimeZoneLocale;
360 QTimeZone::TimeType timeType
361 = data.daylightTimeOffset ? QTimeZone::DaylightTime : QTimeZone::StandardTime;
362 data.abbreviation = ucalTimeZoneDisplayName(m_ucal, timeType, QTimeZone::ShortName,
363 QLocale().name().toUtf8());
365 data.atMSecsSinceEpoch = forMSecsSinceEpoch;
369bool QIcuTimeZonePrivate::hasTransitions()
const
372#if U_ICU_VERSION_MAJOR_NUM
>= 50
379QTimeZonePrivate::Data QIcuTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch)
const
382#if U_ICU_VERSION_MAJOR_NUM
>= 50
383 return ucalTimeZoneTransition(m_ucal, UCAL_TZ_TRANSITION_NEXT, afterMSecsSinceEpoch);
385 Q_UNUSED(afterMSecsSinceEpoch);
390QTimeZonePrivate::Data QIcuTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch)
const
393#if U_ICU_VERSION_MAJOR_NUM
>= 50
394 return ucalTimeZoneTransition(m_ucal, UCAL_TZ_TRANSITION_PREVIOUS, beforeMSecsSinceEpoch);
396 Q_UNUSED(beforeMSecsSinceEpoch);
401QByteArray QIcuTimeZonePrivate::systemTimeZoneId()
const
405 return ucalDefaultTimeZoneId();
408bool QIcuTimeZonePrivate::isTimeZoneIdAvailable(QByteArrayView ianaId)
const
410 return QtTimeZoneLocale::ucalKnownTimeZoneId(QString::fromUtf8(ianaId));
413QList<QByteArray> QIcuTimeZonePrivate::availableTimeZoneIds()
const
415 UErrorCode status = U_ZERO_ERROR;
416 UEnumeration *uenum = ucal_openTimeZones(&status);
418 QList<QByteArray> result;
419 if (U_SUCCESS(status))
420 result = uenumToIdList(uenum);
425QList<QByteArray> QIcuTimeZonePrivate::availableTimeZoneIds(QLocale::Territory territory)
const
427 const QLatin1StringView regionCode = QLocalePrivate::territoryToCode(territory);
428 const QByteArray regionCodeUtf8 = QString(regionCode).toUtf8();
429 UErrorCode status = U_ZERO_ERROR;
430 UEnumeration *uenum = ucal_openCountryTimeZones(regionCodeUtf8.data(), &status);
431 QList<QByteArray> result;
432 if (U_SUCCESS(status))
433 result = uenumToIdList(uenum);
440QList<QByteArray> QIcuTimeZonePrivate::availableTimeZoneIds(
int offsetFromUtc)
const
443#if U_ICU_VERSION_MAJOR_NUM
>= 49
|| (U_ICU_VERSION_MAJOR_NUM
== 4
&& U_ICU_VERSION_MINOR_NUM
== 8
)
444 UErrorCode status = U_ZERO_ERROR;
445 UEnumeration *uenum = ucal_openTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY,
nullptr,
446 &offsetFromUtc, &status);
447 QList<QByteArray> result;
448 if (U_SUCCESS(status))
449 result = uenumToIdList(uenum);
455 return QTimeZonePrivate::availableTimeZoneIds(offsetFromUtc);
static bool ucalOffsetsAtTime(UCalendar *m_ucal, qint64 atMSecsSinceEpoch, int *utcOffset, int *dstOffset)
static int ucalDaylightOffset(const QByteArray &id)
static QList< QByteArray > uenumToIdList(UEnumeration *uenum)