How to best debug NSDate / NSTimezone related code - objective-c

I know that NSDate does not represent a timezone, but perhaps someone can advise me on how to best debug its relationship to other classes, for example NSDatePicker, CalCalendarStore.
As an example, I want to set the date for a date picker to 01-01-2012. I do something like this:
newDate = [NSDate date];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:newDate];
[components setMonth:1];
[components setDay:1];
newDate = [calendar dateFromComponents:components];
This works fine in my datepicker, but as soon as I try debugging date-related code, things get very confusing (with TZ-related shifts in the hour, sometimes even day). Can someone advise me on how to do this?
If I should use a date formatter (probably!), how should I do this so I can easily debug without cluttering up the code too much?

NSDate is just a wrapper around unix time and as such is not time zone aware at all, its actually your date formatter that puts a time zone of any kind on it.
Dealing with similar problems I ended up just forcing all my NSDate objects to use UTC dates (when not worrying about the "time" components themselves).
You have to use a new NSCalendar instance with the timezone property set to UTC to make those dates, but this way you're dealing with consistant dates, just use a UTC time zone set formatter to display them, or a UTC set Calendar to break them up into components as needed.

Related

How can I get the amound of seconds from a NSDate ("hh:mm:ss") and vice versa

I am trying to make a timer and yes I have looked at NSTimer and it is not what I'm looking for, I basically need a way to convert a NSDate in the format of ("hh:mm:ss") into the amount of seconds that would be in this. And then I need a way to do the opposite so convert the seconds to the amount of hours, minutes and leftover seconds from that.
You can extract components from NSDate using the NSCalendar class. The following example extracts a single component, NSCalendarUnitSecond, from the current date.
NSDate *today = [NSDate date];
NSCalendar *localCalendar = [NSCalendar currentCalendar];
NSUInteger seconds = [localCalendar component:NSCalendarUnitSecond fromDate:today];
You could have a place holder date e.g. 00:00:00 and then use the NSDate function timeIntervalSinceDate: to get the seconds. Converting back again you could use the dateWithTimeInterval: method.
Obviously both these dates would have to be the same year month and day and you could use any arbitrary values for these as long as they are the same.

What is the best way of getting the CFAbsoluteTime of midnight of today?

Im using CFAbsoluteTimeGetCurrent() to get the current time, as a CFAbsoluteTime struct.
What is the best way of getting the CFAbsoluteTime of midnight of today?
Ive considered getting midnight using a similar method to the one shown here and then converting the result to a CFAbsoluteTime, but this seems ridiculously complicated to do a simple thing.
Is there a better way?
Computing "midnight of the current day" is not completely trivial, because things as
the time zone and daylight savings time transitions must be taken into account.
My preferred way is
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *midnight;
[calendar rangeOfUnit:NSDayCalendarUnit
startDate:&midnight
interval:NULL
forDate:[NSDate date]];
which you can then convert with
CFAbsoluteTime cfMidnight = [midnight timeIntervalSinceReferenceDate];

How do I calculating the difference between two dates in Objective-C?

I'm working through a challenge in Objective-C Programming, The Big Nerd Ranch Guide, and I'm a little flummoxed by one of the challenges.
Use two instances of NSDate to figure out how many seconds you have been alive. Hint: here is how you create a new date object from the year, month, etc.:
So I need to the difference between now and my date of birth in seconds. Sounds good. Then the hint shows up:
#autoreleasepool {
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setYear:1981];
[comps setMonth:7];
[comps setDay:12];
[comps setHour:1];
[comps setMinute:55];
[comps setSecond:33];
NSCalendar *g = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *dateOfBirth = [g dateFromComponents:comps];
The first issue is I don't understand what *g is meant to be. I know it's a pointer to an NSCalendar object. But why do we need it? And what is g meant to stand for?
The sample code then uses the g variable to grab a date. In another language, this would be as easy as DateDiff(dateOne, dateTwo, interval). I'm not clear on why the Calendar object is necessary in the first place, and why we have to create date components to feed the object.
This is all new to me, and I've worked with dynamic languages in the past. So a "dummies" like explanation would be great!
The sample code then uses the g variable to grab a date. In another language, this would be as easy as DateDiff(dateOne, dateTwo, interval). I'm not clear on why the Calendar object is necessary in the first place, and why we have to create date components to feed the object.
I'm not an Objective-C programmer, but I know a bit about date/time APIs.
In order to specify your birth date/time, you're giving a year of 1981, a month of 7 etc. What does a year of 1981 mean? To you, it may mean about 31 years ago... but to someone using a different calendar system, it could mean something entirely different. Converting from "year/month/day etc" to "point in time" is a bit like converting from a string to an integer: does "10" mean ten, or sixteen? It all depends on your frame of reference (the base, in this case - the calendar system in the date case).
The calendar - initialized as a Gregorian calendar - takes those date components and is able to give you back an NSDate which is a sort of "absolute" value in time.
As for computing the difference between two NSDate values - I suspect there's a member which gives you something like "seconds since the Unix epoch" (or possible milliseconds). So take that from both dates (your birth and "now"), subtract one from the other, and you'll get the elapsed number of seconds (or milliseconds) between the two.
EDIT: In fact, the timeIntervalSinceNow function is probably the one you want, once you've got your birth date.
You can do it this way
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setYear:1981];
[comps setMonth:7];
[comps setDay:12];
[comps setHour:1];
[comps setMinute:55];
[comps setSecond:33];
NSDate *dateOfBirth = [[NSCalendar currentCalendar] dateFromComponents:comps];
NSTimeInterval timeGap=[[NSDate new] timeIntervalSinceDate:dateOfBirth ];

