My time comes wrong in India after 5:30 PM iphone sdk - ios

I am using the following code to calculate time difference
NSString *strTemp = [[NSString alloc] initWithString:[dicTemp objectForKey:#"created_at"]];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
NSDateFormatter *dtFormatter = [[NSDateFormatter alloc] init];
dtFormatter.dateFormat = [NSString stringWithFormat:DATEFORMAT_TYPE];
[dtFormatter setLocale:locale];
[dtFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSDate *dt = [dtFormatter dateFromString:strTemp];
NSDateFormatter *todayFormatter = [[NSDateFormatter alloc] init];
[todayFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
todayFormatter.dateFormat = DATEFORMAT_TYPE;
[todayFormatter setLocale:locale];
NSString *strToday = [todayFormatter stringFromDate:[NSDate date]];
NSDate *today = [todayFormatter dateFromString:strToday];
NSCalendar *c = [NSCalendar currentCalendar];
NSDateComponents *components = [c components:NSCalendarUnitHour fromDate:dt toDate:today options:0];
NSDateComponents *componentsMinute = [c components:NSCalendarUnitMinute fromDate:dt toDate:today options:0];
NSInteger diffHours = components.hour;
NSInteger diffMinutes = componentsMinute.minute;
While sending date to server I send it in the following way:
NSDate *date = [NSDate date];
NSDateFormatter *dateFormate = [[NSDateFormatter alloc] init];
[dateFormate setDateFormat:DATEFORMAT_TYPE];
[dateFormate setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]];
[dateFormate setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSString *strCurrentDate = [dateFormate stringFromDate:date];
I get the same date from server which I send, while converting nsdate to get current date to calculate hours, I always start getting time in negative i.e. the hour difference in negative, I have noted that it happens after 5:30 PM in India, before that it is proper.
Kindly help.

Your problem is in the difference calculation. Let's take three examples. Dates that are 30 minutes apart, dates that are 60 minutes apart and dates that are 90 minutes apart.
NSDateComponents *components = [c components:NSCalendarUnitHour fromDate:dt toDate:today options:0];
This code calculates the difference in hours between two dates. 0 for the first example (30 min), 1 for the second example (60 min), 1 for the third example (90 min).
NSDateComponents *componentsMinute = [c components:NSCalendarUnitMinute fromDate:dt toDate:today options:0];
This code calculates the difference in minutes between two dates. It does not ignore the hours. It will give you all minutes between the dates, so the result can be bigger than 59. It's 30 for the first example (30 min), 60 for the second example (60 min), 90 for the third example (90 min).
If you think you get the minutes by using 60*diffHours + diffMinutes your result will be wrong for every difference that is not less than 60 minutes. For 60 minutes you would calculate: 60 * 1 + 60 which is 120, and not 60. For 90 minutes you would calculate: 60 * 1 + 90 which is 150, and not 90.
I'm not sure what output you need. If you only need minutes just delete the first call.
If you need more components you should OR the NSCalendarUnits together:
NSDateComponents *components = [c components:NSCalendarUnitHour|NSCalendarUnitMinute fromDate:dt toDate:today options:0];
NSInteger diffHours = components.hour;
NSInteger diffMinutes = components.minute;
When you calculate the difference with this method, the calendar will take the bigger units into account when calculating the smaller units. Only the remainder will be used, i.e. the result will be hour = 1 and minute = 30 for 90 minutes.

Related

NSDateComponents wrongly adds one extra hour

I'm trying to create a method in Objective-C which would get the total number of minutes from a time value, written in "HHmm" format.
E.g. for "0210" the return value should be 130.
+ (int)totalMinutesFromHHmm:(NSString *)HHmm {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:#"UTC"];
[dateFormatter setTimeZone:timeZone];
[dateFormatter setDateFormat:#"HHmm"];
NSLocale *enLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en-GB"];
[dateFormatter setLocale:enLocale];
NSDate *date = [dateFormatter dateFromString:HHmm];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [calendar components:( NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond) fromDate:date];
NSInteger hour = [components hour];
NSInteger minute = [components minute];
return (int)(hour * 60 + minute);
}
The problem is the hour component: it's always one hour off.
On this picture the NSDate shows a 09:22 time, but on the picture below you can see the hour component is 10 (the minute component is correctly set to 22).
I looked at other posts ('NSDateComponents on hour off', etc.), but couldn't find a solution that works. Any idea what I'm doing wrong?
Time Zone / locale might not need to come into this. I could be misunderstanding, but it seems like you are just trying to take a string in HHmm format and calculate the total minutes.
If you need to use NSDate still for some reason, this could work:
+ (int)totalMinutesFromHHmm:(NSString*)HHmm
{
NSString* refHHmm = #"0000";
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HHmm"];
NSDate* refDate = [dateFormatter dateFromString:refHHmm];
NSDate* date = [dateFormatter dateFromString:HHmm];
int minutes = [date timeIntervalSinceDate:refDate] / 60;
return minutes;
}
Otherwise, this could be a simpler option, since you know you will have a 4-character string representing the hours and minutes:
+ (int)totalMinutesFromHHmm:(NSString*)HHmm
{
int minutes = [[HHmm substringWithRange:NSMakeRange(0, 2)] intValue] * 60;
minutes += [[HHmm substringWithRange:NSMakeRange(2, 2)] intValue];
return minutes;
}

NSDate dateWithTimeIntervalSince1970 adding an extra day on

I have a method that updates a label and acts as a stop watch. It works fine accept when I format the string to factor days in it adds an additional day on. For example. If the stopwatch is started ten minutes ago the label will display:
01:00:10:00
it should just display 00:00:10:00
- (void)updateTimer
{
NSDate *currentDate = [NSDate date];
NSDate *dateValue=[[NSUserDefaults standardUserDefaults] objectForKey:#"pickStart"];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:dateValue];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
// Create a date formatter
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd:HH:mm:ss"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
// Format the elapsed time and set it to the label
NSString *timeString = [dateFormatter stringFromDate:timerDate];
self.stopWatchLabel.text = timeString;
}
Any help would be greatly appreciated.
What you are doing isn't appropriate. Your goal seems to be to convert timeInterval into days, hours, minutes, and seconds. Your use of timerDate and NSDateFormatter are not the proper way to achieve that goal.
timeInterval is not an offset from January 1, 1970 and timeInterval doesn't represent a date.
What you should do is get the difference between currentDate and dateValue as a set of NSDateComponents.
- (void)updateTimer {
NSDate *currentDate = [NSDate date];
NSDate *dateValue = [[NSUserDefaults standardUserDefaults] objectForKey:#"pickStart"];
unsigned int unitFlags = NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *comps = [[NSCalendar currentCalendar] components:unitFlags fromDate:dateValue toDate:currentDate options:0];
int days = [comps day];
int hours = [comps hours];
int minutes = [comps minutes];
int seconds = [comps seconds];
NSString *timeString = [NSString stringWithFormat:#"%d:%02d:%02d:%02d", days, hours, minutes, seconds];
self.stopWatchLabel.text = timeString;
}
There is no "additional day", the "date" you produce is a point in time after the 1st Jan 1970, so if your format includes the day you get at least a 1...
Just stick with the NSTimeInterval value and use NSDateComponentsFormatter - which also formats time intervals despite the name - or just do the math yourself to get the seconds, minutes, etc. and format those.
HTH

NSDate loses and hour when adding a month during DST change?

When trying to add a month using the suggested 'correct' method on all the stackoverflow questions I can find, the date I get back always loses an hour due to DST.
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *component = [[NSDateComponents alloc] init];
[component setDay:29];
[component setMonth:3];
[component setYear:2015];
NSDate *date = [gregorian dateFromComponents:component];
NSLog(#"Date: %#", date);
NSDateComponents *monthComponent = [[NSDateComponents alloc] init];
monthComponent.month = 1;
NSDate *newDate = [gregorian dateByAddingComponents:monthComponent toDate:date options:0];
NSLog(#"newDate: %#", newDate);
The output of this code is:
Date: 2015-03-29 00:00:00 +0000
newDate: 2015-04-28 23:00:00 +0000
How can I add a month across a DST change and keep the time at midnight?
Thanks for any help.
Example in response to gnasher729 below:
In the example the first two dates would be set at midnight and the second two would be 23:00. What would be the best practice to implement something like this while keeping all the outputted dates to the desired midnight time?
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *initialDateComponent = [[NSDateComponents alloc] init];
[initialDateComponent setDay:29];
[initialDateComponent setMonth:1];
[initialDateComponent setYear:2015];
NSDate *date = [gregorian initialDateComponent];
NSLog(#"Date: %#", date);
NSDateComponents *monthComponent = [[NSDateComponents alloc] init];
monthComponent.month = 1;
monthComponent.hour = 0;
NSMutableArray *eventAlarmDate = [[NSMutableArray alloc] init];
int numberOfRepeatingMonths = 4;
for(int x = 0; 0 < numberOfRepeatingMonths; x++) {
date = [gregorian dateByAddingComponents:monthComponent toDate:date options:0];
[eventAlarmDate addObject:date];
}
You are actually asking us how to introduce a bug in your code.
The result is correct. Adding one month during a DST change will and must add one hour more or one hour less than full days.
NSDate always displays its date in UTC, which is British time without DST correction. The date calculated is with DST corrections, and it depends on your location. If you are in India, midnight is at 5:30 am UTC (or 18:30 pm UTC on the previous day, not sure).

iOS: display time as am/pm

I am new to objective c. I wish to do the following:
Convert 24 hour format to 12 hour and then add +2 to hour and display it like: 4:00 pm
I get the 12 hour format but after adding +2 to it , the time is displayed always as "am", i.e even if it is 4 pm it is displayed as 4 am. Below is my code:
NSDate *now = [NSDate date];
NSDateFormatter *timeFormatter=[[NSDateFormatter alloc]init];
timeFormatter.dateFormat=#"hh:00 a";
NSString *currentHour=[timeFormatter stringFromDate:now ];
lblcurrentHour.text=[NSString stringWithFormat:#"%#",currentHour];
NSLog(#"%#",currentHour);
int hour=[[timeFormatter stringFromDate:now]intValue];
NSDateFormatter *dateFormatter1 = [[NSDateFormatter alloc] init];
dateFormatter1.dateFormat = #"HH:mm";
NSDate *date1 = [dateFormatter1 dateFromString:[NSString stringWithFormat:#"%02d:00",hour+=3]];
dateFormatter1.dateFormat = #"hh:mm a";
lblnextHour.text = [dateFormatter1 stringFromDate:date1]; // prints 4:00 am not pm
How do i solve this? Where am i getting wrong?
If I understand your requirements correctly, you want to take the current time and display the minutes as :00, anchoring to the current hour. Then you want to add two hours and display that time. The following code prints 04:00 AM and 06:00 AM to the console (local time is 0421.)
For calendrical calculations, I would avoid using NSDateFormatter as you are doing when you compute the time two hours from now. There are too many ways that can go astray. For example, what happens when the now time is 2300?
A good reference on calendrical calculations in Cocoa is here
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
// use gregorian calendar for calendrical calculations
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
// get current date
NSDate *date = [NSDate date];
NSCalendarUnit units = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
units |= NSHourCalendarUnit | NSMinuteCalendarUnit;
NSDateComponents *currentComponents = [gregorian components:units fromDate:date];
// change the minutes to 0
currentComponents.minute = 0;
date = [gregorian dateFromComponents:currentComponents];
// format and display the time
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
timeFormatter.dateFormat = #"hh:mm a";
NSString *currentTimeString = [timeFormatter stringFromDate:date];
NSLog(#"Current hour = %#",currentTimeString);
// add two hours
NSDateComponents *incrementalComponents = [[NSDateComponents alloc] init];
incrementalComponents.hour = 2;
NSDate *twoHoursLater = [gregorian dateByAddingComponents:incrementalComponents toDate:date options:0];
// format and display new time
NSString *twoHoursLaterStr = [timeFormatter stringFromDate:twoHoursLater];
NSLog(#"Two hours later = %#",twoHoursLaterStr);
}
return 0;
}
Try this:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"hh:mm:ss a"];
NSLog(#"Today's Date and Time: %#", [formatter stringFromDate:[NSDate date]]);
Output:
Today's Date and Time: 02:43:33 PM

NSDate subtracting trouble

so in my app I want to subtract two dates. The first date is set date and the second one is the current date. So i tried this code:
NSString *setDateString = [NSString stringWithFormat:#"12:30"];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSDate *setDate = [dateFormatter dateFromString:setDateString];
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:setDate];
But it counts the interval from 1970. But I need from the current day. Can anyone help?
I assume you want the difference between now and 1230 hrs of today. This can be done by
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components =[gregorian components:(NSDayCalendarUnit|NSYearCalendarUnit|NSMonthCalendarUnit) fromDate:today];
[components setHour:12];
[components setMinute:30];
[components setSecond:0];
NSDate *setDate=[gregorian dateFromComponents:components];
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:setDate];
[gregorian release];
The reason it doesn't work for you is you've not given the format correctly. Alternatively, you can describe it correctly in setDateString by specifying all the components rather than just hour and minute.

Resources