NSDate setting the time, not the expected result - ios

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]];

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

iOS set date to MM//DD/YY 00:00:00

I know there's a few questions already on this but I keep running into the same error regardless of what I do to my code. I am working in the simulator, I have location set to my long/lat. When I try to convert the current date to zero hours, minutes, seconds I always get this result:
2015-07-10 08:53:19.868 xxxxxxxxxxxxxxxxx[2184:7462272] Today at start of day:2015-07-10 04:00:00 +0000
Here's my code:
NSDate* today = [[NSDate alloc] init];
NSCalendar* currentCalendar = [NSCalendar currentCalendar];
NSDateComponents* dateComponents = [currentCalendar components:NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitYear fromDate:today];
NSInteger thisMonth = [dateComponents month];
NSInteger thisDay = [dateComponents day];
NSInteger thisYear = [dateComponents year];
NSDateComponents* dayComponents = [[NSDateComponents alloc] init];
[dayComponents setDay:thisDay];
[dayComponents setMonth:thisMonth];
[dayComponents setYear:thisYear];
NSDate* todayAtMidnight = [currentCalendar dateFromComponents:dayComponents];
NSLog(#"Today at start of day:%#", todayAtMidnight);
Even if add
[dayComponents setHour:0]; the hour still comes out as 4.
What am I doing wrong?
To get the beginning of today you can use
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:[NSDate date]];
[calendar setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
NSLog(#"date %#", [calendar dateFromComponents:components]);
Make sure you have the correct timezone
2015-07-10 04:00:00 +0000 is UTC, not your local timezone.
To display it in your local timezone, use an NSDateFormatter:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"yyyy-MM-dd HH:mm";
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
NSLog([dateFormatter stringFromDate:todayAtMidnight]);
Use NSDateFormatter as follow because system timezone is UTC:
NSDateFormatter * formatter = [[NSDateFormatter alloc] init];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
[formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate * curDate = [formatter dateFromString:[NSDate date]];
Then you'll get 2015-07-10 00:00:00.

Update Countdown Timestamp According to Timezone

Hi I have a countdown timer in my app and I am looking for a way to take my timestamp date and modify it based on the time zone without formatting it. The time stamp is GMT and it looks like this:
theDate = [NSDate dateWithTimeIntervalSince1970:1387929601];
Then I have my countdown formatter here:
-(void)updateCountdownText
{
//Update the Countdown Label
NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
int units = NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *components = [calendar components:units fromDate:[NSDate date] toDate:theDate options:0];
[dateLabel setText:[NSString stringWithFormat:#"%d%c %d%c %d%c %d%c", [components day], 'd', [components hour], 'h', [components minute], 'm', [components second], 's']];
}
Since I'm already formatting the timestamp below all i would like to do is take the GMT timestamp number and convert it according to the local time zone. So I would just like to add the time zone code before the dateWithTimeInterval and then change that number (keeping it a timestamp) according to the time zone. Is this possible? Thanks!
Try this one:
//Timestamp convert to NSDate
double time=[myString doubleValue];//in yourcase mystring=#"1387929601"; mystring is timestamp
NSTimeInterval interval =time ;
NSDate *online = [NSDate dateWithTimeIntervalSince1970:interval];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"hh:mm a dd-MMM-yyyy"];
NSLog(#"Timestamp date is: %#", [dateFormatter stringFromDate:online]);
NSString *mystr=[dateFormatter stringFromDate:online];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [dateFormatter dateFromString:mystr];
value1=([[NSTimeZone localTimeZone] secondsFromGMT]);
value1=value1/3600;
float value123=((value1) * 3600);
NSTimeZone *tz = [NSTimeZone timeZoneForSecondsFromGMT:(value123)]; // for PST
NSDateComponents *dc = [cal components: NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit fromDate:now];
[cal setTimeZone:tz];
NSDate *newDate = [cal dateFromComponents:dc];
NSDateFormatter *dateFormatter1 = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter1 setDateFormat:#"hh:mm a dd-MMM-yyyy"];
NSLog(#"result: %#", [dateFormatter1 stringFromDate:newDate]);
May it will work for you.
happy coding...
Use NSDateFormatter to get correct time zone of your theDate object.
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setTimeZone:[NSTimeZone localTimeZone];
NSTimeZone has a property secondsFromGMT. So you can use [NSTimeZone systemTimeZone].secondsFromGMT; to obtain the difference, add it to your time interval and instantiate the date.
Format the NSDate to adjust for time zone:
NSTimeZone *tz = [[NSTimeZone timeZoneForSecondsFromGMT:(-8 * 3600)];
[dateFormatter setTimeZone:tz];
NSString* s = [dateFormatter stringFromDate:now];

Date selected from UIDatePicker is different from the date being saved

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

Constructing an NSDate from today's date and a string with the time

If I have a string representing a time, say "10:45 am", and do the following to parse the string:
NSDateFormatter *dateFormat;
dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"h:mm a"];
NSLog(#"%#", [dateFormat dateFromString:#"10:45 AM"]);
I would get this logged:
2013-09-09 17:52:30.416 TimeTest[49491:a0b] 2000-01-01 15:45:00 +0000
How can I create an NSDate for the current day at the given time? I tried this
NSDate *date = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"h:mm a"];
NSDate *time = [formatter dateFromString:#"10:45 AM"];
NSDateComponents *timeComponents = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | NSMinuteCalendarUnit ) fromDate:time];
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:date];
NSDateComponents *newComponents = [[NSDateComponents alloc]init];
newComponents.timeZone = [NSTimeZone systemTimeZone];
[newComponents setDay:[dateComponents year]];
[newComponents setMonth:[dateComponents month]];
[newComponents setYear:[dateComponents year]];
[newComponents setHour:[timeComponents hour]];
[newComponents setMinute:[timeComponents minute]];
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *combinedDate = [gregorianCalendar dateFromComponents:newComponents];
NSLog(#"%#", combinedDate);
with the result
2013-09-09 19:57:14.506 TimeTest[49712:a0b] 2019-03-06 15:45:00 +0000
How should I go about this?
I'm not exactly sure what you are looking for. For what I understand, you want to build a date with the current year, month and day, but with your supplied time by parsing it from a string.
If that is the case, as others have pointed out, you need to play with NSDateComponents.
Based on your code I wrote these lines. They should build a date by merging two dates. The current one and the one you parsed.
// Get the full current date
NSDate *date = [NSDate date];
// Get the current calendar
NSCalendar *calendar = [NSCalendar currentCalendar];
// Split the date into components but only take the year, month and day and leave the rest behind
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:date];
// Build the date formatter
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"h:mm a"];
// Convert the string time into an NSDate
NSDate *time = [formatter dateFromString:#"10:45 AM"];
// Split this one in components as well but take the time part this time
NSDateComponents *timeComponents = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | NSMinuteCalendarUnit ) fromDate:time];
// Do some merging between the two date components
dateComponents.hour = timeComponents.hour;
dateComponents.minute = timeComponents.minute;
// Extract the NSDate object again
NSDate *result = [calendar dateFromComponents:dateComponents];
// Check if this was what you where looking for
NSLog(#"%#",result);
Please be aware that this sample code is by far non-optimized. There are more crisp ways to obtain what you are looking for by using time intervals, but I felt like you wanted a dirty simple example on how to do components copy and paste and then extracting dates.
This will create a date for the beginning of the day in the current time zone.
NSDate *today = [NSDate date];
NSTimeInterval interval;
NSCalendar *cal = [NSCalendar currentCalendar];
[cal rangeOfUnit:NSDayCalendarUnit
startDate:&today
interval:&interval
forDate:today];
Now we add the time:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
// I have to set the locale to posix_en_us, as my system is using 24hour style as default
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[dateFormatter setDateFormat:#"hh:mm a"];
NSDate *time = [dateFormatter dateFromString:#"10:45 AM"];
NSDateComponents *comps = [cal components:(NSHourCalendarUnit | NSMinuteCalendarUnit)
fromDate:time];
NSDate *dateAndTime = [cal dateByAddingComponents:comps
toDate:today
options:0];
dateAndTime will now be todays date with 10:45 am in the local timezone.
controlling in the debugger:
po dateAndTime
$0 = 0x41b7df138c00000d 2013-09-10 08:45:00 +0000
This is correct, as my timezone is 2 hours ahead to GMT, as we still have summer time.

Resources