summaryrefslogtreecommitdiffstats
path: root/src/corelib/time/qtimezonelocale.cpp
blob: cf3a84b317305c0f8b28742bae27e5fd43c10c33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include <private/qtimezonelocale_p.h>
#include <private/qtimezoneprivate_p.h>

#if !QT_CONFIG(icu)
#  include <private/qdatetime_p.h>
// Use data generated from CLDR:
#  include <private/qtimezonelocale_data_p.h>
#  include <private/qtimezoneprivate_data_p.h>
#endif

QT_BEGIN_NAMESPACE

#if QT_CONFIG(icu) // Get data from ICU:
namespace {

// Convert TimeType and NameType into ICU UCalendarDisplayNameType
constexpr UCalendarDisplayNameType ucalDisplayNameType(QTimeZone::TimeType timeType,
                                                       QTimeZone::NameType nameType)
{
    // TODO ICU C UCalendarDisplayNameType does not support full set of C++ TimeZone::EDisplayType
    // For now, treat Generic as Standard
    switch (nameType) {
    case QTimeZone::OffsetName:
        Q_UNREACHABLE(); // Callers of ucalTimeZoneDisplayName() should take care of OffsetName.
    case QTimeZone::ShortName:
        return timeType == QTimeZone::DaylightTime ? UCAL_SHORT_DST : UCAL_SHORT_STANDARD;
    case QTimeZone::DefaultName:
    case QTimeZone::LongName:
        return timeType == QTimeZone::DaylightTime ? UCAL_DST : UCAL_STANDARD;
    }
    Q_UNREACHABLE_RETURN(UCAL_STANDARD);
}

} // nameless namespace

namespace QtTimeZoneLocale {

// Qt wrapper around ucal_getTimeZoneDisplayName()
// Used directly by ICU backend; indirectly by TZ (see below).
QString ucalTimeZoneDisplayName(UCalendar *ucal,
                                QTimeZone::TimeType timeType,
                                QTimeZone::NameType nameType,
                                const QByteArray &localeCode)
{
    constexpr int32_t BigNameLength = 50;
    int32_t size = BigNameLength;
    QString result(size, Qt::Uninitialized);
    auto dst = [&result]() { return reinterpret_cast<UChar *>(result.data()); };
    UErrorCode status = U_ZERO_ERROR;
    const UCalendarDisplayNameType utype = ucalDisplayNameType(timeType, nameType);

    // size = ucal_getTimeZoneDisplayName(cal, type, locale, result, resultLength, status)
    size = ucal_getTimeZoneDisplayName(ucal, utype, localeCode.constData(),
                                       dst(), size, &status);

    // If overflow, then resize and retry
    if (size > BigNameLength || status == U_BUFFER_OVERFLOW_ERROR) {
        result.resize(size);
        status = U_ZERO_ERROR;
        size = ucal_getTimeZoneDisplayName(ucal, utype, localeCode.constData(),
                                           dst(), size, &status);
    }

    if (!U_SUCCESS(status))
        return QString();

    // Resize and return:
    result.resize(size);
    return result;
}

} // QtTimeZoneLocale

// Used by TZ backends when ICU is available:
QString QTimeZonePrivate::localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc,
                                     QTimeZone::TimeType timeType,
                                     QTimeZone::NameType nameType,
                                     const QLocale &locale) const
{
    Q_UNUSED(atMSecsSinceEpoch);
    // TODO: use CLDR data for the offset name.
    // No ICU API for offset formats, so fall back to our ISO one, even if
    // locale isn't C:
    if (nameType == QTimeZone::OffsetName)
        return isoOffsetFormat(offsetFromUtc);

    const QString id = QString::fromUtf8(m_id);
    const QByteArray loc = locale.name().toUtf8();
    UErrorCode status = U_ZERO_ERROR;
    UCalendar *ucal = ucal_open(reinterpret_cast<const UChar *>(id.data()), id.size(),
                                loc.constData(), UCAL_DEFAULT, &status);
    if (ucal && U_SUCCESS(status)) {
        auto tidier = qScopeGuard([ucal]() { ucal_close(ucal); });
        return QtTimeZoneLocale::ucalTimeZoneDisplayName(ucal, timeType, nameType, loc);
    }
    return QString();
}
#else // No ICU, use QTZ[LP}_data_p.h data for feature timezone_locale.
namespace {
using namespace QtTimeZoneLocale; // QTZL_data_p.h
using namespace QtTimeZoneCldr; // QTZP_data_p.h
// Accessors for the QTZL_data_p.h

// Accessors for the QTZP_data_p.h

} // nameless namespace

QString QTimeZonePrivate::localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc,
                                     QTimeZone::TimeType timeType,
                                     QTimeZone::NameType nameType,
                                     const QLocale &locale) const
{
    Q_ASSERT(nameType != QTimeZone::OffsetName || locale.language() != QLocale::C);
    // Get data from QTZ[LP]_data_p.h

    Q_UNUSED(atMSecsSinceEpoch);
    Q_UNUSED(offsetFromUtc);
    Q_UNUSED(timeType);
    return QString();
}
#endif // ICU

QT_END_NAMESPACE