In Objective-C, to get the current hour and minute as integers, we need to use NSDateComponents and NSCalendar?

I'd like to get the current hour and minute as integers. So if right now is 3:16am, I'd like to get the two integers: 3 and 16.
But it looks like [NSDate date] will give the number of seconds since 1970, or it can give a string of the current time representation, but there is no easy way to get them as integers?
I see a post in Getting current time, but it involved NSDateComponents and NSCalendar? That's way too complicated... all that was need is something like
NSDate *date = [NSDate date];
int hour = [date getHour]; // which is not possible
Is there a simpler way than using 3 classes NSDate, NSDateComponents, and NSCalendar to get the current hour as an integer, or typically, in Objective-C, would we typically still use C language's localtime and tm to get the hour as an integer?
How you interpret the seconds since 1970 depends on the calendar that you are using. There is simply no other option. Fortunately it is not that difficult to set up. See the 'Data and Time Programming Guide' for lots of examples. In your case:
// Assume you have a 'date'
NSCalendar *gregorianCal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComps = [gregorianCal components: (NSHourCalendarUnit | NSMinuteCalendarUnit)
fromDate: date];
// Then use it
[dateComps minute];
[dateComps hour];
So it really isn't that complicated.
Also note that you could create a 'Class Category' to encapsulate this as:
#interface NSDate (MyGregorianDateComponents)
- (NSInteger) getGregorianHour;
- (NSInteger) getGregorianMinute;
#end
NSDate just holds the time that has passed since a certain reference date, to get more meaningful numbers out of this (eg. after taking care of DST, leap years and all the other stupid time stuff), you have to use NSDateComponents with the appropriate NSCalendar.
My class can help.
https://github.com/TjeerdVurig/Vurig-Calendar/blob/master/Vurig%20Calendar/NSDate%2Bconvenience.m
I'm sure you can figure out the minute part :)

How do I Increment an NSDate object in Objective-C

I want to take the next day by giving the current date
The code i used as follows
+(NSDate *)getForDays:(int)days fromDate:(NSDate *) date {
NSTimeInterval secondsPerDay = 24 * 60 * 60 * days;
return [date addTimeInterval:secondsPerDay];
}
this works fine but when the daylight saving enabled this leads to errors. How can I make this work when daylight saving is enabled.
As you have found, what you have now is pretty error-prone. Not only can it trip up over a daylight savings change, but also what if your user has a non-gregorian calendar? Then, days are not 24 hours long.
Instead, use NSCalendar and NSDateComponents which were exactly designed for this:
+ (NSDate *)getForDays:(int)days fromDate:(NSDate *)date
{
NSDateComponents *components= [[NSDateComponents alloc] init];
[components setDay:days];
NSCalendar *calendar = [NSCalendar currentCalendar];
return [calendar dateByAddingComponents:components toDate:date options:0];
}
Use NSCalendar to perform calculations like this. Not only is it more likely to work, but your code will be clearer.
I've no idea what language or system you're using here, but my advice would be to perform all of your calculations using time as UTC and only use local time when you come to display it.
Most operating systems and languages will factor in timzone and daylight saving on the conversion of UTC to local time.