How to set time on NSDate? - objective-c

I want to set the NSDate time with my desired hours:minutes:seconds
currently im working with NSDate component but it is not giving the desired result
[comps setHour: -hours];
[comps setMinute:0];
[comps setSecond:0];
NSDate *minDate = [calendar_c dateFromComponents:comps];

This works great as an NSDate category.
/** Returns a new NSDate object with the time set to the indicated hour,
* minute, and second.
* #param hour The hour to use in the new date.
* #param minute The number of minutes to use in the new date.
* #param second The number of seconds to use in the new date.
*/
-(NSDate *) dateWithHour:(NSInteger)hour
minute:(NSInteger)minute
second:(NSInteger)second
{
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components: NSYearCalendarUnit|
NSMonthCalendarUnit|
NSDayCalendarUnit
fromDate:self];
[components setHour:hour];
[components setMinute:minute];
[components setSecond:second];
NSDate *newDate = [calendar dateFromComponents:components];
return newDate;
}
With the above category, if you have an existing date you want to change the time on, you do so like this:
NSDate *newDate = [someDate dateWithHour:10 minute:30 second:00];
If, however, you are trying to add or subtract hours from an existing date, a category method to do that is also straightforward:
/** Returns a new date with the given number of hours added or subtracted.
* #param hours The number of hours to add or subtract from the date.
*/
-(NSDate*)dateByAddingHours:(NSInteger)hours
{
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setHour:hours];
return [[NSCalendar currentCalendar]
dateByAddingComponents:components toDate:self options:0];
}

