Discrepancy between SQLite's strftime / julianday and Cocoa's timeIntervalSince1970? - objective-c

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSDate *date1 = [dateFormatter dateFromString:#"1213-02-27"];
NSTimeInterval nsdateResult = [date1 timeIntervalSince1970];
NSTimeInterval sqliteResult = -23883638400;
GHAssertEquals(sqliteResult, nsdateResult, #"sqlite and nsdate should agree");
The expected number is what SQLite tells me should be the result, but this test fails since Cocoa tells me -23883033600 instead of -23883638400...i.e. 4 days later!
What gives? Am I doing something wrong or is either SQLite or Cocoa wrong?
Edit
Just checked the math and it seems Cocoa is giving me a wrong value: according to Wolfram Alpha, there are 276431 days between 2/27/1213 and 1/1/1970. Take this times 24*60*60, and you get the value given by SQLite... so am I doing something wrong or is this some kind of Cocoa bug?
Edit 2
Fvu is right, it has to do with the Gregorian/Julian craziness back in 1582.
NSDate *date1 = [dateFormatter dateFromString:#"1582-10-15"];
NSDate *date2 = [dateFormatter dateFromString:#"1582-10-14"];
NSTimeInterval i = [date2 timeIntervalSinceDate:date1];
Surprisingly, i is 777600, i.e. 10/14 is 9 days LATER than 10/15 because it automatically is viewed as a Julian date whereas 10/15 is viewed as a Gregorian date. So basically what I will need to do is convert any dates before 10/15 from the Julian to the Gregorian calendar.

Your sample date predates the Gregorian calendar so I think some oddities can be expected. However, as at the introduction of the Gregorian calendar the date advanced by 10 days I don't have a bulletproof explanation for the calculated 4 day difference.

Related

NSDate being set to the day before [duplicate]

This question already has answers here:
NSDate Format outputting wrong date
(5 answers)
Closed 7 years ago.
Important update: Of you hover over a NSDATE with your mouse the degugger will convert the NSDate to your local timezone you have set on you Mac, but if you do a NSLOG you will notice that the NSDate is using the timezone that you assigned to the its respective formatter.
If you want to see in the xcode debugger what the NSDate is for the timezone you are working with go to your date/time settings for you Mac OS and change the Timezone to the one you are testing.
I require a NSDate to be created from the date I pass in, but currently it is set to the the day before I pass in:
NSString *dateStr = #"2015-08-09";
NSDateFormatter *myformatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd"];
NSDate *date = [formatter dateFromString:dateStr];
The code above returns: an NSDate set to '2015-08-08 12:00:00 +0000'
I need an NSDate object set to the datStr I pass in.
This perhaps, from this:
Convert NSDate to NSString with NSDateFormatter with TimeZone without GMT Time Modifier
leave the 'z' lowercase for named timezone, i.e. PST and uppercase 'Z' for -0800
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:#"MMMM dd, yyyy (EEEE) HH:mm:ss z Z"];
NSDate *now = [NSDate date];
NSString *nsstr = [format stringFromDate:now];
Also, you date should be more robust, like if you want to pass in the current day that your are passing in and it's one day off, then just add a day. The problem, it seems is that the date is returning the correct date which is the end of the last day, add 1 second or a millisecond and it'll probably be corrected, or just hack attack this and add 1 day to the days you are passing in. Be smart! Sometimes you just have to add 1 day to fix stuff and move on.

Converting NSString to NSDate adds one year in some cases

I have some issues converting an NSString to NSDate since the end of the year. The code have always worked great before, but it suddenly started to behave wierd...
For example 2013-01-05 becomes 2014-01-05 when converted to NSDate.
Since it's a whole year it doesn't feel like it's the timezone spooking.
It's not doing this with dates from 2012.
Does anybody have an idea of what might be wrong?
Code:
NSString *dateString = postInfo.noteDate;
NSString *newDateString = [dateString substringToIndex:10];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"YYYY-MM-dd"];
NSDate *date = [[NSDate alloc] init];
date = [dateFormat dateFromString:newDateString];
newDateString returns 2013-01-05
date returns 2014-01-05
From the docs:
Y 1..n 1997 Year (in "Week of Year" based calendars). Normally the length specifies the padding, but for two letters it also specifies the maximum length. This year designation is used in ISO year-week calendar as defined by ISO 8601, but can be used in non-Gregorian based calendar systems where week date processing is desired. May not always be the same value as calendar year.
y 1..n 1996 Year. Normally the length specifies the padding, but for two letters it also specifies the maximum length.
So you want 'yyyy'
This 'bug' is also discussed in the fantastic WWDC 2011 Video "Session 117 - Performing Calendar Calculations", a must-see for any iOS/Cocoa-Developer.
Wikipedia article on ISO 8601
NSDate *date = [[NSDate alloc] init];
date = [dateFormat dateFromString:newDateString];
You create a NSDate and than you create another and overwrite the first one. Just do
NSDate *date = [dateFormat dateFromString:newDateString];
use yyyy for year not YYYY, which gives week year. see the ISO standard.
Use yyyy in small letters, YYYY is another thing:
Year (in "Week of Year" based calendars). This year designation is used in ISO year-week calendar as defined by ISO 8601, but can be used in non-Gregorian based calendar systems where week date processing is desired. May not always be the same value as calendar year.
see http://www.unicode.org/reports/tr35/tr35-19.html#Date_Format_Patterns
I hope this will helps u. Try this
- (NSDate*) dateFromString:(NSString*)aStr
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"] autorelease]];
[dateFormatter setDateFormat:#"MM/dd/yyyy HH:mm:ss a"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSLog(#"%#", aStr);
NSDate *aDate = [dateFormatter dateFromString:aStr];
[dateFormatter release];
return aDate;
}

NSDate with no time

I have written the following method:
- (NSDate *)stringToDate:(NSString *)dateString
{
// Convert string to date
NSDateFormatter * dateFormat = [[NSDateFormatter alloc] init];
NSTimeZone *tz = [NSTimeZone timeZoneWithName:#"America/New_York"];
[dateFormat setDateFormat:#"M/d/yyyy HH:mm:ss"];
[dateFormat setTimeZone:tz];
NSDate * date = [dateFormat dateFromString:[NSString stringWithFormat:#"%# 00:00:00", dateString]];
return dateOnly;
}
When I call this with just a date such as 11/1/2013 or 11/13/2013 I get 2013-11-01 04:00:00 +0000 and 2013-11-13 05:00:00 +0000.
If I set a breakpoint on the return the date appears right, but if I break at in the calling function after this call, the date is returned with the time.
How come my time is not always 0. Can anyway tell me what is wrong in my function?
Thank you
UPDATE:
The input string is as follows: 11/1/2013 and 11/13/2013
NSDate is a point in time. It will always have a time component.
And if not printed as a string form a NSDateFormatter, the Date and time will always be the one of UTC/GMT.
The format and the date string must fit.
NSString *dateString = #"11/1/2013";
[dateFormat setDateFormat:#"M/d/yyyy"];
The one hour apart comes from the Daylight saving time. Till November, 3rd 2013 New York has Summer time. http://www.timeanddate.com/worldclock/clockchange.html?n=179
Ok, so can I ignore that? I am trying to compare NSDates when I do my comparison fails because of the time part
You should create dates with with a time during the day — i.e. noon — to be save of DST mess and compare those. Use NSComponents for that.
A must-see for any iOS/Cocoa-Developer: the fantastic WWDC 2011 Video "Session 117 - Performing Calendar Calculations".

NSDate Output incorrectly [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Getting date from [NSDate date] off by a few hours
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"M-d-yyyy H:mm"];
NSDate *start= [dateFormatter dateFromString:#"10-24-2012 12:15"];
NSDate *end = [dateFormatter dateFromString:#"10-24-2012 15:30"];
When I print out
NSLog(#"------main_event start %#", start);
NSLog(#"-----main_event end %#", end);
The result is
---main_event start 2012-10-24 19:15:00 +0000
---main_event end 2012-10-24 22:30:00 +0000
Now, it looks like the time added 7 hours automatically, 12:15 becomes 19:15, and 15:30 becomes 22:30.
Why?
because the timezone, where your device is located, is UTC-7.
The output is in UTC (hence the +0000), as a single NSDate will always print out it's time in UTC.
If you use an NSDateFormatter to output the date, it will take your locale in account. See my answer here: NSDate date method returns wrong result
These are correct results. When you use NSLog to output an NSDate object, it displays in GMT. The parsing was done in your local timezone. NSDate objects are alway in GMT. If you want to print the NSDate object in your local timezone then you need an NSDateFormatter to print the date.

How to determine if an NSTimeInterval occurred during an arbitrary NSDate?

I have an NSTimeInterval, and I'd like to know whether that timestamp falls between the start and end of a date. Basically I need to be able to do something like:
NSDate *today = [NSDate date];
NSTimeInterval myInterval = someInterval;
[date returnYesIfFallsThisDate:myInterval];
Is there a straight forward method to figure out if my NSTimeInterval falls on the same day as an NSDate object?
Thanks all.
An NSTimeInterval is just a number of seconds. To compare it to an NSDate, you need to interpret the time interval relative to some reference point, then create an NSDate with the result, then compare the two NSDates.
There are two standard reference dates: 2001-01-01 and 1970-01-01 (the latter being “UNIX time”). If neither of those is the correct reference date, use NSCalendar to create an NSDate for the correct reference date, then create your NSDate of interest relative to that.
Now for the comparison.
If all you care about is the date on the calendar, then you'll create the NSDate, then use an NSCalendar to get NSDateComponents for the date. Specifically, you'll get the year, month, and day-of-the-month, then compare those.
There's no need to worry about “start” and “end” times; in fact, if you only care about the date on the calendar, you can ignore the time-of-day entirely.
Keep in mind that NSDate doesn't represent a "day" in any form, just a point in time. You'll have to do a little work with NSDateComponents, converted using an NSCalendar (typically the user's default calendar) to figure out the start and end NSDate values, and compare use those to compare your time interval to.
I would start by taking the NSDate that falls within your day, and converting it to an NSDateComponents, but without hours, minutes or seconds. Here's a quick (untested) example to help you get started:
NSDateComponents *comps = [[NSCalendar currentCalendar] components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:[NSDate date]];
NSDateComponents *day = [[[NSDateComponents alloc] init] autorelease];
[day setDay:1];
NSDate *start = [[NSCalendar currentCalendar] dateFromComponents:comps];
NSDate *end = [[NSCalendar currentCalendar] dateByAddingComponents:day toDate:start options:0];
Then you can compare the time interval as suggested by Mr. Jalkut (or another method, NSDate can work with NSTimeIntervals in a few different ways). I would definitely spend some time looking over NSCalendar and NSDateComponents in the docs though, you might find a better method than what I'm suggesting for what you need to do.
Is it just me or does the OP seem to think that a NSTimeInterval is a representation of an interval in time from A to B? I.e. an absolute distance (in seconds) from Date A to Date B.
The original question needs to be repose to state that you need to find it based on the reference date. Something like this:
NSDate *refDate = someReferenceDate;
NSTimeInterval interval = someInterval;
NSDate *today = [NSDate date];
BOOL isInRange = false;
isInRange = [today isInterval:interval inRangeFromReference:refDate];
Then that method would use some (or parts of all) of the startegies that Damiel, Peter and Marc mention above.
Conceptually you want two dates that constitute the "start" and "end" of the target date in question. Then you can test the time interval directly against the respective time intervals of those dates.
For instance, if I live in San Francisco, then I want the "start" to be 12AM pacific time, and the end to be 11:59:59.99999 PM pacific time.
Once you've figured out what time zones/etc you want to consider as the start and end points, you can just use the time intervals to do the test:
if ((myInterval >= [earlyMorningDate timeIntervalSinceReferenceDate]) &&
(myInterval <= [lateEveningDate timeIntervalSinceReferenceDate]))
{
NSLog(#"Whoo hoo - it's the right date!");
}