Date selected from UIDatePicker is different from the date being saved - ios

This is how I setup my datePicker
self.datePicker = [[UIDatePicker alloc] init];
self.datePicker.timeZone = [NSTimeZone localTimeZone];
This is how I save the date that I selected
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeZone:[NSTimeZone localTimeZone]];
dateToSave = [formatter dateFromString:self.dateTextField.text];
NSLog(#"date saved = %#", dateToSave);
If I select Nov 18 2013 from the date picker, the NSLog shows
date saved = 2013-11-17 16:00:00 +0000
However, somewhere in my code, I need to get the difference in days between today's date and the date that I selected in the datepicker.
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSDayCalendarUnit fromDate:[NSDate date] toDate:dateSaved options:0];
NSLog(#"number of days => %i", [dateComponents day]);
Today is Nov 10. The date I saved is Nov 18. But the number of days difference is 7, instead of 8.

Your time zone is -8. 2013-11-17 16:00:00 +0000 equals to 2013-11-18 00:00:00 -0800.
Use [NSTimeZone timeZoneForSecondsFromGMT:0] instead of [NSTimeZone localTimeZone]

(This answer refers to the updated question about calculating the number of days
between two dates.)
The problem is that [NSDate date] is the current date+time, not the start of the current day. For example, if
[NSDate date] = "2013-11-10 10:00:00"
dateSaved = "2013-11-18 00:00:00" (both in your *local* timezone)
then the difference between
these two dates is "7 days and 14 hours". Therefore you get 7 as the number of days.
So you have to calculate the start of the current day first:
NSDate *startOfDay;
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit
startDate:&startOfDay
interval:NULL
forDate:[NSDate date]];
and then use it in the calculation of the difference:
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSDayCalendarUnit
fromDate:startOfDay
toDate:dateSaved
options:0];

