How can I set only time in NSDate variable? - ios

I have NSDate variable and would like to change only time (date shouldn't be changed). Is it possible ?
Eg: user pick date interval in DatePicker date (If it's start date I would like to set time as 00:00:00, if it's end date, I set time as 23:59:59)
Thanks all for your help.
Regards, Alex.

You'll want to use NSDateComponents.
NSDate *oldDate = datePicker.date; // Or however you get it.
unsigned unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *comps = [calendar components:unitFlags fromDate:oldDate];
comps.hour = 23;
comps.minute = 59;
comps.second = 59;
NSDate *newDate = [calendar dateFromComponents:comps];

The NSDate object cannot be changed.
You can create a new NSDate object from it. Take a look at the - (id)dateByAddingTimeInterval:(NSTimeInterval)seconds method.
NSDate *newDate = [endDate dateByAddingTimeInterval:24.0f * 60.0f * 60.0f - 1.0f];

When I only need to track the time, I don't use NSDate or NSTimeInterval. Instead I use an NSinteger and store the "military" time, ie 0830 = 8:30 AM, 14:15 = 2:15 PM.

Related

How to get current seconds left to complete hour?

I want to get how many seconds are remaining to complete an hour. No matter which what time it is?
if its 05:01:00 then it should give 3540 seconds
and if its 11:58:40 then it gives 80 seconds and so on. I try to find it on google but could not able to find it.
Thanks in advance.
NSCalendar has got methods to do that kind of date math:
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
// find next date where the minutes are zero
NSDate *nextHour = [calendar nextDateAfterDate:now matchingUnit:NSCalendarUnitMinute value:0 options:NSCalendarMatchNextTime];
// get the number of seconds between now and next hour
NSDateComponents *componentsToNextHour = [calendar components:NSCalendarUnitSecond fromDate:now toDate:nextHour options:0];
NSLog(#"%ld", componentsToNextHour.second);
#Vadian's answer is very good. (voted)
It requires iOS 8 or later however.
There are other ways you could do this using NSCalendar and NSDateComponents that would work with older OS versions.
You could use componentsFromDate to get the month, day, year, and hour from the current date, then increment the hour value and use the NSCalendar method dateFromComponents: to convert your to adjusted components back to a date.
NSDate *date1 = [NSDate dateWithString:#"2010-01-01 00:00:00 +0000"];
NSDate *date2 = [NSDate dateWithString:#"2010-02-03 00:00:00 +0000"];
NSTimeInterval secondsBetween = [date2 timeIntervalSinceDate:date1];
Fill in with the correct times and dates to get the difference in seconds
Edit: An alternative method is to work out the currenthour and return as an integer. Then add one to the NSInteger returned as below (you will have to make sure to handle the case where it is after midnight though!)
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:[NSDate date]];
NSInteger currentHour = [components hour];

NSDate created from NSDateComponents incorrect?

I created an NSDate by dateFromComponents, using NSCalendar with NSGregorianCalendar identifier, here's the strange part:
The date get incorrect if it's before a certain point in time before 1900/12/31
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [[NSDateComponents alloc] init];
components.year = 1900; components.month = 12; components.day = 31;
NSDate *date = [calendar dateFromComponents:components];
components.year = 1901; components.month = 1; components.day = 1;
NSDate *date2 = [calendar dateFromComponents:components];
NSLog(#"%#",calendar.timeZone.description);
NSLog(#"%#",date);
NSLog(#"%#",date2);
The log will be:
2016-05-25 14:58:21.014 date[79754:2192157] Asia/Shanghai (GMT+8) offset 28800
2016-05-25 14:58:21.015 date[79754:2192157] 1900-12-30 15:54:17 +0000
2016-05-25 14:58:21.015 date[79754:2192157] 1900-12-31 16:00:00 +0000
As you can see, there is a 5 minutes gap during the day.
However, if I set the timeZone by [NSTimeZone timeZoneForSecondsFromGMT:], even with the same seconds deviation - 28800, it will be normal.
What is the cause of this?
No, the date isn't incorrect. Instead, the NSCalendar code knows things about calendars that you wouldn't dream about, like calendars changing their time offsets at some points in time in the past.
You asked for the Asia/Shanghai calendar to convert two dates, one on the day before they changed their time zone, one on the day after they changed their time zone, and both times are converted correctly. That night everyone in Shanghai had to adjust their watches.
Interesting question. What you are seeing is the effects of a time zone change from Local Mean Time to China Standard Time on 01-01-1901 when the clocks were turned back 05m43s.
More details here.
Try this!!
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setYear:1987];
[components setMonth:3];
[components setDay:17];
[components setHour:14];
[components setMinute:20];
[components setSecond:0];
NSDate *date = [calendar dateFromComponents:components];
Hope this Help:)

iOS) value of timeIntervalSince70 is fixed when i approach at the level of second

I want to update label that shows time left between 2 nsdates everysecond.
my code is below :
NSDate *nowDate = [NSDate date];
double diff = [campaignDate timeIntervalSince1970] - [nowDate timeIntervalSince1970];
int diff_day = diff/60/60/24 - 1;
int diff_hour = ((int)diff/60/60)%24;
int diff_min = ((int)diff/60)%60;
int diff_sec = ((int)diff/60/60)%60;
When i logged diff_sec , it always shows me 49
day,hour and min value is printed in working order
why does that diff_sec make a problem? is there any solution ?
I think you should use NSDateComponents to get the number of days/hours/minutes/seconds between two days.
Then you can get the remaing time like this:
NSDate *fromDate = [NSDate date];
NSDate *toDate = [NSDate dateWithTimeIntervalSinceNow:12345];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *difference = [calendar components:NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:fromDate toDate:toDate options:0];
NSLog(#"Event in %# days, %#:%#:%#", #(difference.day), #(difference.hour), #(difference.minute), #(difference.second));
Use NSCalendar
NSDate *dateA;
NSDate *dateB;
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
fromDate:dateA
toDate:dateB
options:0];
NSLog(#"Difference in date components: %i/%i/%i", components.day, components.month, components.year);
The error is in calculating diff_sec, the divisions by 60 are incorrect because diff is already in seconds.
Incorrect code:
int diff_sec = ((int)diff/60/60)%60;
Correct code
int diff_sec = ((int)diff)%60;

Date Formatting is Weird

I have a date string that looks like this:
1391640679661
When I use this code:
NSString *seconds = #"1391640679661";
NSDate *date = [NSDate dateWithTimeIntervalSince1970:[seconds doubleValue]];
I end up with this:
46069-05-03 07:27:41 +0000
So what's happening here? Is this a particular date format that I'm not accounting for? Or am I doing something else wrong?
Apple's own api will do all the hard work for you to format components as per your need.
If you want to get individual components as well you can apply below approach.
NSTimeInterval theTimeInterval = 1391640679661;
// Get the system calendar
NSCalendar *sysCalendar = [NSCalendar currentCalendar];
// Create the NSDates
NSDate *date1 = [[NSDate alloc] init];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:theTimeInterval sinceDate:date1];
// Get conversion to months, days, hours, minutes
unsigned int unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;
NSDateComponents *conversionInfo = [sysCalendar components:unitFlags fromDate:date1 toDate:date2 options:0];
NSLog(#"Conversion: %dmin %dhours %ddays %dmoths",[conversionInfo minute], [conversionInfo hour], [conversionInfo day], [conversionInfo month]);
To convert a timestamp string into NSDate, you need to divid the timestamp double value to 1000, and then call dateWithTimeIntervalSince1970:
NSString *timestamp = #"1391640679661";
double seconds = [timestamp doubleValue]/1000.0;
NSDate *date = [NSDate dateWithTimeIntervalSince1970:seconds];
The result is:
2014-02-05 22:51:19 +0000

Possible to compare NSDate objects without using calendar components?

I'm looking to compare NSDate objects based on the day only (ignoring time). Instead of converting the time to 0:00:00, or using NSDateComponent like most solutions (ex. Comparing two NSDates and ignoring the time component)
Does anyone see an issue with converting the date to an int representing the number of days since 1970 with the timeIntervalSince1970 method?
return (int)([date timeIntervalSince1970]/(SECONDS_PER_DAY));
Yes, absolutely. There are an endless number of pitfalls with date math. Use NSDateComponents; they’re not hard.
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *date1Components = [cal components:NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date1];
NSDateComponents *date2Components = [cal components:NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date2];
NSComparisonResult comparison = [[cal dateFromComponents:date1Components] compare:[cal dateFromComponents:date2Components];
Here's a way to convert an NSDate to an NSTimeInterval that represents midnight of the original date without using NSCalendar. Doing this with two NSDate objects would let you compare the two dates without regard to time.
NSDate *now = [NSDate date]; // Your original date with time
NSTimeInterval interval = [now timeIntervalSince1970]; // the full interval
NSDateFormatter *form = [[NSDateFormatter alloc] init];
[form setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; // Zulu time
[form setDateFormat:#"A"]; // milliseconds since midnight
NSString *secondsStr = [form stringFromDate:now];
NSTimeInterval seconds = [secondsStr integerValue] / 1000.0; // seconds since midnight
NSTimeInterval justDate = interval - seconds; // interval for date at midnight (Zulu time)
// For testing purposes
NSDate *nowDate = [NSDate dateWithTimeIntervalSince1970:justDate];
NSLog(#"now = %#, interval = %f", now, interval);
NSLog(#"seconds = %#", secondsStr);
NSLog(#"justDate = %f, nowDate = %#", justDate, nowDate);
This may or may not be better than using NSCalendar as shown in Noah's answer.
You must definitely not simply divide by SECONDS_PER_DAY. That will simply be wrong.
NSCalendar.currentCalendar().compareDate(date1, toDate: date2, toUnitGranularity: .Day)
Returns NSComparisonResult
Here is what apple talks about it

Resources