NSNumber from NSDate
Asked Answered
A

3

13

I'm attempting to get around a date validation that refuses to take anything earlier than tomorrow.
So far I have this:

NSDate *dateY = [NSDate dateWithTimeIntervalSinceNow:-86400];
                // Negative one day, in seconds (-60*60*24)
NSLog(@"%@", [NSDate date]);
    // "yyyy-MM-dd HH:mm:ss Z", accurate assuming Z = +0000
NSLog(@"%@", dateY);
    // "yyyy-MM-dd HH:mm:ss Z", same accuracy (minus one day)

That's great, but dateY is not an NSNumber. I need an NSNumber for the comparison, but I can't find anything that works. (I don't even know how an NSNumber can be 2011-04-14 13:22:29 +0000, anyway...)

I can use NSDateFormatter to convert an NSDate into an NSString, so if it would be possible to take that string and convert it to the required NSNumber (as opposed to directly converting the NSDate to an NSNumber, which I can't seem to find help with either), that would be fine.


- (BOOL)validateDueDate:(id *)ioValue error:(NSError **)outError {
    NSDate *dateY = [NSDate dateWithTimeIntervalSinceNow:-86400];
    NSNumber *tis1970 = [NSNumber numberWithDouble:[dateY timeIntervalSince1970]];
    NSLog(@"NSNumber From Date : %@", tis1970);
    NSLog(@"Date From NSNumber : %@", [NSDate dateWithTimeIntervalSince1970:[tis1970 doubleValue]]);

    // Due dates in the past are not valid
    // Enforced that a due date has to be >= today's date
    if ([*ioValue compare:[NSDate date]] == NSOrderedAscending) {
        if (outError != NULL) {
            NSString *errorStr = [[[NSString alloc] initWithString:@"Due date must be today or later."] autorelease];
            NSDictionary *userInfoDictionary = [NSDictionary dictionaryWithObject:errorStr forKey:@"ErrorString"];
            NSError *error = [[[NSError alloc]
                                initWithDomain:TASKS_ERROR_DOMAIN
                                code:DUEDATE_VALIDATION_ERROR_CODE
                                userInfo:userInfoDictionary] autorelease];
            *outError = error;
            }
        return NO;
    } else {
        return YES;
    }
}

Right now, the user is not allowed to choose a date before tomorrow. errorStr lies. Before today makes more sense than before tomorrow as a rule for refusing to save the date, so I've been fighting with this thing to let me use yesterday in place of today, rather than looking any deeper.

Edit: Using NSOrderedSame allows any date to be selected without an error. That won't do.

Ashly answered 14/4, 2011 at 13:50 Comment(4)
if you want just to compare equality, you can use [date isEqualToDate:dateY];Dusty
Why do you need an NSNumber for the comparison? You already have an NSNumber to compare to? What does it represent?Hydrometeor
What is ioValue? A number? A string?Hydrometeor
(id *)ioValue just tells me that ioValue is a pointer to an id (not an id, which is an object pointer, but a pointer to an id). It could be a pointer to tour app delegate, or an NSTask, or a UITableView. I'd be surprised if any of those could be considered dates.Hydrometeor
S
28

You can convert an NSDate to an NSNumber like this:

NSDate *aDate = [NSDate date];
NSNumber *secondsSinceRefDate = [NSNumber numberWithDouble:[aDate timeIntervalSinceReferenceDate]];

and convert back like:

aDate = [NSDate dateWithTimeIntervalSinceReferenceDate:[NSNumber doubleValue]];
Sometime answered 14/4, 2011 at 13:59 Comment(1)
for new folks (me), when converting back, the 'NSNumber' above is placeholder for your variable. e.g., code above would read 'aDate = [NSDate dateWithTimeIntervalSinceReferenceDate:[secondsSinceRefDate doubleValue]];' // (thank you odrm)Rammer
P
1

All that is needed to get a NSNumber is

NSDate *dateY = [NSDate dateWithTimeIntervalSinceNow:-86400];
NSNumber *tis1970 = [NSNumber numberWithDouble:[dateY timeIntervalSince1970]];
NSLog(@"NSNumber From Date : %@", tis1970);
NSLog(@"Date From NSNumber : %@", [NSDate dateWithTimeIntervalSince1970:[tis1970 doubleValue]]);
Prudhoe answered 14/4, 2011 at 13:57 Comment(3)
You are more than likely doing something wrong. Try copying and pasting my code exactly I am going to add an edit. It looks like you are calling timeIntervalSinceReferenceData on a NSNumber not a NSDate.Prudhoe
Add the code to your original question. We need to know what ioValue is and what you are really trying to accomplish. NSNumber may not even be the right solution for you.Prudhoe
POST YOUR CODE!!! seriously add your code, explain what you are trying to accomplish and I can guarantee you if it is logical you will get a proper solution.Prudhoe
C
1

You should never use 86400 to calculate date differences, because not all days have 86,400 seconds in them. Use NSDateComponents instead:

- (BOOL)validateDueDate:(NSDate *)dueDate error:(NSError *)error {
  NSDate *today = [NSDate date];
  NSCalendar *calendar = [NSCalendar currentCalendar];
  NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:today];
  //adjust the components to tomorrow at the first instant of the day
  [components setDay:[components day] + 1];
  [components setHour:0];
  [components setMinute:0];
  [components setSecond:0];
  NSDate *tomorrow = [calendar dateFromComponents:components];

  NSDate *earlierDate = [dueDate earlierDate:tomorrow];
  if ([earlierDate isEqualToDate:dueDate]) {
    //the dueDate is before tomorrow
    if (error != nil) {
      NSString *errorStr = [[[NSString alloc] initWithString:@"Due date must be today or later."] autorelease];
      NSDictionary *userInfoDictionary = [NSDictionary dictionaryWithObject:errorStr forKey:NSLocalizedDescriptionKey];
      *error = [[[NSError alloc] initWithDomain:TASKS_ERROR_DOMAIN code:DUEDATE_VALIDATION_ERROR_CODE userInfo:userInfoDictionary] autorelease];
    }
    return NO;
  }
  return YES;
}

WARNING: code typed in a browser. Caveat Implementor

Cardiology answered 14/4, 2011 at 18:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.