9#include "private/qcore_mac_p.h"
12#include <Foundation/NSTimeZone.h>
21
22
23
24
25
28QMacTimeZonePrivate::QMacTimeZonePrivate()
30 QMacAutoReleasePool pool;
32 [NSTimeZone resetSystemTimeZone];
33 m_nstz = [NSTimeZone.systemTimeZone retain];
35 m_id = QString::fromNSString(m_nstz.name).toUtf8();
39QMacTimeZonePrivate::QMacTimeZonePrivate(
const QByteArray &ianaId)
45QMacTimeZonePrivate::QMacTimeZonePrivate(
const QMacTimeZonePrivate &other)
46 : QTimeZonePrivate(other), m_nstz([other.m_nstz copy])
50QMacTimeZonePrivate::~QMacTimeZonePrivate()
55QMacTimeZonePrivate *QMacTimeZonePrivate::clone()
const
57 return new QMacTimeZonePrivate(*
this);
60void QMacTimeZonePrivate::init(
const QByteArray &ianaId)
62 QMacAutoReleasePool pool;
64 m_nstz = [[NSTimeZone timeZoneWithName:QString::fromUtf8(ianaId).toNSString()] retain];
72 m_nstz = [NSTimeZone.systemTimeZone retain];
74 if (QString::fromNSString(m_nstz.name).toUtf8() == ianaId)
79QString QMacTimeZonePrivate::comment()
const
81 return QString::fromNSString(m_nstz.description);
84QString QMacTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
85 QTimeZone::NameType nameType,
86 const QLocale &locale)
const
89 if (nameType == QTimeZone::OffsetName) {
90 const Data nowData = data(QDateTime::currentMSecsSinceEpoch());
92 if (timeType == QTimeZone::DaylightTime && hasDaylightTime())
93 return isoOffsetFormat(nowData.standardTimeOffset + 3600);
95 return isoOffsetFormat(nowData.standardTimeOffset);
98 NSTimeZoneNameStyle style = NSTimeZoneNameStyleStandard;
101 case QTimeZone::ShortName :
102 if (timeType == QTimeZone::DaylightTime)
103 style = NSTimeZoneNameStyleShortDaylightSaving;
104 else if (timeType == QTimeZone::GenericTime)
105 style = NSTimeZoneNameStyleShortGeneric;
107 style = NSTimeZoneNameStyleShortStandard;
109 case QTimeZone::DefaultName :
110 case QTimeZone::LongName :
111 if (timeType == QTimeZone::DaylightTime)
112 style = NSTimeZoneNameStyleDaylightSaving;
113 else if (timeType == QTimeZone::GenericTime)
114 style = NSTimeZoneNameStyleGeneric;
116 style = NSTimeZoneNameStyleStandard;
118 case QTimeZone::OffsetName :
123 NSString *macLocaleCode = locale.name().toNSString();
124 NSLocale *macLocale = [[NSLocale alloc] initWithLocaleIdentifier:macLocaleCode];
125 const QString result = QString::fromNSString([m_nstz localizedName:style locale:macLocale]);
130QString QMacTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch)
const
132 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
133 return QString::fromNSString([m_nstz abbreviationForDate:[NSDate dateWithTimeIntervalSince1970:seconds]]);
136int QMacTimeZonePrivate::offsetFromUtc(qint64 atMSecsSinceEpoch)
const
138 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
139 return [m_nstz secondsFromGMTForDate:[NSDate dateWithTimeIntervalSince1970:seconds]];
142int QMacTimeZonePrivate::standardTimeOffset(qint64 atMSecsSinceEpoch)
const
144 return offsetFromUtc(atMSecsSinceEpoch) - daylightTimeOffset(atMSecsSinceEpoch);
147int QMacTimeZonePrivate::daylightTimeOffset(qint64 atMSecsSinceEpoch)
const
149 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
150 return [m_nstz daylightSavingTimeOffsetForDate:[NSDate dateWithTimeIntervalSince1970:seconds]];
153bool QMacTimeZonePrivate::hasDaylightTime()
const
158 NSDate *epoch = [NSDate dateWithTimeIntervalSince1970:0];
159 const NSDate *date = [m_nstz nextDaylightSavingTimeTransitionAfterDate:epoch];
160 const bool result = (date.timeIntervalSince1970 > epoch.timeIntervalSince1970);
164bool QMacTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch)
const
166 const NSTimeInterval seconds = atMSecsSinceEpoch / 1000.0;
167 return [m_nstz isDaylightSavingTimeForDate:[NSDate dateWithTimeIntervalSince1970:seconds]];
170QTimeZonePrivate::Data QMacTimeZonePrivate::data(qint64 forMSecsSinceEpoch)
const
172 QMacAutoReleasePool pool;
173 const NSTimeInterval seconds = forMSecsSinceEpoch / 1000.0;
174 NSDate *date = [NSDate dateWithTimeIntervalSince1970:seconds];
176 data.atMSecsSinceEpoch = forMSecsSinceEpoch;
177 data.offsetFromUtc = [m_nstz secondsFromGMTForDate:date];
178 data.daylightTimeOffset = [m_nstz daylightSavingTimeOffsetForDate:date];
179 data.standardTimeOffset = data.offsetFromUtc - data.daylightTimeOffset;
180 data.abbreviation = QString::fromNSString([m_nstz abbreviationForDate:date]);
184bool QMacTimeZonePrivate::hasTransitions()
const
190QTimeZonePrivate::Data QMacTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch)
const
193 const NSTimeInterval seconds = afterMSecsSinceEpoch / 1000.0;
194 NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:seconds];
195 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
196 const NSTimeInterval nextSecs = nextDate.timeIntervalSince1970;
197 if (nextDate == nil || nextSecs <= seconds) {
201 tran.atMSecsSinceEpoch = nextSecs * 1000;
202 tran.offsetFromUtc = [m_nstz secondsFromGMTForDate:nextDate];
203 tran.daylightTimeOffset = [m_nstz daylightSavingTimeOffsetForDate:nextDate];
204 tran.standardTimeOffset = tran.offsetFromUtc - tran.daylightTimeOffset;
205 tran.abbreviation = QString::fromNSString([m_nstz abbreviationForDate:nextDate]);
209QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch)
const
212 constexpr NSTimeInterval lowerBound = std::numeric_limits<NSTimeInterval>::lowest();
213 const qint64 endSecs = beforeMSecsSinceEpoch / 1000;
214 const int year = 366 * 24 * 3600;
215 NSTimeInterval prevSecs = endSecs;
216 NSTimeInterval nextSecs = prevSecs - year;
217 NSTimeInterval tranSecs = lowerBound;
219 NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:nextSecs];
220 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
222 && (tranSecs = nextDate.timeIntervalSince1970) < endSecs) {
227 nextDate = [NSDate dateWithTimeIntervalSince1970:lowerBound];
228 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
229 if (nextDate != nil) {
230 NSTimeInterval lateSecs = nextSecs;
231 nextSecs = nextDate.timeIntervalSince1970;
232 Q_ASSERT(nextSecs <= endSecs - year || nextSecs == tranSecs);
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
252 while (nextSecs + year < lateSecs) {
254 NSTimeInterval middle = nextSecs / 2 + lateSecs / 2;
255 NSDate *split = [NSDate dateWithTimeIntervalSince1970:middle];
256 split = [m_nstz nextDaylightSavingTimeTransitionAfterDate:split];
257 if (split != nil && (tranSecs = split.timeIntervalSince1970) < endSecs) {
264 Q_ASSERT(nextDate != nil);
271 while (nextDate != nil && nextSecs < endSecs) {
273 nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate];
274 nextSecs = nextDate.timeIntervalSince1970;
275 if (nextSecs <= prevSecs)
278 if (prevSecs < endSecs)
279 return data(qint64(prevSecs * 1e3));
285QByteArray QMacTimeZonePrivate::systemTimeZoneId()
const
287 QMacAutoReleasePool pool;
290 [NSTimeZone resetSystemTimeZone];
291 Q_ASSERT(NSTimeZone.systemTimeZone);
292 return QString::fromNSString(NSTimeZone.systemTimeZone.name).toUtf8();
295bool QMacTimeZonePrivate::isTimeZoneIdAvailable(QByteArrayView ianaId)
const
297 QMacAutoReleasePool pool;
298 return [NSTimeZone timeZoneWithName:QString::fromUtf8(ianaId).toNSString()] != nil;
301QList<QByteArray> QMacTimeZonePrivate::availableTimeZoneIds()
const
303 NSEnumerator *enumerator = NSTimeZone.knownTimeZoneNames.objectEnumerator;
304 QByteArray tzid = QString::fromNSString(enumerator.nextObject).toUtf8();
306 QList<QByteArray> list;
307 while (!tzid.isEmpty()) {
309 tzid = QString::fromNSString(enumerator.nextObject).toUtf8();
312 std::sort(list.begin(), list.end());
313 list.erase(std::unique(list.begin(), list.end()), list.end());
318NSTimeZone *QMacTimeZonePrivate::nsTimeZone()
const