NSCalendarDate has subsecond precision
NSCalendarDate has subsecond precision
- Subject: NSCalendarDate has subsecond precision
- From: "Jim Thomason" <email@hidden>
- Date: Fri, 15 Aug 2008 16:28:38 -0500
Wow. I just spent about an hour and a half debugging this, since it's
rather nefarious. Now I need to go back to all sorts of existing data
and correct for it, too. :-(
Anyway, I'm just posting to the list as an informational thing just in
case anybody else runs into a similar issue. I wasn't having any luck
with what I was googling for, so I figured another post would be
useful. Personally, I think this constitutes a bug in NSCalendarDate
(since there's no way to specify the submillisecond precision it's
using) and am going to file a bug indicating as such.
First of all, the origin of this. I had a little method that returns
"today at midnight". Basically, I just created an NSCalendarDate
object with [NSCalendarDate date] and subtracted off the current
hours, minutes, and seconds to yield today with time values of
00:00:00. That worked just fine, and for today (for example), I got a
nice value back of: 2008-08-15 00:00:00 -0500.
I encountered a problem today when I hit the case of comparing two
objects both created to be "today at midnight" (got me how I didn't
hit it before). The issue is that NSCalendarDate internally has
subsecond precision, but there doesn't seem to be any way to get or
set that information, other than via timeIntervalSinceDate et. al.
So two different NSCalendarDates created by using this method would
actually have slight subsecond variations in their time, based upon
when the todayAtMidnight method was called.
Solution? I tweaked the method. Instead of subtracting off from the
"now" value, I create a new NSCalendarDate and set the year/month/day
to today's, and leave everything else 0. That has the additional
effect of leaving the subseconds set to 0.
Incidentally, if anybody has a more clever way of creating such a
method, I'd love to hear it. It's my understanding that natural
language strings ("today at midnight") use is strongly discourage, so
I'm trying to avoid it. Or I'll just stick with my new method, since
it works.
Here's a test case to look at. Sample output would include:
kent:~ jim$ ./test
2008-08-15 16:26:30.263 test[96256:10b] 2008-08-15 00:00:00 -0500 <=>
2008-08-15 00:00:00 -0500 == 1 (seconds apart: 0.262046)
kent:~ jim$ ./test
2008-08-15 16:26:30.547 test[96257:10b] 2008-08-15 00:00:00 -0500 <=>
2008-08-15 00:00:00 -0500 == 1 (seconds apart: 0.546184)
kent:~ jim$ ./test
2008-08-15 16:26:30.814 test[96258:10b] 2008-08-15 00:00:00 -0500 <=>
2008-08-15 00:00:00 -0500 == 1 (seconds apart: 0.813310)
That one was sneaky. Hopefully this'll help somebody else.
-Jim......
#import <Foundation/Foundation.h>
#include <stdlib.h>
/*And you can compile it on the command line with: cc -Wall -o test
-framework Foundation DateCompare.m */
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSCalendarDate* today = [NSCalendarDate date];
NSCalendarDate* todayAtMidnight1 = [today
dateByAddingYears:0
months:0
days:0
hours: -[today hourOfDay]
minutes: -[today minuteOfHour]
seconds: -[today secondOfMinute]
];
NSCalendarDate* todayAtMidnight2 = [NSCalendarDate
dateWithYear:[today yearOfCommonEra]
month:[today monthOfYear]
day:[today dayOfMonth]
hour:0 minute:0 second:0 timeZone:[today timeZone]
];
NSLog(@"%@ <=> %@ == %d (seconds apart: %f)",
todayAtMidnight1,
todayAtMidnight2,
[todayAtMidnight1 compare:todayAtMidnight2],
[todayAtMidnight1 timeIntervalSinceDate:todayAtMidnight2]
);
[pool release];
return 0;
} // main
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden