8#include "private/qcore_mac_p.h"
11#include <Foundation/NSTimeZone.h>
20
21
22
23
24
27QMacTimeZonePrivate::QMacTimeZonePrivate()
30 [NSTimeZone resetSystemTimeZone];
31 m_nstz = [NSTimeZone.systemTimeZone retain];
33 m_id = QString::fromNSString(m_nstz.name).toUtf8();
37QMacTimeZonePrivate::QMacTimeZonePrivate(
const QByteArray &ianaId)
43QMacTimeZonePrivate::QMacTimeZonePrivate(
const QMacTimeZonePrivate &other)
44 : QTimeZonePrivate(other), m_nstz([other.m_nstz copy])
48QMacTimeZonePrivate::~QMacTimeZonePrivate()
53QMacTimeZonePrivate *QMacTimeZonePrivate::clone()
const
55 return new QMacTimeZonePrivate(*
this);
58void QMacTimeZonePrivate::init(
const QByteArray &ianaId)
60 m_nstz = [[NSTimeZone timeZoneWithName:QString::fromUtf8(ianaId).toNSString()] retain];
68 m_nstz = [NSTimeZone.systemTimeZone retain];
70 if (QString::fromNSString(m_nstz.name).toUtf8() == ianaId)
75QString QMacTimeZonePrivate::comment()
const
77 return QString::fromNSString(m_nstz.description);
80QString QMacTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
81 QTimeZone::NameType nameType,
82 const QLocale &locale)
const
85 if (nameType == QTimeZone::OffsetName) {
86 const Data nowData = data(QDateTime::currentMSecsSinceEpoch());
88 if (timeType == QTimeZone::DaylightTime && hasDaylightTime())
89 return isoOffsetFormat(nowData.standardTimeOffset + 3600);
91 return isoOffsetFormat(nowData.standardTimeOffset);
94 NSTimeZoneNameStyle style = NSTimeZoneNameStyleStandard;
97 case QTimeZone::ShortName :
98 if (timeType == QTimeZone::DaylightTime)
99 style = NSTimeZoneNameStyleShortDaylightSaving;
100 else if (timeType == QTimeZone::GenericTime)
101 style = NSTimeZoneNameStyleShortGeneric;
103 style = NSTimeZoneNameStyleShortStandard;
105 case QTimeZone::DefaultName :
106 case QTimeZone::LongName :
107 if (timeType == QTimeZone::DaylightTime)
108 style = NSTimeZoneNameStyleDaylightSaving;
109 else if (timeType == QTimeZone::GenericTime)
110 style = NSTimeZoneNameStyleGeneric;
112 style = NSTimeZoneNameStyleStandard;
114 case QTimeZone::OffsetName :
119 NSString *macLocaleCode = locale.name().toNSString();
120 NSLocale *macLocale = [[NSLocale alloc] initWithLocaleIdentifier:macLocaleCode];
121 const QString result = QString::fromNSString([m_nstz localizedName:style locale:macLocale]);
126QString QMacTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch)
const
128 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
129 return QString::fromNSString([m_nstz abbreviationForDate:[NSDate dateWithTimeIntervalSince1970:seconds]]);
132int QMacTimeZonePrivate::offsetFromUtc(qint64 atMSecsSinceEpoch)
const
134 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
135 return [m_nstz secondsFromGMTForDate:[NSDate dateWithTimeIntervalSince1970:seconds]];
138int QMacTimeZonePrivate::standardTimeOffset(qint64 atMSecsSinceEpoch)
const
140 return offsetFromUtc(atMSecsSinceEpoch) - daylightTimeOffset(atMSecsSinceEpoch);
143int QMacTimeZonePrivate::daylightTimeOffset(qint64 atMSecsSinceEpoch)
const
145 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
146 return [m_nstz daylightSavingTimeOffsetForDate:[NSDate dateWithTimeIntervalSince1970:seconds]];
149bool QMacTimeZonePrivate::hasDaylightTime()
const
152 return hasTransitions();
155bool QMacTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch)
const
157 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
158 return [m_nstz isDaylightSavingTimeForDate:[NSDate dateWithTimeIntervalSince1970:seconds]];
161QTimeZonePrivate::Data QMacTimeZonePrivate::data(qint64 forMSecsSinceEpoch)
const
163 const NSTimeInterval seconds = forMSecsSinceEpoch / 1000.0;
164 NSDate *date = [NSDate dateWithTimeIntervalSince1970:seconds];
166 data.atMSecsSinceEpoch = forMSecsSinceEpoch;
167 data.offsetFromUtc = [m_nstz secondsFromGMTForDate:date];
168 data.daylightTimeOffset = [m_nstz daylightSavingTimeOffsetForDate:date];
169 data.standardTimeOffset = data.offsetFromUtc - data.daylightTimeOffset;
170 data.abbreviation = QString::fromNSString([m_nstz abbreviationForDate:date]);
174bool QMacTimeZonePrivate::hasTransitions()
const
178 NSDate *epoch = [NSDate dateWithTimeIntervalSince1970:0];
179 const NSDate *date = [m_nstz nextDaylightSavingTimeTransitionAfterDate:epoch];
180 const bool result = (date.timeIntervalSince1970 > epoch.timeIntervalSince1970);
184QTimeZonePrivate::Data QMacTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch)
const
187 const NSTimeInterval seconds = afterMSecsSinceEpoch / 1000.0;
188 NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:seconds];
189 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
190 const NSTimeInterval nextSecs = nextDate.timeIntervalSince1970;
191 if (nextDate == nil || nextSecs <= seconds) {
195 tran.atMSecsSinceEpoch = nextSecs * 1000;
196 tran.offsetFromUtc = [m_nstz secondsFromGMTForDate:nextDate];
197 tran.daylightTimeOffset = [m_nstz daylightSavingTimeOffsetForDate:nextDate];
198 tran.standardTimeOffset = tran.offsetFromUtc - tran.daylightTimeOffset;
199 tran.abbreviation = QString::fromNSString([m_nstz abbreviationForDate:nextDate]);
203QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch)
const
206 constexpr NSTimeInterval lowerBound = std::numeric_limits<NSTimeInterval>::lowest();
207 const qint64 endSecs = beforeMSecsSinceEpoch / 1000;
208 const int year = 366 * 24 * 3600;
209 NSTimeInterval prevSecs = endSecs;
210 NSTimeInterval nextSecs = prevSecs - year;
211 NSTimeInterval tranSecs = lowerBound;
213 NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:nextSecs];
214 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
216 && (tranSecs = nextDate.timeIntervalSince1970) < endSecs) {
221 nextDate = [NSDate dateWithTimeIntervalSince1970:lowerBound];
222 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
223 if (nextDate != nil) {
224 NSTimeInterval lateSecs = nextSecs;
225 nextSecs = nextDate.timeIntervalSince1970;
226 Q_ASSERT(nextSecs <= endSecs - year || nextSecs == tranSecs);
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
246 while (nextSecs + year < lateSecs) {
248 NSTimeInterval middle = nextSecs / 2 + lateSecs / 2;
249 NSDate *split = [NSDate dateWithTimeIntervalSince1970:middle];
250 split = [m_nstz nextDaylightSavingTimeTransitionAfterDate:split];
251 if (split != nil && (tranSecs = split.timeIntervalSince1970) < endSecs) {
258 Q_ASSERT(nextDate != nil);
265 while (nextDate != nil && nextSecs < endSecs) {
267 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
268 nextSecs = nextDate.timeIntervalSince1970;
269 if (nextSecs <= prevSecs)
272 if (prevSecs < endSecs)
273 return data(qint64(prevSecs * 1e3));
279QByteArray QMacTimeZonePrivate::systemTimeZoneId()
const
282 [NSTimeZone resetSystemTimeZone];
283 Q_ASSERT(NSTimeZone.systemTimeZone);
284 return QString::fromNSString(NSTimeZone.systemTimeZone.name).toUtf8();
287bool QMacTimeZonePrivate::isTimeZoneIdAvailable(
const QByteArray& ianaId)
const
289 QMacAutoReleasePool pool;
290 return [NSTimeZone timeZoneWithName:QString::fromUtf8(ianaId).toNSString()] != nil;
293QList<QByteArray> QMacTimeZonePrivate::availableTimeZoneIds()
const
295 NSEnumerator *enumerator = NSTimeZone.knownTimeZoneNames.objectEnumerator;
296 QByteArray tzid = QString::fromNSString(enumerator.nextObject).toUtf8();
298 QList<QByteArray> list;
299 while (!tzid.isEmpty()) {
301 tzid = QString::fromNSString(enumerator.nextObject).toUtf8();
304 std::sort(list.begin(), list.end());
305 list.erase(std::unique(list.begin(), list.end()), list.end());
310NSTimeZone *QMacTimeZonePrivate::nsTimeZone()
const