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
155 return hasTransitions();
158bool QMacTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch)
const
160 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
161 return [m_nstz isDaylightSavingTimeForDate:[NSDate dateWithTimeIntervalSince1970:seconds]];
164QTimeZonePrivate::Data QMacTimeZonePrivate::data(qint64 forMSecsSinceEpoch)
const
166 QMacAutoReleasePool pool;
167 const NSTimeInterval seconds = forMSecsSinceEpoch / 1000.0;
168 NSDate *date = [NSDate dateWithTimeIntervalSince1970:seconds];
170 data.atMSecsSinceEpoch = forMSecsSinceEpoch;
171 data.offsetFromUtc = [m_nstz secondsFromGMTForDate:date];
172 data.daylightTimeOffset = [m_nstz daylightSavingTimeOffsetForDate:date];
173 data.standardTimeOffset = data.offsetFromUtc - data.daylightTimeOffset;
174 data.abbreviation = QString::fromNSString([m_nstz abbreviationForDate:date]);
178bool QMacTimeZonePrivate::hasTransitions()
const
182 NSDate *epoch = [NSDate dateWithTimeIntervalSince1970:0];
183 const NSDate *date = [m_nstz nextDaylightSavingTimeTransitionAfterDate:epoch];
184 const bool result = (date.timeIntervalSince1970 > epoch.timeIntervalSince1970);
188QTimeZonePrivate::Data QMacTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch)
const
191 const NSTimeInterval seconds = afterMSecsSinceEpoch / 1000.0;
192 NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:seconds];
193 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
194 const NSTimeInterval nextSecs = nextDate.timeIntervalSince1970;
195 if (nextDate == nil || nextSecs <= seconds) {
199 tran.atMSecsSinceEpoch = nextSecs * 1000;
200 tran.offsetFromUtc = [m_nstz secondsFromGMTForDate:nextDate];
201 tran.daylightTimeOffset = [m_nstz daylightSavingTimeOffsetForDate:nextDate];
202 tran.standardTimeOffset = tran.offsetFromUtc - tran.daylightTimeOffset;
203 tran.abbreviation = QString::fromNSString([m_nstz abbreviationForDate:nextDate]);
207QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch)
const
210 constexpr NSTimeInterval lowerBound = std::numeric_limits<NSTimeInterval>::lowest();
211 const qint64 endSecs = beforeMSecsSinceEpoch / 1000;
212 const int year = 366 * 24 * 3600;
213 NSTimeInterval prevSecs = endSecs;
214 NSTimeInterval nextSecs = prevSecs - year;
215 NSTimeInterval tranSecs = lowerBound;
217 NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:nextSecs];
218 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
220 && (tranSecs = nextDate.timeIntervalSince1970) < endSecs) {
225 nextDate = [NSDate dateWithTimeIntervalSince1970:lowerBound];
226 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
227 if (nextDate != nil) {
228 NSTimeInterval lateSecs = nextSecs;
229 nextSecs = nextDate.timeIntervalSince1970;
230 Q_ASSERT(nextSecs <= endSecs - year || nextSecs == tranSecs);
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
250 while (nextSecs + year < lateSecs) {
252 NSTimeInterval middle = nextSecs / 2 + lateSecs / 2;
253 NSDate *split = [NSDate dateWithTimeIntervalSince1970:middle];
254 split = [m_nstz nextDaylightSavingTimeTransitionAfterDate:split];
255 if (split != nil && (tranSecs = split.timeIntervalSince1970) < endSecs) {
262 Q_ASSERT(nextDate != nil);
269 while (nextDate != nil && nextSecs < endSecs) {
271 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
272 nextSecs = nextDate.timeIntervalSince1970;
273 if (nextSecs <= prevSecs)
276 if (prevSecs < endSecs)
277 return data(qint64(prevSecs * 1e3));
283QByteArray QMacTimeZonePrivate::systemTimeZoneId()
const
285 QMacAutoReleasePool pool;
288 [NSTimeZone resetSystemTimeZone];
289 Q_ASSERT(NSTimeZone.systemTimeZone);
290 return QString::fromNSString(NSTimeZone.systemTimeZone.name).toUtf8();
293bool QMacTimeZonePrivate::isTimeZoneIdAvailable(
const QByteArray& ianaId)
const
295 QMacAutoReleasePool pool;
296 return [NSTimeZone timeZoneWithName:QString::fromUtf8(ianaId).toNSString()] != nil;
299QList<QByteArray> QMacTimeZonePrivate::availableTimeZoneIds()
const
301 NSEnumerator *enumerator = NSTimeZone.knownTimeZoneNames.objectEnumerator;
302 QByteArray tzid = QString::fromNSString(enumerator.nextObject).toUtf8();
304 QList<QByteArray> list;
305 while (!tzid.isEmpty()) {
307 tzid = QString::fromNSString(enumerator.nextObject).toUtf8();
310 std::sort(list.begin(), list.end());
311 list.erase(std::unique(list.begin(), list.end()), list.end());
316NSTimeZone *QMacTimeZonePrivate::nsTimeZone()
const