I believe that NSDate/NSCalendar has a bug or two on iOS 4.2.
[[NSDate date] description]
always prints using GMT, i.e. the local time zone setting is ignored. Has been reported previously, but is included to hopefully better explain the output below.
[calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:dateA]
Doesn't always return the correct value, while this does:
[calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:dateA]
Based on a previous post, I created some test code:
NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss Z"];
NSDate* dateA = [formatter dateFromString:#"2010-12-29 11:11:17 +1100"];
NSDate* dateB = [formatter dateFromString:#"2010-12-29 10:11:17 +1100"];
NSDate* dateC = [formatter dateFromString:#"2010-12-27 11:11:17 +1100"];
NSDate* dateD = [formatter dateFromString:#"2010-12-27 10:11:17 +1100"];
NSLog(#"dateA=%#, %#", dateA, [formatter stringFromDate:dateA]);
NSLog(#"dateB=%#, %#", dateB, [formatter stringFromDate:dateB]);
NSLog(#"dateC=%#, %#", dateC, [formatter stringFromDate:dateC]);
NSLog(#"dateD=%#, %#", dateD, [formatter stringFromDate:dateD]);
NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSLog(#"timezone=%#", [calendar timeZone]);
NSLog(#"A day inUnit:Year=%d", [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:dateA]);
NSLog(#"B day inUnit:Year=%d", [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:dateB]);
NSLog(#"C day inUnit:Year=%d", [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:dateC]);
NSLog(#"D day inUnit:Year=%d", [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:dateD]);
NSLog(#"A day inUnit:Era =%d", [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:dateA]);
NSLog(#"B day inUnit:Era =%d", [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:dateB]);
NSLog(#"C day inUnit:Era =%d", [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:dateC]);
NSLog(#"D day inUnit:Era =%d", [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:dateD]);
and got this output:
[33920:207] dateA=2010-12-29 00:11:17 +0000, 2010-12-29 11:11:17 +1100
[33920:207] dateB=2010-12-28 23:11:17 +0000, 2010-12-29 10:11:17 +1100
[33920:207] dateC=2010-12-27 00:11:17 +0000, 2010-12-27 11:11:17 +1100
[33920:207] dateD=2010-12-26 23:11:17 +0000, 2010-12-27 10:11:17 +1100
[33920:207] timezone=Australia/Hobart (GMT+11:00) offset 39600 (Daylight)
[33920:207] A day inUnit:Year=363
[33920:207] B day inUnit:Year=363
[33920:207] C day inUnit:Year=361
[33920:207] D day inUnit:Year=361
[33920:207] A day inUnit:Era =734135
[33920:207] B day inUnit:Era =734134
[33920:207] C day inUnit:Era =734133
[33920:207] D day inUnit:Era =734132
I found that by offsetting the date by the time zone offset I get a consistent ordinality.
Taking dateC and dateD from your code:
NSTimeZone *tz = [[NSCalendar autoupdatingCurrentCalendar] timeZone];
NSTimeInterval offset = [tz secondsFromGMT];
NSDate* dateC = [formatter dateFromString:#"2010-12-27 11:11:17 +1100"];
NSDate* dateD = [formatter dateFromString:#"2010-12-27 10:11:17 +1100"];
NSLog(#"dateC=%#, %#", dateC, [formatter stringFromDate:dateC]);
NSLog(#"dateD=%#, %#", dateD, [formatter stringFromDate:dateD]);
dateC = [dateC dateByAddingTimeInterval: offset];
dateD = [dateD dateByAddingTimeInterval: offset];
NSLog(#"C day inUnit:Era =%d", [calendar ordinalityOfUnit:NSDayCalendarUnitinUnit:NSEraCalendarUnit forDate: dateC]);
NSLog(#"D day inUnit:Era =%d", [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate: dateD]);
yields the same ordinality for both.
I am seeing the same issue. Doesn't look like the ordinalityOfUnit respects the timezone
Related
How can I get the seconds that have passed since 1980-01-01 00:00:00 +1100 using NSTimeInterval?
// I need the function to use something like and am having an issue
NSDate *aDate = (NSDate*)#"1980-01-01 00:00:00 +1100";
NSDate *seconds = [NSDate dateWithTimeInterval:60*60*24 sinceDate:aDate];
NSLog(#"seconds since Jan 1980 %#",seconds);
// I am trying to replace the following
//NSTimeInterval dateinterval = [[NSDate date] timeIntervalSince1970];
NSTimeInterval dateinterval = seconds;
NSDate only retrieves the GMT at +0000 which is not helpful in real world applications. Local dates are mandatory.
Is this too hard or can it not be done this way?
You are initializing your NSDate object wrong. You can't directly cast an NSString as an NSDate, you need to use NSDateFormatter:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"yyyy-MM-dd HH:mm:ss z";
NSDate *aDate = [formatter dateFromString:#"1980-01-01 00:00:00 +1100"];
NSDate *now = [NSDate date];
NSTimeInterval seconds = [now timeIntervalSinceDate:aDate];
To format the date for a different time zone, use a new NSDateFormatter and set its local and timeZone.
I am using NSDateFormatter to convert a series of dates to a week number within a month.
The date formatting code I am using is yyyyMMW and everything I have read tells me that W will be between 1-5.
But, the 2nd of June 2013 fell on a Sunday (the default start day of the week in the gregorian calendar) and it's week number is reported as 0 even though the start date of the week is calculated correctly:
2013-06-03 14:15:45.611 date=20130531, week=2013055, start of week=20130526
2013-06-03 14:15:45.612 date=20130602, week=2013060, start of week=20130602
2013-06-03 14:15:45.612 date=20130603, week=2013061, start of week=20130602
Some quick and dirty test code to reproduce the log shown above:
NSDateFormatter *dateFormatDaily = [[NSDateFormatter alloc] init];
[dateFormatDaily setDateFormat:#"yyyyMMdd"];
NSDateFormatter *dateFormatterWeekly = [[NSDateFormatter alloc] init];
[dateFormatterWeekly setDateFormat:#"yyyyMMW"];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setFirstWeekday:1]; // default but set here for clarity
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setMonth:5];
[dateComponents setDay:31];
[dateComponents setYear:2013];
NSDate *date_1 = [calendar dateFromComponents:dateComponents];
[dateComponents setMonth:6];
[dateComponents setDay:2];
NSDate *date_2 = [calendar dateFromComponents:dateComponents];
[dateComponents setDay:3];
NSDate *date_3 = [calendar dateFromComponents:dateComponents];
NSArray *datesToTest = #[date_1, date_2, date_3];
for (NSDate *date in datesToTest) {
NSString *weekNo = [dateFormatterWeekly stringFromDate:date];
NSDate *beginningOfWeek = nil;
BOOL rc = [calendar rangeOfUnit:NSWeekCalendarUnit startDate:&beginningOfWeek interval:NULL forDate:date];
if (rc) {
NSLog(#"date=%#, week=%#, start of week=%#", [dateFormatDaily stringFromDate:date], weekNo, [dateFormatDaily stringFromDate:beginningOfWeek]);
} else {
NSLog(#"Could not calculate beginning of week");
}
}
Any ideas? A week number of 0 under any circumstances seems wrong to me.
Thanks
There are various parameters that cause this effect. First of all, you did not set a calendar for the date formatter. If you add
[dateFormatterWeekly setCalendar:calendar];
to your code, then the output will be as you expected:
date=20130531, week=2013055, start of week=20130526
date=20130602, week=2013062, start of week=20130602
date=20130603, week=2013062, start of week=20130602
But in your case, the date formatter uses the current calendar, and therefore has separate parameters firstWeekDay and minimumDaysInFirstWeek. These parameters are locale dependent. If I test this on the iOS Simulator with the "Region Format" set to "German -> Germany", then
[[dateFormatterWeekly calendar] firstWeekday] = 2
[[dateFormatterWeekly calendar] minimumDaysInFirstWeek] = 4
and I assume that you will have similar values, because now I get the same output as you.
Now for the date formatter, the week starts on a Monday, which means that June 2 is in the week starting at May 27. This counts as "week #0" in June, because only one day of this week is in June, but minimumDaysInFirstWeek = 4. The first week in a month that has at least
minimumDaysInFirstWeek days, counts as "week #1".
(I found the relevance of the minimumDaysInFirstWeek parameter here:
http://www.cocoabuilder.com/archive/cocoa/326845-week-of-month-confusion.html)
I want to send local push notification last day of every month 12.00.
I want someone to check if this is the right code since I don't wanna wait a month to see if it works? Thnx!
NSDate *curDate = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *comps = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:curDate];
comps = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:curDate];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
NSDate *fireTime;
[comps setMonth: [comps month] + 1];
[comps setDay: 0];
[comps setHour: 14];
[comps setMinute: 0];
NSDate *lastDayMonth = [calendar dateFromComponents:comps];
NSLog(#"%#", lastDayMonth);
fireTime = lastDayMonth;
localNotif.repeatInterval = NSMonthCalendarUnit;
localNotif.fireDate = fireTime;
localNotif.alertBody = [NSString stringWithFormat: #"working?"];
Well, obviously you should set the Hour as 12 if you want the notification to be fired at 12:00...
Why not try Hours or Days first. If they work, the Month should do as well.
I have the following code:
-(void)setDate:(double)dateInterval {
NSDate *date = [NSDate dateWithTimeIntervalSince1970:(NSTimeInterval)dateInterval];
NSLog(#"NSDate-Result: %#", [date description]);
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeStyle:NSDateFormatterMediumStyle];
[formatter setFormatterBehavior:NSDateFormatterBehavior10_4];
[formatter setDateFormat:#"YYYY-MM-DD HH:mm:SS"];
NSString *dateString = [formatter stringFromDate:date];
NSLog(#"String-Result: %#", dateString);
date_label.text = dateString;
}
in NSDate the Date is correct, but the converted string isn't correct anymore.
Results:
2012-08-03 10:58:40.469 iSkizzenaufmass[4148:c07] NSDate-Result:
2012-08-03 08:08:35 +0000 2012-08-03 10:58:40.471
iSkizzenaufmass[4148:c07] String-Result: 2012-08-216 10:08:48
You have to use yyyy-MM-dd HH:mm:SS instead of -DD (DD is day of the year)
EDIT: changed YYYY to yyyy as YYYY is week based year and could differ from current year (see link below for all opts)
http://unicode.org/reports/tr35/tr35-10.html#Date_Format_Patterns
NSDateFormatter *timeFormat = [[NSDateFormatter alloc] init];
[timeFormat setDateFormat:#"hh:mm a"];
NSDate* sourceDate = [timeFormat dateFromString:#"19/11/2010 12:00 am"];
if(sourceDate==nil)
{
NSLog(#"source date nil");
}
I'm using 24 hour setting in iPhone. After I change to 24 hour setting, datefromstring always return nil. I rechange to 12 hour format, it's working again. Why ?
The locale needs to be set to avoid being affected by the 24-hour setting change.
The format also has to match the input string (which in your example includes the date):
NSDateFormatter *timeFormat = [[NSDateFormatter alloc] init];
NSLocale *locale = [[[NSLocale alloc]
initWithLocaleIdentifier:#"en_US_POSIX"] autorelease];
[timeFormat setLocale:locale];
[timeFormat setDateFormat:#"dd/MM/yyyy hh:mm a"];
NSDate* sourceDate = [timeFormat dateFromString:#"19/11/2010 12:00 am"];
if(sourceDate==nil)
{
NSLog(#"source date nil");
}
See QA1480 for more information.