Your approach should work fine. I needed a solution for this type problem (setting the individual date components) and the following code works as expected for me. My situation: I wanted to create a date object that used the current date but had the time set to a value that was passed in as a string.
NSString *string = #"7:00";
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
NSDateFormatter *timeOnlyFormatter = [[NSDateFormatter alloc] init];
[timeOnlyFormatter setLocale:locale];
[timeOnlyFormatter setDateFormat:#"h:mm"];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *today = [NSDate date];
NSDateComponents *todayComps = [calendar components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:today];
NSDateComponents *comps = [calendar components:(NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:[timeOnlyFormatter dateFromString:string]];
comps.day = todayComps.day;
comps.month = todayComps.month;
comps.year = todayComps.year;
NSDate *date = [calendar dateFromComponents:comps];
[calendar release];
[timeOnlyFormatter release];
[locale release];
One thing to note is that you really have to pay attention to time zones when you are judging whether a time appears to be accurate. For example, in my app, when you stop at a breakpoint, you will see the time in GMT (so it looks different than the input time, which is in my local time), but when the time is actually displayed on screen in the app, it is being formatted to display in the local timezone. You may need to take this into consideration to determine whether the result is actually different from what you would expect.
If this does not help, can you elaborate on "not giving the desired result"? What result is it giving and how does that compare to what you expected?

is Swift2
extension NSDate {
func dateWithHour (hour: Int, minute:Int, second:Int) ->NSDate?{
let calendar = NSCalendar.currentCalendar(),
components = calendar.components([.Day,.Month,.Year], fromDate: self)
components.hour = hour;
components.minute = minute;
components.second = second;
return calendar.dateFromComponents(components)
}
}

You can set 0 to hour, min, and second.
NSDateFormatter *tFmt = [[NSDateFormatter alloc] init];
tFmt.dateFormat = #"yyyy-MM-dd";
NSString *strNowDate = [NSString stringWithFormat:#"%# 00:00:00",[tFmt stringFromDate:[NSDate date]]];
NSDate *nowDate = [NSDate dateWithString:strNowDate formatString:#"yyyy-MM-dd HH:mm:ss"];

Swift 5 solution (based on #dattk answer) for those who fear Deprecation warnings :)
func date(withHour hour: Int, withMinute minute: Int, withSeconds second: Int) -> Date? {
let now = Date()
let calendar = NSCalendar.current
var components = calendar.dateComponents([.day,.month,.year], from: now)
components.hour = hour
components.minute = minute
components.second = second
return calendar.date(from: components)
}

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *comps = [calendar components:(NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:[NSDate date]];
comps.hour = 0;
comps.minute = 15;
NSDate *date = [calendar dateFromComponents:comps];
iOS 8

Related

NSDate setHour is giving wrong hour [duplicate]

I need to get an NSDate object for 00:00(beginning of the day) from [NSDate date], let's say if currently it is 11:30am(returned by [NSDate date]), on 01/06/2012, now I need to have an NSDate for 00:00am on 01/06/2012.
I haven't tried this, but what is in my mind is:
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:now];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
NSDate *morningStart = [calendar dateFromComponents:components];
So I first get current date(say it is 01/06/2012), and construct a NSDateComponent for the date, then I set hour/minute/second to 0 and the year/month/day should not be changed(ie. 01/06/2012) then I create an NSDate for this component setting and can I get a date of 00:00:00 01/06/2012?
What you doing is correct, but when you NSLog morningStart the date will be displayed in GMT time zone
If you wanna make sure that the date is correct, convert it to NSString
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MMM-dd HH:mm:ss"];
NSString *strFromDate = [formatter stringFromDate:morningStart]; // this will return 2012-Jun-21 00:00:00
Converting NSDate to NSString can be helpful but if you need to keep a NSDate object for further processing, here is your solution to have your real morningStart NSDate object set at 00:00:00 time, with care of the timezone as well... As you will see you were not so far from the solution :
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:now];
NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];
int timeZoneOffset = [destinationTimeZone secondsFromGMTForDate:now] / 3600;
[components setHour:timeZoneOffset];
[components setMinute:0];
[components setSecond:0];
NSDate *morningStart = [calendar dateFromComponents:components];
It's very easy to do this in iOS8 using startOfDayForDate:
let date = NSDate()
let calendar = NSCalendar.currentCalendar(calendarIdentifier: NSGregorianCalendar)
let dateAtStartOfDay = calendar.startOfDayForDate(date)
OR you may do it in the traditional way in Swift as follows:
let date = NSDate()
let calendar = NSCalendar.currentCalendar(calendarIdentifier: NSGregorianCalendar)
// Use a mask to extract the required components from today's date
let components = calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: date)
let dateAtStartOfDay = calendar.dateFromComponents(components)!
print(dateAtStartOfDay)
(Note: NSDates are stored relative to GMT. So print will display the relative local time. A clear understanding of TimeZone's is essential to using NSDates properly.)

Comparing the time of two NSDates, ignoring the date component

I want to compare two NSDates with NOW ([NSDate date]).
NSDate *date1 = [NSDate dateWithString:#"1982-02-12 07:00:00 +0100"];
NSDate *now = [NSDate dateWithString:#"2012-01-25 10:19:00 +0100"]; //example
NSDate *date2 = [NSDate dateWithString:#"1989-02-12 15:00:00 +0100"];
I would like to check if now is between date1 and date2. In the example above this is the case. The date component should be completely ignored, so only the time component should be compared. How could I accomplish this?
Thanks in advance!
unsigned int flags = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* components = [calendar components:flags fromDate:date1];
NSDate* timeOnly = [calendar dateFromComponents:components];
This will give you a date object where everything but the hours/minutes/seconds have been reset to some common value. Then you can use the standard NSDate compare functions on them.
For reference, here is the opposite question to yours: Comparing two NSDates and ignoring the time component
You can create a date representing the start of today and add the time as components to it to get the boundary dates.
NSDate *now = [NSDate date];
NSDate *startOfToday;
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&startOfToday interval:NULL forDate:now];
NSDateComponents *startComps = [[NSDateComponents alloc] init];
startComps.hour = 7;
startComps.minute = 30;
NSDateComponents *endComps = [[NSDateComponents alloc] init];
endComps.hour = 20;
NSDate *startDate = [[NSCalendar currentCalendar] dateByAddingComponents:startComps toDate:startOfToday options:0];
NSDate *endDate = [[NSCalendar currentCalendar] dateByAddingComponents:endComps toDate:startOfToday options:0];
if ([startDate timeIntervalSince1970] < [now timeIntervalSince1970] && [now timeIntervalSince1970] < [endDate timeIntervalSince1970]) {
NSLog(#"good");
}
NSDateFormatter* formatterDate = [[[NSDateFormatter alloc] init] autorelease];
formatterDate.dateStyle = NSDateFormatterMediumStyle; // whatever format you like
NSDate *first_Date = [formatterDate dateFromString:#""];
NSDate *second_Date = [formatterDate dateFromString:#""];
NSDate *todaysDate = [NSDate date];
NSTimeInterval timeIntFormFirstDate = [todaysDate timeIntervalSinceDate:First_Date];
NSTimeInterval timeIntFronLastDate = [second_Date timeIntervalSinceDate:todaysDate];
int interval1 = timeIntFormFirstDate/60;
int interval2 = timeIntFronLastDate/60;
if (interval1 >0 && interval2 >0)
{
NSLog(#"Today's date is between first and second date");
}

Storing Time Values and Comparing Them

I am trying to have points in time and then compare them. I have figured out how to compare them, but I am trying to create NSDate objects to represent times of day, and it is causing some trouble. I used NSDateFromComponents and used the setHour: and setMinute: functions, but it does not successfully modify the object. It also needs to automatically set the other components of the date to the current time and date.
COMPARING OBJECTS:
static bool DateIsBetween(NSDate *beginDate, NSDate *date, NSDate *endDate) {
return [date timeIntervalSince1970] > [beginDate timeIntervalSince1970] && [date timeIntervalSince1970] < [endDate timeIntervalSince1970];
}
CREATING DATE OBJECTS:
NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithName:#"EST"]];
NSDateComponents *weekdayComponents = [calendar components:NSWeekdayCalendarUnit fromDate:todayDate];
NSDateComponents *genericTimeComponents = [[NSDateComponents alloc]init];
[genericTimeComponents setHour:5];
[genericTimeComponents setMinute:0];
[genericTimeComponents setDay:weekdayComponents.day];
[genericTimeComponents setYear:weekdayComponents.year];
[genericTimeComponents setMonth:weekdayComponents.month];
NSDateComponents *secondComps = [[NSDateComponents alloc]init];
[secondComps setHour:7];
[secondComps setMinute:0];
[secondComps setDay:weekdayComponents.day];
[secondComps setYear:weekdayComponents.year];
[secondComps setEra:weekdayComponents.era];
[secondComps setMonth:weekdayComponents.month];
Make sure to use parentheses in your date compare function (for the sake of clarity only; logically, it should work just fine):
static bool DateIsBetween(NSDate *beginDate, NSDate *date, NSDate *endDate) {
return (([date timeIntervalSince1970] > [beginDate timeIntervalSince1970]) && ([date timeIntervalSince1970] < [endDate timeIntervalSince1970]));
}
For such cases, it's a good idea to create a category for NSDate class and write an objective-c method.
For the rest, I tried the following code and it worked for me:
NSDate * now = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setTimeZone:[NSTimeZone localTimeZone]];
NSDateComponents *genericTimeComponents = [gregorian components:(NSWeekdayCalendarUnit |NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit |NSYearCalendarUnit|NSMonthCalendarUnit|NSEraCalendarUnit)
fromDate:now];
[genericTimeComponents setHour:5];
[genericTimeComponents setMinute:0];
// Quick Check
NSLog(#"GTC=%#", genericTimeComponents);

Increase NSDate +1 day method Objective-C?

This is my method I use for increasing by one day in my navigationBar, and setting the name of the day as a title. I know it's wrong because I set "today" variable every time its called. But I can't figure out how to increase +1 day every time I call this method.
-(void)stepToNextDay:(id)sender
{
today = [NSDate date];
NSDate *datePlusOneDay = [today dateByAddibgTimeInterval:(60 * 60 * 24)];
NSDateFormatter *dateformatterBehaviour = [[[NSDateFormatter alloc]init]autorelease];
[dateFormatter setDateFormat:#"EEEE"];
NSString *dateString = [dateFormatter stringFromDate:datePlusOneDay];
self.navigationItem.title = datestring;
}
Store the date your are showing in a property (ivar, ...) of your view controller. That way you can retrieve the current setting when you go to the next day.
If you want to reliably add dates, use NSCalendar and NSDateComponents to get a "1 day" unit, and add that to the current date.
NSCalendar* calendar = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar] autorelease];
NSDateComponents* components = [[[NSDateComponents alloc] init] autorelease];
components.day = 1;
NSDate* newDate = [calendar dateByAddingComponents: components toDate: self.date options: 0];
As from iOS 8 NSGregorianCalendar is depricated, the updated answer will be,
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [[NSDateComponents alloc] init];
components.day = 1;
NSDate *newDate = [calendar dateByAddingComponents:components toDate:today options:0];
Swift Code:
var today:NSDate = NSDate()
let calender:NSCalendar! = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
var components:NSDateComponents = NSDateComponents()
components.setValue(1, forComponent: NSCalendarUnit.CalendarUnitDay)
var newDate:NSDate! = calender.dateByAddingComponents(components, toDate:today, options: NSCalendarOptions(0))

NSDate - Changing the year value

I need to change a NSDate object. What I am basically doing is changing the year value.
for example:
NSString *someYear = #"2093";
NSDate *date = [NSDate date]; // Gets the current date.
... Create a new date based upon 'date' but with specified year value.
So with 'date' returning 2011-03-06 22:17:50 +0000 from init, I would like to create a date with 2093-03-06 22:17:50 +0000.
However I would like this to be as culturally neutral as possible, so it will work whatever the timezone.
Thanks.
Here's my code for setting the UIDatePicker limits for a Date Of Birth selection. Max age allowed is 100yrs
_dateOfBirth.maximumDate = [NSDate date];
//To limit the datepicker year to current year -100
NSDate *currentDate = [NSDate date];
NSUInteger componentFlags = NSYearCalendarUnit;
NSDateComponents *components = [[NSCalendar currentCalendar] components:componentFlags fromDate:currentDate];
NSInteger year = [components year];
NSLog(#"year = %d",year);
[components setYear:-100];
NSDate *minDate = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:currentDate options:0];
_dateOfBirth.minimumDate = minDate;
Take a look at NSCalendar, especially components:fromDate: and dateFromComponents: methods.
I managed to figure the answer with the pointer Hoha gave me.
NSNumber *newYear = [[NSNumber alloc] initWithInt:[message intValue]];
NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
unsigned int unitFlags = NSYearCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;
NSDateComponents* dateComponents = [gregorian components:unitFlags fromDate:[NSDate date]];
[dateComponents setYear:[newYear intValue]];
NSDate *newDate = [gregorian dateFromComponents:dateComponents];
[newYear release];
Starting in iOS 8 you can set an specific date component. For example:
date = [calendar dateBySettingUnit:NSCalendarUnitYear value:year ofDate:date options:0];