8#include "private/qcore_mac_p.h"
11#include <Foundation/NSTimeZone.h>
20
21
22
23
24
27QMacTimeZonePrivate::QMacTimeZonePrivate()
29 QMacAutoReleasePool pool;
31 [NSTimeZone resetSystemTimeZone];
32 m_nstz = [NSTimeZone.systemTimeZone retain];
34 m_id = QString::fromNSString(m_nstz.name).toUtf8();
38QMacTimeZonePrivate::QMacTimeZonePrivate(
const QByteArray &ianaId)
44QMacTimeZonePrivate::QMacTimeZonePrivate(
const QMacTimeZonePrivate &other)
45 : QTimeZonePrivate(other), m_nstz([other.m_nstz copy])
49QMacTimeZonePrivate::~QMacTimeZonePrivate()
54QMacTimeZonePrivate *QMacTimeZonePrivate::clone()
const
56 return new QMacTimeZonePrivate(*
this);
59void QMacTimeZonePrivate::init(
const QByteArray &ianaId)
61 QMacAutoReleasePool pool;
63 m_nstz = [[NSTimeZone timeZoneWithName:QString::fromUtf8(ianaId).toNSString()] retain];
71 m_nstz = [NSTimeZone.systemTimeZone retain];
73 if (QString::fromNSString(m_nstz.name).toUtf8() == ianaId)
78QString QMacTimeZonePrivate::comment()
const
80 return QString::fromNSString(m_nstz.description);
83QString QMacTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
84 QTimeZone::NameType nameType,
85 const QLocale &locale)
const
88 if (nameType == QTimeZone::OffsetName) {
89 const Data nowData = data(QDateTime::currentMSecsSinceEpoch());
91 if (timeType == QTimeZone::DaylightTime && hasDaylightTime())
92 return isoOffsetFormat(nowData.standardTimeOffset + 3600);
94 return isoOffsetFormat(nowData.standardTimeOffset);
97 NSTimeZoneNameStyle style = NSTimeZoneNameStyleStandard;
100 case QTimeZone::ShortName :
101 if (timeType == QTimeZone::DaylightTime)
102 style = NSTimeZoneNameStyleShortDaylightSaving;
103 else if (timeType == QTimeZone::GenericTime)
104 style = NSTimeZoneNameStyleShortGeneric;
106 style = NSTimeZoneNameStyleShortStandard;
108 case QTimeZone::DefaultName :
109 case QTimeZone::LongName :
110 if (timeType == QTimeZone::DaylightTime)
111 style = NSTimeZoneNameStyleDaylightSaving;
112 else if (timeType == QTimeZone::GenericTime)
113 style = NSTimeZoneNameStyleGeneric;
115 style = NSTimeZoneNameStyleStandard;
117 case QTimeZone::OffsetName :
122 NSString *macLocaleCode = locale.name().toNSString();
123 NSLocale *macLocale = [[NSLocale alloc] initWithLocaleIdentifier:macLocaleCode];
124 const QString result = QString::fromNSString([m_nstz localizedName:style locale:macLocale]);
129QString QMacTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch)
const
131 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
132 return QString::fromNSString([m_nstz abbreviationForDate:[NSDate dateWithTimeIntervalSince1970:seconds]]);
135int QMacTimeZonePrivate::offsetFromUtc(qint64 atMSecsSinceEpoch)
const
137 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
138 return [m_nstz secondsFromGMTForDate:[NSDate dateWithTimeIntervalSince1970:seconds]];
141int QMacTimeZonePrivate::standardTimeOffset(qint64 atMSecsSinceEpoch)
const
143 return offsetFromUtc(atMSecsSinceEpoch) - daylightTimeOffset(atMSecsSinceEpoch);
146int QMacTimeZonePrivate::daylightTimeOffset(qint64 atMSecsSinceEpoch)
const
148 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
149 return [m_nstz daylightSavingTimeOffsetForDate:[NSDate dateWithTimeIntervalSince1970:seconds]];
152bool QMacTimeZonePrivate::hasDaylightTime()
const
157 NSDate *epoch = [NSDate dateWithTimeIntervalSince1970:0];
158 const NSDate *date = [m_nstz nextDaylightSavingTimeTransitionAfterDate:epoch];
159 const bool result = (date.timeIntervalSince1970 > epoch.timeIntervalSince1970);
163bool QMacTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch)
const
165 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
166 return [m_nstz isDaylightSavingTimeForDate:[NSDate dateWithTimeIntervalSince1970:seconds]];
169QTimeZonePrivate::Data QMacTimeZonePrivate::data(qint64 forMSecsSinceEpoch)
const
171 QMacAutoReleasePool pool;
172 const NSTimeInterval seconds = forMSecsSinceEpoch / 1000.0;
173 NSDate *date = [NSDate dateWithTimeIntervalSince1970:seconds];
175 data.atMSecsSinceEpoch = forMSecsSinceEpoch;
176 data.offsetFromUtc = [m_nstz secondsFromGMTForDate:date];
177 data.daylightTimeOffset = [m_nstz daylightSavingTimeOffsetForDate:date];
178 data.standardTimeOffset = data.offsetFromUtc - data.daylightTimeOffset;
179 data.abbreviation = QString::fromNSString([m_nstz abbreviationForDate:date]);
183bool QMacTimeZonePrivate::hasTransitions()
const
189QTimeZonePrivate::Data QMacTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch)
const
192 const NSTimeInterval seconds = afterMSecsSinceEpoch / 1000.0;
193 NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:seconds];
194 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
195 const NSTimeInterval nextSecs = nextDate.timeIntervalSince1970;
196 if (nextDate == nil || nextSecs <= seconds) {
200 tran.atMSecsSinceEpoch = nextSecs * 1000;
201 tran.offsetFromUtc = [m_nstz secondsFromGMTForDate:nextDate];
202 tran.daylightTimeOffset = [m_nstz daylightSavingTimeOffsetForDate:nextDate];
203 tran.standardTimeOffset = tran.offsetFromUtc - tran.daylightTimeOffset;
204 tran.abbreviation = QString::fromNSString([m_nstz abbreviationForDate:nextDate]);
208QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch)
const
211 constexpr NSTimeInterval lowerBound = std::numeric_limits<NSTimeInterval>::lowest();
212 const qint64 endSecs = beforeMSecsSinceEpoch / 1000;
213 const int year = 366 * 24 * 3600;
214 NSTimeInterval prevSecs = endSecs;
215 NSTimeInterval nextSecs = prevSecs - year;
216 NSTimeInterval tranSecs = lowerBound;
218 NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:nextSecs];
219 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
221 && (tranSecs = nextDate.timeIntervalSince1970) < endSecs) {
226 nextDate = [NSDate dateWithTimeIntervalSince1970:lowerBound];
227 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
228 if (nextDate != nil) {
229 NSTimeInterval lateSecs = nextSecs;
230 nextSecs = nextDate.timeIntervalSince1970;
231 Q_ASSERT(nextSecs <= endSecs - year || nextSecs == tranSecs);
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
251 while (nextSecs + year < lateSecs) {
253 NSTimeInterval middle = nextSecs / 2 + lateSecs / 2;
254 NSDate *split = [NSDate dateWithTimeIntervalSince1970:middle];
255 split = [m_nstz nextDaylightSavingTimeTransitionAfterDate:split];
256 if (split != nil && (tranSecs = split.timeIntervalSince1970) < endSecs) {
263 Q_ASSERT(nextDate != nil);
270 while (nextDate != nil && nextSecs < endSecs) {
272 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
273 nextSecs = nextDate.timeIntervalSince1970;
274 if (nextSecs <= prevSecs)
277 if (prevSecs < endSecs)
278 return data(qint64(prevSecs * 1e3));
284QByteArray QMacTimeZonePrivate::systemTimeZoneId()
const
286 QMacAutoReleasePool pool;
289 [NSTimeZone resetSystemTimeZone];
290 Q_ASSERT(NSTimeZone.systemTimeZone);
291 return QString::fromNSString(NSTimeZone.systemTimeZone.name).toUtf8();
294bool QMacTimeZonePrivate::isTimeZoneIdAvailable(QByteArrayView ianaId)
const
296 QMacAutoReleasePool pool;
297 return [NSTimeZone timeZoneWithName:QString::fromUtf8(ianaId).toNSString()] != nil;
300QList<QByteArray> QMacTimeZonePrivate::availableTimeZoneIds()
const
302 NSEnumerator *enumerator = NSTimeZone.knownTimeZoneNames.objectEnumerator;
303 QByteArray tzid = QString::fromNSString(enumerator.nextObject).toUtf8();
305 QList<QByteArray> list;
306 while (!tzid.isEmpty()) {
308 tzid = QString::fromNSString(enumerator.nextObject).toUtf8();
311 std::sort(list.begin(), list.end());
312 list.erase(std::unique(list.begin(), list.end()), list.end());
317NSTimeZone *QMacTimeZonePrivate::nsTimeZone()
const