NSDateFormatter *date_form=[[NSDateFormatter alloc]init];
[date_form setDateFormat:#"dd/MM/yyyy"];
NSDate *seletected_date = [datepicker date];
NSString *dateToSave=[[NSString alloc] initWithFormat:#"%#",[date_form stringFromDate:seletected_date]];
NSLog(#"date saved = %#", dateToSave);
Remove localtimezone

Related

Strange NSDate after changing hour

I want to change hour in NSDate. I did something like this:
NSDate *final = [gregorian dateBySettingUnit:NSCalendarUnitHour value:hour.intValue ofDate:self.dateForNewEvent options:NSCalendarMatchStrictly];
where self.dateForNewEvent = 2018-07-09 07:24:13 +0000
and hour.intValue = 5 and i expect date = 2018-07-09 05:00:00 + 0000 but i got 2018-07-10 03:00:00 UTC. How should I do it to get expected date ?
To change the hours of a specific NSDate, you need to manipulate it via NSDateComponents. Please try below code for the same:
NSDate *now = [NSDate date]; // YOUR DATE INSTANCE
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier: NSCalendarIdentifierGregorian];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond fromDate:now];
[components setHour:5];
NSDate *today5am = [calendar dateFromComponents:components];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
NSLog(#"Date ===>>> %#",[dateFormatter stringFromDate:[NSDate date]]);
Hope this helps!
I think you are mixing NSDate with NSCalendar: NSDate is a point in time, internally represented in UTC. To get the local date/time as it is displayed on a calendar or watch , you use NSCalendar.
So if you are in MEST (UTC+2) and set the time to "5" hours on your calendar, this will be UTC "3" hours.
To get the calendar date/time back, you could use components(_:from:) from NSCalendar.
Just check this code:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
NSDate * dateForNewEvent = [dateFormatter dateFromString: #"2018-07-09T07:24:13+00:00"];
NSLog(#"dateForNewEvent: %#", dateForNewEvent);
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *comps = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear|NSCalendarUnitHour|NSCalendarUnitMinute fromDate:dateForNewEvent];
[comps setHour:5];
NSDate *final = [gregorian dateFromComponents:comps];
NSLog(#"final: %#", final);
Output as expected:
2018-07-09 11:11:43.542 jdoodle[22:22] dateForNewEvent: 2018-07-09 07:24:13 +0000
2018-07-09 11:11:43.542 jdoodle[22:22] final: 2018-07-09 05:24:00 +0000

How to add Date if today is last day of the month.?

I am stuck a problem where i need to create a stepper by 7 day. I code for that but in case of last days of month it will remain continue with same month rather than it should be change in next month as well.
Same case needs to be implemented for the year.
For e.g if today is 30 dec 2016 then by adding 7 day it needs to be change as 7 jan 2017. Thanks in advance.
Try this. Here I have added 7 days from a particular date.
// Enter current date
NSString *currentDate = #"2016-12-30";
// Set number of days to add
int addDaysCount = 7;
// Set date formatter
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
// Convert string to NSDate
NSDate *dateFromString = [dateFormatter dateFromString:currentDate];
// Initialize date component
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setDay:addDaysCount];
// Retrieve date with increased days count
NSDate *newDate = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:dateFromString options:0];
NSLog(#"Current date: %#", [dateFormatter stringFromDate:dateFromString]);
NSLog(#"Updated date: %#", [dateFormatter stringFromDate:newDate]);
NSDate *now = [NSDate date];
NSDate *sevenDaysAgo = [now dateByAddingTimeInterval:+7*24*60*60];
Here add 7 days add to your current date

Adding an amount of hours to NSDate isn't working?

I've spent a good few hours trying to make this work. Here's what I'm trying to do:
Take input from a UITextField in the form HH:mm AM/PM
Convert that string into an NSDate object, and update the month/day/year properties of that NSDate to reflect the curren month/day/year.
Add 4 hours to the time of the NSDate object.
That last bit isn't working. It works for times such as 12:00 PM and 12:30 PM but for times such as 2:30 PM, it will output 4:30 PM rather than 6:30 PM as expected. Here is my code, broken up to reflect those three tasks.
Task 1 - checking to see if the text input was HH:mm AM/PM
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US"]];
[format setTimeZone:[NSTimeZone systemTimeZone]];
[format setDateFormat:#"HH:mm a"];
NSString *dateString = textField.text;
NSLog(#"input datestring: %#", dateString);
NSDate *parsed = [format dateFromString:dateString];
if (parsed) {
NSLog(#"datestring is valid, %#", parsed);
}
Task 2- Updating the m/d/y components of that date to reflect today's.
//gregorian calendar, get the hour and minute components from the input time
NSCalendar *greg = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [greg components: NSCalendarUnitHour | NSCalendarUnitMinute fromDate:parsed];
//get the month/day/year components from the current date
NSDateComponents *comps = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:[NSDate date]];
//set the components of the original date to the month/day/year components of today
[components setYear:comps.year];
[components setDay:comps.day];
[components setMonth:comps.month];
//create the new date.
NSDate* newDate = [greg dateFromComponents:components];
NSLog(#"########### %#", newDate);
Task 3 - Add 4 hours.
int hours = 4 ;
NSString *output;
NSDateComponents *add = [[NSDateComponents alloc] init];
[add setHour:hours];
newDate = [greg dateByAddingComponents:add toDate:newDate options:0];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateStyle:NSDateFormatterShortStyle];
[df setTimeStyle:NSDateFormatterShortStyle];
output = [df stringFromDate:newDate];
NSLog(#"new date: %#", output);
Log:
2015-08-27 16:03:35.672 Del Taco[1960:117431] input datestring: 2:30 pm
2015-08-27 16:03:35.673 Del Taco[1960:117431] datestring is valid, 2000-01-01 20:30:00 +0000
2015-08-27 16:03:35.673 Del Taco[1960:117431] ########### 2015-08-27 19:30:00 +0000
2015-08-27 16:03:35.674 Del Taco[1960:117431] new date: 8/27/15, 4:30 PM
I think I have this figured out. It was my date formatter where I set the format like this:
#"HH:mm a"
I went to Unicode's website to double check that I was doing this right, and ended up changing my format string to:
#"h:mm a"
And things seem to be working out well!

Comparing 2 dates gives me 1 day less in comparison in IOS

I am trying to compare 2 Dates but in i am getting 1 day less
here is a snippet:
NSDateComponents* dateComponents = [[NSDateComponents alloc] init];
[dateComponents setYear: 2014];
[dateComponents setMonth: 1];
[dateComponents setDay: 31];
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDate* otherDay = [calendar dateFromComponents: dateComponents];
NSDate * todaydate= [NSDate date];
if ([otherDay compare:todaydate]>= NSOrderedDescending)
{
NSLog(#"In If other Date= %# & Today = %# ", otherDay,todaydate);
}else
{
NSLog(#"I am in else other date= %# and today = %# ",otherDay, todaydate);
}
The Log i am getting is :
I am in else other date= 2014-01-30 18:30:00 +0000 and today = 2014-01-31 08:34:21 +0000
Why it's showing other date = 30th jan 2014 ?
You need to set timezone of NSDateComponents such like,
[dateComponents setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
Or as trojanfoe's suggestion you can also set timezone of NSCalendar such like,
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
And To exact compare otherDay to todaydate please see answer of Martin R you need to set
NSDate * todaydate;
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&todaydate interval:NULL forDate:[NSDate date]];
From Martin R's answer this is very useful.
There are two different aspects in your question. First,
NSDateComponents* dateComponents = [[NSDateComponents alloc] init];
[dateComponents setYear: 2014];
[dateComponents setMonth: 1];
[dateComponents setDay: 31];
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDate* otherDay = [calendar dateFromComponents: dateComponents];
computes otherDay as "2014-01-31 00:00" (in your time zone), and
NSDate *todaydate = [NSDate date];
computes todaydate as the current point in time, which includes the hours, minutes
and seconds, for example "2014-01-31 13:00:00" (in your time zone). Therefore
[otherDay compare:todaydate]
returns NSOrderedAscending: otherDay is earlier than todaydate!
What you probably want is to compute todaydate as the start of the current day
(today at 00:00). This can be done as
NSDate * todaydate;
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&todaydate interval:NULL forDate:[NSDate date]];
And now [otherDay compare:todaydate] returns NSOrderedSame, as you expected.
The other aspect is the NSLog output. Printing a NSDate with NSLog()
prints the date according to GMT, and "2014-01-31 00:00" in your time zone is
exactly the same time as "2014-01-30 18:30:00 +0000" in GMT.
The output is correct, it just uses GMT instead of your local timezone for display.

NSDate setting the time, not the expected result

I have the following code to set the time on a date to 0 hours, 0 minutes, 0 seconds by using the YEAR, MONTH and DAY components from the date to construct a new one:
NSDate *date = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:date];
NSDate *newDate = [gregorian dateFromComponents:comps];
NSLog(#"date: %#, newDate: %#", date, newDate);
The output is:
date: 2012-11-06 11:44:09 +0000, newDate: 2012-11-05 23:00:00 +0000
but I was expecting the new date to be: 2012-11-06 00:00:00 +0000
What's happening that I should know of?
NSLog shows the dates using -[NSDate description] which, in turn, converts the absolute time stored in the NSDate to a string. This conversion is done using UTC as the time zone.
For you case it's probably best to do the date calculations in UTC as well. To do so adjust the calendar object that does the calculations:
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
See this answer for a similar Stack Overflow question.
This should solve your issue with daylight savings:
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setCalendar:[NSCalendar currentCalendar]];
[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSString *string = [formatter stringFromDate:[NSDate date]];

Resources