2012-08-25 10:38:29 +00:00
|
|
|
/* Copyright (c) 2011 Google Inc.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
//
|
|
|
|
// GTLDateTime.m
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "GTLDateTime.h"
|
|
|
|
|
2013-01-31 21:22:37 +00:00
|
|
|
@interface GTLDateTime ()
|
|
|
|
|
|
|
|
- (void)setFromDate:(NSDate *)date timeZone:(NSTimeZone *)tz;
|
|
|
|
- (void)setFromRFC3339String:(NSString *)str;
|
|
|
|
|
|
|
|
@property (nonatomic, retain, readwrite) NSTimeZone *timeZone;
|
|
|
|
@property (nonatomic, copy, readwrite) NSDateComponents *dateComponents;
|
|
|
|
@property (nonatomic, assign, readwrite) NSInteger milliseconds;
|
|
|
|
|
|
|
|
@property (nonatomic, assign, readwrite) BOOL hasTime;
|
|
|
|
@property (nonatomic, assign, readwrite) NSInteger offsetSeconds;
|
|
|
|
@property (nonatomic, assign, getter=isUniversalTime, readwrite) BOOL universalTime;
|
|
|
|
|
|
|
|
@end
|
2012-08-25 10:38:29 +00:00
|
|
|
|
2013-04-27 21:14:05 +00:00
|
|
|
static NSCharacterSet *gDashSet = nil;
|
|
|
|
static NSCharacterSet *gTSet = nil;
|
|
|
|
static NSCharacterSet *gColonSet = nil;
|
|
|
|
static NSCharacterSet *gPlusMinusZSet = nil;
|
|
|
|
static NSMutableDictionary *gCalendarsForTimeZones = nil;
|
|
|
|
|
2012-08-25 10:38:29 +00:00
|
|
|
@implementation GTLDateTime
|
|
|
|
|
|
|
|
// A note about milliseconds_:
|
|
|
|
// RFC 3339 has support for fractions of a second. NSDateComponents is all
|
|
|
|
// NSInteger based, so it can't handle a fraction of a second. NSDate is
|
|
|
|
// built on NSTimeInterval so it has sub-millisecond precision. GTL takes
|
|
|
|
// the compromise of supporting the RFC's optional fractional second support
|
|
|
|
// by maintaining a number of milliseconds past what fits in the
|
|
|
|
// NSDateComponents. The parsing and string conversions will include
|
|
|
|
// 3 decimal digits (hence milliseconds). When going to a string, the decimal
|
|
|
|
// digits are only included if the milliseconds are non zero.
|
|
|
|
|
|
|
|
@dynamic date;
|
|
|
|
@dynamic calendar;
|
|
|
|
@dynamic RFC3339String;
|
|
|
|
@dynamic stringValue;
|
|
|
|
@dynamic timeZone;
|
|
|
|
@dynamic hasTime;
|
|
|
|
|
|
|
|
@synthesize dateComponents = dateComponents_,
|
|
|
|
milliseconds = milliseconds_,
|
|
|
|
offsetSeconds = offsetSeconds_,
|
|
|
|
universalTime = isUniversalTime_;
|
|
|
|
|
2013-04-27 21:14:05 +00:00
|
|
|
+ (void)initialize {
|
|
|
|
// Note that initialize is guaranteed by the runtime to be called in a
|
|
|
|
// thread-safe manner.
|
|
|
|
if (gDashSet == nil) {
|
|
|
|
gDashSet = [[NSCharacterSet characterSetWithCharactersInString:@"-"] retain];
|
|
|
|
gTSet = [[NSCharacterSet characterSetWithCharactersInString:@"Tt "] retain];
|
|
|
|
gColonSet = [[NSCharacterSet characterSetWithCharactersInString:@":"] retain];
|
|
|
|
gPlusMinusZSet = [[NSCharacterSet characterSetWithCharactersInString:@"+-zZ"] retain];
|
|
|
|
|
|
|
|
gCalendarsForTimeZones = [[NSMutableDictionary alloc] init];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-25 10:38:29 +00:00
|
|
|
+ (GTLDateTime *)dateTimeWithRFC3339String:(NSString *)str {
|
|
|
|
if (str == nil) return nil;
|
|
|
|
|
|
|
|
GTLDateTime *result = [[[self alloc] init] autorelease];
|
|
|
|
[result setFromRFC3339String:str];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (GTLDateTime *)dateTimeWithDate:(NSDate *)date timeZone:(NSTimeZone *)tz {
|
|
|
|
if (date == nil) return nil;
|
|
|
|
|
|
|
|
GTLDateTime *result = [[[self alloc] init] autorelease];
|
|
|
|
[result setFromDate:date timeZone:tz];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-01-31 21:22:37 +00:00
|
|
|
+ (GTLDateTime *)dateTimeForAllDayWithDate:(NSDate *)date {
|
|
|
|
if (date == nil) return nil;
|
|
|
|
|
|
|
|
GTLDateTime *result = [[[self alloc] init] autorelease];
|
|
|
|
[result setFromDate:date timeZone:nil];
|
|
|
|
result.hasTime = NO;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (GTLDateTime *)dateTimeWithDateComponents:(NSDateComponents *)components {
|
|
|
|
NSCalendar *cal = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
|
|
|
|
NSDate *date = [cal dateFromComponents:components];
|
|
|
|
#if GTL_IPHONE
|
|
|
|
NSTimeZone *tz = [components timeZone];
|
|
|
|
#else
|
|
|
|
// NSDateComponents added timeZone: in Mac OS X 10.7.
|
|
|
|
NSTimeZone *tz = nil;
|
|
|
|
if ([components respondsToSelector:@selector(timeZone)]) {
|
|
|
|
tz = [components timeZone];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return [self dateTimeWithDate:date timeZone:tz];
|
|
|
|
}
|
|
|
|
|
2012-08-25 10:38:29 +00:00
|
|
|
- (void)dealloc {
|
|
|
|
[dateComponents_ release];
|
|
|
|
[timeZone_ release];
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)copyWithZone:(NSZone *)zone {
|
2013-01-31 21:22:37 +00:00
|
|
|
// Object is immutable
|
|
|
|
return [self retain];
|
2012-08-25 10:38:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// until NSDateComponent implements isEqual, we'll use this
|
|
|
|
- (BOOL)doesDateComponents:(NSDateComponents *)dc1
|
|
|
|
equalDateComponents:(NSDateComponents *)dc2 {
|
|
|
|
|
|
|
|
return [dc1 era] == [dc2 era]
|
|
|
|
&& [dc1 year] == [dc2 year]
|
|
|
|
&& [dc1 month] == [dc2 month]
|
|
|
|
&& [dc1 day] == [dc2 day]
|
|
|
|
&& [dc1 hour] == [dc2 hour]
|
|
|
|
&& [dc1 minute] == [dc2 minute]
|
|
|
|
&& [dc1 second] == [dc2 second]
|
|
|
|
&& [dc1 week] == [dc2 week]
|
|
|
|
&& [dc1 weekday] == [dc2 weekday]
|
|
|
|
&& [dc1 weekdayOrdinal] == [dc2 weekdayOrdinal];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isEqual:(GTLDateTime *)other {
|
|
|
|
|
|
|
|
if (self == other) return YES;
|
|
|
|
if (![other isKindOfClass:[GTLDateTime class]]) return NO;
|
|
|
|
|
|
|
|
BOOL areDateComponentsEqual = [self doesDateComponents:self.dateComponents
|
|
|
|
equalDateComponents:other.dateComponents];
|
|
|
|
NSTimeZone *tz1 = self.timeZone;
|
|
|
|
NSTimeZone *tz2 = other.timeZone;
|
|
|
|
BOOL areTimeZonesEqual = (tz1 == tz2 || (tz2 && [tz1 isEqual:tz2]));
|
|
|
|
|
|
|
|
return self.offsetSeconds == other.offsetSeconds
|
|
|
|
&& self.isUniversalTime == other.isUniversalTime
|
|
|
|
&& self.milliseconds == other.milliseconds
|
|
|
|
&& areDateComponentsEqual
|
|
|
|
&& areTimeZonesEqual;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)description {
|
|
|
|
return [NSString stringWithFormat:@"%@ %p: {%@}",
|
|
|
|
[self class], self, self.RFC3339String];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSTimeZone *)timeZone {
|
|
|
|
if (timeZone_) {
|
|
|
|
return timeZone_;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self.isUniversalTime) {
|
|
|
|
NSTimeZone *ztz = [NSTimeZone timeZoneWithName:@"Universal"];
|
|
|
|
return ztz;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSInteger offsetSeconds = self.offsetSeconds;
|
|
|
|
|
|
|
|
if (offsetSeconds != NSUndefinedDateComponent) {
|
|
|
|
NSTimeZone *tz = [NSTimeZone timeZoneForSecondsFromGMT:offsetSeconds];
|
|
|
|
return tz;
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setTimeZone:(NSTimeZone *)timeZone {
|
|
|
|
[timeZone_ release];
|
|
|
|
timeZone_ = [timeZone retain];
|
|
|
|
|
|
|
|
if (timeZone) {
|
|
|
|
NSInteger offsetSeconds = [timeZone secondsFromGMTForDate:self.date];
|
|
|
|
self.offsetSeconds = offsetSeconds;
|
|
|
|
} else {
|
|
|
|
self.offsetSeconds = NSUndefinedDateComponent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-27 21:14:05 +00:00
|
|
|
- (NSCalendar *)calendarForTimeZone:(NSTimeZone *)tz {
|
|
|
|
NSCalendar *cal = nil;
|
|
|
|
@synchronized(gCalendarsForTimeZones) {
|
|
|
|
id tzKey = (tz ? tz : [NSNull null]);
|
|
|
|
cal = [gCalendarsForTimeZones objectForKey:tzKey];
|
|
|
|
if (cal == nil) {
|
|
|
|
cal = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
|
|
|
|
if (tz) {
|
|
|
|
[cal setTimeZone:tz];
|
|
|
|
}
|
|
|
|
[gCalendarsForTimeZones setObject:cal forKey:tzKey];
|
|
|
|
}
|
2012-08-25 10:38:29 +00:00
|
|
|
}
|
|
|
|
return cal;
|
|
|
|
}
|
|
|
|
|
2013-04-27 21:14:05 +00:00
|
|
|
- (NSCalendar *)calendar {
|
|
|
|
NSTimeZone *tz = self.timeZone;
|
|
|
|
return [self calendarForTimeZone:tz];
|
|
|
|
}
|
|
|
|
|
2012-08-25 10:38:29 +00:00
|
|
|
- (NSDate *)date {
|
|
|
|
NSDateComponents *dateComponents = self.dateComponents;
|
|
|
|
NSTimeInterval extraMillisecondsAsSeconds = 0.0;
|
2013-04-27 21:14:05 +00:00
|
|
|
NSCalendar *cal;
|
2012-08-25 10:38:29 +00:00
|
|
|
|
|
|
|
if (!self.hasTime) {
|
2013-04-27 21:14:05 +00:00
|
|
|
// We're not keeping track of a time, but NSDate always is based on
|
2012-08-25 10:38:29 +00:00
|
|
|
// an absolute time. We want to avoid returning an NSDate where the
|
|
|
|
// calendar date appears different from what was used to create our
|
|
|
|
// date-time object.
|
|
|
|
//
|
|
|
|
// We'll make a copy of the date components, setting the time on our
|
|
|
|
// copy to noon GMT, since that ensures the date renders correctly for
|
2013-04-27 21:14:05 +00:00
|
|
|
// any time zone.
|
2012-08-25 10:38:29 +00:00
|
|
|
NSDateComponents *noonDateComponents = [[dateComponents copy] autorelease];
|
|
|
|
[noonDateComponents setHour:12];
|
|
|
|
[noonDateComponents setMinute:0];
|
|
|
|
[noonDateComponents setSecond:0];
|
|
|
|
dateComponents = noonDateComponents;
|
|
|
|
|
|
|
|
NSTimeZone *gmt = [NSTimeZone timeZoneWithName:@"Universal"];
|
2013-04-27 21:14:05 +00:00
|
|
|
cal = [self calendarForTimeZone:gmt];
|
2012-08-25 10:38:29 +00:00
|
|
|
} else {
|
2013-04-27 21:14:05 +00:00
|
|
|
cal = self.calendar;
|
|
|
|
|
2012-08-25 10:38:29 +00:00
|
|
|
// Add in the fractional seconds that don't fit into NSDateComponents.
|
|
|
|
extraMillisecondsAsSeconds = ((NSTimeInterval)self.milliseconds) / 1000.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSDate *date = [cal dateFromComponents:dateComponents];
|
|
|
|
|
|
|
|
// Add in any milliseconds that didn't fit into the dateComponents.
|
|
|
|
if (extraMillisecondsAsSeconds > 0.0) {
|
|
|
|
#if GTL_IPHONE || (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5)
|
|
|
|
date = [date dateByAddingTimeInterval:extraMillisecondsAsSeconds];
|
|
|
|
#else
|
|
|
|
date = [date addTimeInterval:extraMillisecondsAsSeconds];
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return date;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)stringValue {
|
|
|
|
return self.RFC3339String;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)RFC3339String {
|
|
|
|
NSDateComponents *dateComponents = self.dateComponents;
|
|
|
|
NSInteger offset = self.offsetSeconds;
|
|
|
|
|
|
|
|
NSString *timeString = @""; // timeString like "T15:10:46-08:00"
|
|
|
|
|
|
|
|
if (self.hasTime) {
|
|
|
|
|
|
|
|
NSString *timeOffsetString; // timeOffsetString like "-08:00"
|
|
|
|
|
|
|
|
if (self.isUniversalTime) {
|
|
|
|
timeOffsetString = @"Z";
|
|
|
|
} else if (offset == NSUndefinedDateComponent) {
|
|
|
|
// unknown offset is rendered as -00:00 per
|
|
|
|
// http://www.ietf.org/rfc/rfc3339.txt section 4.3
|
|
|
|
timeOffsetString = @"-00:00";
|
|
|
|
} else {
|
|
|
|
NSString *sign = @"+";
|
|
|
|
if (offset < 0) {
|
|
|
|
sign = @"-";
|
|
|
|
offset = -offset;
|
|
|
|
}
|
|
|
|
timeOffsetString = [NSString stringWithFormat:@"%@%02ld:%02ld",
|
|
|
|
sign, (long)(offset/(60*60)) % 24, (long)(offset / 60) % 60];
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString *fractionalSecondsString = @"";
|
|
|
|
if (self.milliseconds > 0.0) {
|
|
|
|
fractionalSecondsString = [NSString stringWithFormat:@".%03ld", (long)self.milliseconds];
|
|
|
|
}
|
|
|
|
|
|
|
|
timeString = [NSString stringWithFormat:@"T%02ld:%02ld:%02ld%@%@",
|
|
|
|
(long)[dateComponents hour], (long)[dateComponents minute],
|
|
|
|
(long)[dateComponents second], fractionalSecondsString, timeOffsetString];
|
|
|
|
}
|
|
|
|
|
|
|
|
// full dateString like "2006-11-17T15:10:46-08:00"
|
|
|
|
NSString *dateString = [NSString stringWithFormat:@"%04ld-%02ld-%02ld%@",
|
|
|
|
(long)[dateComponents year], (long)[dateComponents month],
|
|
|
|
(long)[dateComponents day], timeString];
|
|
|
|
|
|
|
|
return dateString;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setFromDate:(NSDate *)date timeZone:(NSTimeZone *)tz {
|
2013-04-27 21:14:05 +00:00
|
|
|
NSCalendar *cal = [self calendarForTimeZone:tz];
|
2012-08-25 10:38:29 +00:00
|
|
|
|
|
|
|
NSUInteger const kComponentBits = (NSYearCalendarUnit | NSMonthCalendarUnit
|
|
|
|
| NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit
|
|
|
|
| NSSecondCalendarUnit);
|
|
|
|
|
|
|
|
NSDateComponents *components = [cal components:kComponentBits fromDate:date];
|
|
|
|
self.dateComponents = components;
|
|
|
|
|
|
|
|
// Extract the fractional seconds.
|
|
|
|
NSTimeInterval asTimeInterval = [date timeIntervalSince1970];
|
|
|
|
NSTimeInterval worker = asTimeInterval - trunc(asTimeInterval);
|
|
|
|
self.milliseconds = (NSInteger)round(worker * 1000.0);
|
|
|
|
|
|
|
|
self.universalTime = NO;
|
|
|
|
|
|
|
|
NSInteger offset = NSUndefinedDateComponent;
|
|
|
|
|
|
|
|
if (tz) {
|
|
|
|
offset = [tz secondsFromGMTForDate:date];
|
|
|
|
|
|
|
|
if (offset == 0 && [tz isEqualToTimeZone:[NSTimeZone timeZoneWithName:@"Universal"]]) {
|
|
|
|
self.universalTime = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.offsetSeconds = offset;
|
|
|
|
|
|
|
|
// though offset seconds are authoritative, we'll retain the time zone
|
|
|
|
// since we can't regenerate it reliably from just the offset
|
|
|
|
timeZone_ = [tz retain];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setFromRFC3339String:(NSString *)str {
|
|
|
|
|
|
|
|
NSInteger year = NSUndefinedDateComponent;
|
|
|
|
NSInteger month = NSUndefinedDateComponent;
|
|
|
|
NSInteger day = NSUndefinedDateComponent;
|
|
|
|
NSInteger hour = NSUndefinedDateComponent;
|
|
|
|
NSInteger minute = NSUndefinedDateComponent;
|
|
|
|
NSInteger sec = NSUndefinedDateComponent;
|
|
|
|
NSInteger milliseconds = 0;
|
|
|
|
double secDouble = -1.0;
|
|
|
|
NSString* sign = nil;
|
|
|
|
NSInteger offsetHour = 0;
|
|
|
|
NSInteger offsetMinute = 0;
|
|
|
|
|
|
|
|
if ([str length] > 0) {
|
|
|
|
NSScanner* scanner = [NSScanner scannerWithString:str];
|
|
|
|
// There should be no whitespace, so no skip characters.
|
|
|
|
[scanner setCharactersToBeSkipped:nil];
|
|
|
|
|
|
|
|
// for example, scan 2006-11-17T15:10:46-08:00
|
|
|
|
// or 2006-11-17T15:10:46Z
|
|
|
|
if (// yyyy-mm-dd
|
|
|
|
[scanner scanInteger:&year] &&
|
2013-04-27 21:14:05 +00:00
|
|
|
[scanner scanCharactersFromSet:gDashSet intoString:NULL] &&
|
2012-08-25 10:38:29 +00:00
|
|
|
[scanner scanInteger:&month] &&
|
2013-04-27 21:14:05 +00:00
|
|
|
[scanner scanCharactersFromSet:gDashSet intoString:NULL] &&
|
2012-08-25 10:38:29 +00:00
|
|
|
[scanner scanInteger:&day] &&
|
|
|
|
// Thh:mm:ss
|
2013-04-27 21:14:05 +00:00
|
|
|
[scanner scanCharactersFromSet:gTSet intoString:NULL] &&
|
2012-08-25 10:38:29 +00:00
|
|
|
[scanner scanInteger:&hour] &&
|
2013-04-27 21:14:05 +00:00
|
|
|
[scanner scanCharactersFromSet:gColonSet intoString:NULL] &&
|
2012-08-25 10:38:29 +00:00
|
|
|
[scanner scanInteger:&minute] &&
|
2013-04-27 21:14:05 +00:00
|
|
|
[scanner scanCharactersFromSet:gColonSet intoString:NULL] &&
|
2012-08-25 10:38:29 +00:00
|
|
|
[scanner scanDouble:&secDouble]) {
|
|
|
|
|
|
|
|
// At this point we got secDouble, pull it apart.
|
|
|
|
sec = (NSInteger)secDouble;
|
|
|
|
double worker = secDouble - ((double)sec);
|
|
|
|
milliseconds = (NSInteger)round(worker * 1000.0);
|
|
|
|
|
|
|
|
// Finish parsing, now the offset info.
|
|
|
|
if (// Z or +hh:mm
|
2013-04-27 21:14:05 +00:00
|
|
|
[scanner scanCharactersFromSet:gPlusMinusZSet intoString:&sign] &&
|
2012-08-25 10:38:29 +00:00
|
|
|
[scanner scanInteger:&offsetHour] &&
|
2013-04-27 21:14:05 +00:00
|
|
|
[scanner scanCharactersFromSet:gColonSet intoString:NULL] &&
|
2012-08-25 10:38:29 +00:00
|
|
|
[scanner scanInteger:&offsetMinute]) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NSDateComponents *dateComponents = [[[NSDateComponents alloc] init] autorelease];
|
|
|
|
[dateComponents setYear:year];
|
|
|
|
[dateComponents setMonth:month];
|
|
|
|
[dateComponents setDay:day];
|
|
|
|
[dateComponents setHour:hour];
|
|
|
|
[dateComponents setMinute:minute];
|
|
|
|
[dateComponents setSecond:sec];
|
|
|
|
|
|
|
|
self.dateComponents = dateComponents;
|
|
|
|
self.milliseconds = milliseconds;
|
|
|
|
|
|
|
|
// determine the offset, like from Z, or -08:00:00.0
|
|
|
|
|
|
|
|
self.timeZone = nil;
|
|
|
|
|
|
|
|
NSInteger totalOffset = NSUndefinedDateComponent;
|
|
|
|
self.universalTime = NO;
|
|
|
|
|
|
|
|
if ([sign caseInsensitiveCompare:@"Z"] == NSOrderedSame) {
|
|
|
|
|
|
|
|
self.universalTime = YES;
|
|
|
|
totalOffset = 0;
|
|
|
|
|
|
|
|
} else if (sign != nil) {
|
|
|
|
|
|
|
|
totalOffset = (60 * offsetMinute) + (60 * 60 * offsetHour);
|
|
|
|
|
|
|
|
if ([sign isEqual:@"-"]) {
|
|
|
|
|
|
|
|
if (totalOffset == 0) {
|
|
|
|
// special case: offset of -0.00 means undefined offset
|
|
|
|
totalOffset = NSUndefinedDateComponent;
|
|
|
|
} else {
|
|
|
|
totalOffset *= -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.offsetSeconds = totalOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)hasTime {
|
|
|
|
NSDateComponents *dateComponents = self.dateComponents;
|
|
|
|
|
|
|
|
BOOL hasTime = ([dateComponents hour] != NSUndefinedDateComponent
|
|
|
|
&& [dateComponents minute] != NSUndefinedDateComponent);
|
|
|
|
|
|
|
|
return hasTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setHasTime:(BOOL)shouldHaveTime {
|
|
|
|
|
|
|
|
// we'll set time values to zero or NSUndefinedDateComponent as appropriate
|
|
|
|
BOOL hadTime = self.hasTime;
|
|
|
|
|
|
|
|
if (shouldHaveTime && !hadTime) {
|
|
|
|
[dateComponents_ setHour:0];
|
|
|
|
[dateComponents_ setMinute:0];
|
|
|
|
[dateComponents_ setSecond:0];
|
|
|
|
milliseconds_ = 0;
|
|
|
|
offsetSeconds_ = NSUndefinedDateComponent;
|
|
|
|
isUniversalTime_ = NO;
|
|
|
|
|
|
|
|
} else if (hadTime && !shouldHaveTime) {
|
|
|
|
[dateComponents_ setHour:NSUndefinedDateComponent];
|
|
|
|
[dateComponents_ setMinute:NSUndefinedDateComponent];
|
|
|
|
[dateComponents_ setSecond:NSUndefinedDateComponent];
|
|
|
|
milliseconds_ = 0;
|
|
|
|
offsetSeconds_ = NSUndefinedDateComponent;
|
|
|
|
isUniversalTime_ = NO;
|
|
|
|
self.timeZone = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@end
|