Please help me with non-obvious code behavior
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
dateComponents.hour = 15;
dateComponents.minute = 20;
dateComponents.calendar = calendar;
NSDate * endDate = [calendar dateFromComponents:dateComponents];
EndDate is 0001-01-01 12:49:43 +0000. Why?
Hours value may be incorrect due to the difference in the time zones. Why such strange minutes and seconds value?
Regards.
If we are just considering the following code snippet
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setCalendar:calendar];
NSDate *date = [calendar dateFromComponents:components];
date = 0000-12-31 23:06:32 +0000, because:
Calendars encapsulate information about systems of reckoning time in
which the beginning, length, and divisions of a year are defined.
[...]
When there are insufficient components provided to completely specify an absolute time, a calendar uses default values of its choice.
Apple Documentation
and
An NSDateComponents object is meaningless in itself; you need to know what calendar it is interpreted against, and you need to know whether the values are absolute values of the units, or quantities of the units. Apple Documentation
Actually, everything is fine and exactly what the documentation says.
Related
This question already has answers here:
Objective C - get the following day from today (tomorrow)
(3 answers)
Closed 9 years ago.
I have an app in I need the date of the next day though I have looked around and found nothing on how to do this.
Edit:
Found the answer at last. Here is what I did:
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
NSDate *startOfToday;
NSDate *tomorrow;
NSTimeInterval interval;
[cal rangeOfUnit:NSDayCalendarUnit
startDate:&startOfToday
interval:&interval
forDate:now];
tomorrow = [startOfToday dateByAddingTimeInterval:interval];
NSDateFormatter* df = [[NSDateFormatter alloc]init];
[df setDateFormat:#"MM-dd-yy"];
tommorowDate = [df stringFromDate:tomorrow];
Though this was all thanks to one of the answers
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
NSDate *startOfToday;
NSDate *tomorrow;
NSTimeInterval interval;
[cal rangeOfUnit:NSDayCalendarUnit
startDate:&startOfToday
interval:&interval // interval will hold the duration of the day. DST-aware.
forDate:now];
tomorrow = [startOfToday dateByAddingTimeInterval:interval];
tomorrow now holds an NSDate object representing 0:00 of the next day in the device's timezone.
NSDate is representing a moment in time. To display it without time portion, use a NSDateFormatter. There are plenty of examples around here.
I need to filter search results based on values that were added yesterday. I have seen plenty on finding yesterday using:
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:[[NSDate alloc] init]];
[components setHour:-24];
[components setMinute:0];
[components setSecond:0];
NSDate *yesterday = [cal dateByAddingComponents:components toDate:[NSDate date] options:0];
predicate = [NSPredicate predicateWithFormat:#"created_at >= %#", yesterday];
But this finds 24 hours since this exact moment in time. I need to filter yesterday as 12:01am-12:00pm. So the actual 24 hour period that was yesterday.
I'm guessing that I need to do something along the lines of:
1. Take the current date
2. Find the time from the current date to 12:01am of the same day
3. Then subtract 24 hours from that date
I feel confident I can do #3 (and #1 of course), but I'm not sure how to go about #2. I maybe over thinking it but I can't seem to grasp how to say: "Ok, it's 8:03am, I need to remove 8 hours and 2 minutes which will put me at 12:01am".
Start with some date of today, for example "now":
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
Subtract one day to get some date of yesterday:
NSDateComponents *minusOneDay = [[NSDateComponents alloc] init];
[oneDay setDay:-1];
NSDate *nowMinusOneDay = [cal dateByAddingComponents:minusOneDay toDate:now options:0];
Compute start and end date of the "day calendar unit" that contains yesterday's date:
NSDate *startOfYesterday;
NSTimeInterval lengthOfYesterday;
[cal rangeOfUnit:NSDayCalendarUnit startDate:&startOfYesterday interval:&lengthOfYesterday forDate:nowMinusOneDay];
NSDate *endOfYesterday = [startOfYesterday dateByAddingTimeInterval:lengthOfYesterday];
This should work even if a daylight savings time transition occurs between today and yesterday.
Generally one should avoid to use explicit time intervals such as "24 hours", because not every day has that length.
I would like to calculate the number of months and days between two NSDates. I have the number of days calculating correctly, but how can convert that to months and remainder days?
This is what I'm using to calculate total number of days, which is working correctly.
- (NSInteger) numberOfDaysUntil {
NSDate *fromDate;
NSDate *toDate;
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&fromDate interval:NULL forDate:[self dateOnly:[NSDate date]]];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&toDate interval:NULL forDate:[self dateOnly:self]];
NSDateComponents *difference = [calendar components:NSDayCalendarUnit fromDate:fromDate toDate:toDate options:0];
return [difference day];
}
As Hot Licks correctly said, you can't convert a number of days to months/days in most calendars.
However, the NSCalendar method components:fromDate:toDate:options: can do this calculation if you agree with Apple's implementation. From the documentation:
The result is lossy if there is not a small enough unit requested to hold the full precision of the difference. Some operations can be ambiguous, and the behavior of the computation is calendar-specific, but generally larger components will be computed before smaller components; for example, in the Gregorian calendar a result might be 1 month and 5 days instead of, for example, 0 months and 35 days.
The discussion in the documentation even includes sample code for exactly your problem:
NSDate *startDate = ...;
NSDate *endDate = ...;
unsigned int unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *comps = [gregorian components:unitFlags fromDate:startDate toDate:endDate options:0];
int months = [comps month];
int days = [comps day];
I'm making my custom calendar view for an app for the European market. In a function I should get number of day of week... I do, but it returns the number of the day of week starting with Sunday. How should I hardcode returning this number starting with Monday?
Thanks
Here is what I have so far:
-(int)getWeekDay:(NSDate*)date_
{
NSLocale *frLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"fr_FR"];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setLocale:frLocale];
NSDateComponents *comps = [gregorian components:NSWeekdayCalendarUnit fromDate:date_];
int weekday = [comps weekday];
NSLog(#"Week day is %i", weekday);
return weekday;
}
You should use [NSCalendar setFirstWeekday:] to do this.
The best way to do this would be to use [NSCalendar setFirstWeekday:], as Joshua said in his answer.
Otherwise, you can do integer arithmetic. Vova's method is straightforward:
if (weekday>1)
weekday--;
else
weekday=7;
This one below works too, although it's a bit confusing:
int europeanWeekday = ((weekday + 5) % 7) + 1;
How to get date for every year of july month using NSDate .I am getting the data from the web service which I called. And now I am showing the full data in the graph which is very huge. The data which we are having is from 1998 to till now. so I want to show the data only every year of july. For this I need the help. Can anyone help me?
Well, NSDate is a specific date and time and not just month and year. If you're fine with something like every July 1 at 12 AM (or whatever time/day) then you can use NSDateComponents to set the components of the date.
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setMonth:5];
[comps setYear:2004];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [gregorian dateFromComponents:comps];
[comps release];
[gregorian release];
This is straight from the Apple documentation. If you want to get the next year, then you can use dateByAddingTimeInterval: on your NSDate to return a new date (or you can use the original NSDateComponents and setYear: in a loop).