NSDateComponents wrongly adds one extra hour - ios

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

Related

What is the simple way to detect time is in hours or not?

I am using UIDatePickerView in my project with timeInterval one minute. After selecting time if time is in hours then I have to do some stuff. So how can I detect if user selects time in hours or not?
Try this one , you can get hours between two date.
NSDate* date1 = someDate;
NSDate* date2 = someOtherDate;
NSTimeInterval distanceBetweenDates = [date1 timeIntervalSinceDate:date2];
double secondsInAnHour = 3600;
NSInteger hoursBetweenDates = distanceBetweenDates / secondsInAnHour;
Finally I got answer for my own question
NSDateFormatter *formatter23 = [[NSDateFormatter alloc]init];
[formatter23 setDateFormat:#"yyyy-MM-dd--HH:mm"];
NSDate* date1 = datePicker.date;
[formatter23 setDateFormat:#"mm"];
if ([[formatter23 stringFromDate:date1] isEqualToString:#"00"] || [[formatter23 stringFromDate:date1] isEqualToString:#"30"]){
NSLog(#"Date is in half an hour or hour");
} else{
NSLog(#"Some other");
}
NSDateFormatter *timeFormatter = [[[NSDateFormatter alloc]init]autorelease];
timeFormatter.dateFormat = #"HH";
NSString *date_Hour= [timeFormatter stringFromDate: localDate];
and simple way to get hour only use NSDateComponents class
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSHourCalendarUnit fromDate:[NSDate date]];
NSInteger hour= [components hour];

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

How to get days in a week from today in objective c

I am trying to get the days of a week in reference to their date.
Ex.: 14th October is a Wednesday.
I am creating a collection view cell and displaying the date as follows.
In the 14th cell it would display Wednesday, but how to get the next day as Thursday, then Friday...and so on.
I have got todays date and which day it is as follows,
day = [components day];
week = [components month];
year = [components year];
weekday = [components weekday];
NSString *string = [NSString stringWithFormat:#"%ld.%ld.%ld", (long)day, (long)week, (long)year];
NSLog(#"%#",string);
NSDate *todayDate = [NSDate date]; // get today date
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEEE"];
NSString *convertedDateString = [dateFormatter stringFromDate:todayDate];// here convert date in
NSLog(#"Today formatted date is %#",convertedDateString);
And i have found this method online, which returns the days in string when you pass the integer, but i am having trouble in this too, not understanding which integer to pass every time so I get different strings.
static inline NSString *stringFromWeekday(int weekday){
static NSString *strings[] = {
#"Sunday",
#"Monday",
#"Tuesday",
#"Wednesday",
#"Thursday",
#"Friday",
#"Saturday",
};
return strings[weekday];
}
You already got everything in place. You should be getting the correct day name in the convertedDateString string. You just have to add 24 hours to your todayDate object and use the dateformatter again to get the next day.
NSDate *todayDate = [NSDate date]; // get today date
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEEE"];
NSString *convertedDateString = [dateFormatter stringFromDate:todayDate];// here convert date in
You can get the next day like this.
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:(NSDayCalendarUnit | NSMonthCalenderUnit | NSYearCalenderUnit | NSWeekdayCalendarUnit) fromDate:today];
[dateComponents setDay:dateComponents.day+1];
NSDate *nextDay = [dateComponents date];
// Get the day by following same approach in the top
You will get days in a week from today using below code.
NSDate *today = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents =
[gregorian components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:today];
NSInteger day = [weekdayComponents day];
NSInteger weekday = [weekdayComponents weekday];

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

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.

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

Resources