Проблема объединения даты и времени в один NSDate

Я пытаюсь совместить значение времени (часы, минуты, секунды) одного NSDate со значением даты (день, месяц, год) второго NSDate с помощью этого метода:

+ (NSDate *)combineDate:(NSDate *)date withTime:(NSDate *)time {

    NSCalendar *gregorian = [[NSCalendar alloc]
        initWithCalendarIdentifier:NSGregorianCalendar];

    NSDateComponents *dateComponents = [gregorian components:(NSDayCalendarUnit | 
        NSWeekdayCalendarUnit) fromDate:date];
    NSDateComponents *timeComponents = [gregorian components:(NSDayCalendarUnit | 
        NSWeekdayCalendarUnit) fromDate:time];

    NSDateComponents *comp = [NSDateComponents alloc];
    [comp setSecond:[timeComponents second]];
    [comp setHour:[timeComponents hour]];
    [comp setMinute:[timeComponents minute]];
    [comp setYear:[dateComponents year]];
    [comp setMonth:[dateComponents month]];
    [comp setDay:[dateComponents day]];

    NSDate *combDate = [gregorian dateFromComponents:comp]; 

    [gregorian release];
    [comp release];

    return combDate;
}

... но то, что он возвращает, фактически тарабарщина (например, год выглядит как "1" ). Кто-нибудь видит, что неправильно с этим методом?

Ответ 1

Я использовал неправильные компоненты календаря. Здесь исправленная функция (теперь для ARC):

+ (NSDate *)combineDate:(NSDate *)date withTime:(NSDate *)time {

    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:
        NSGregorianCalendar];

    unsigned unitFlagsDate = NSYearCalendarUnit | NSMonthCalendarUnit 
        |  NSDayCalendarUnit;
    NSDateComponents *dateComponents = [gregorian components:unitFlagsDate 
        fromDate:date];
    unsigned unitFlagsTime = NSHourCalendarUnit | NSMinuteCalendarUnit 
        |  NSSecondCalendarUnit;
    NSDateComponents *timeComponents = [gregorian components:unitFlagsTime 
        fromDate:time];

    [dateComponents setSecond:[timeComponents second]];
    [dateComponents setHour:[timeComponents hour]];
    [dateComponents setMinute:[timeComponents minute]];

    NSDate *combDate = [gregorian dateFromComponents:dateComponents];   

    return combDate;
}

Ответ 2

Здесь он находится в Swift 2

func combineDateAndTime(date: NSDate, time: NSDate) -> NSDate {

    let calendar = NSCalendar.currentCalendar()
    let dateComponents = calendar.components([.Year, .Month, .Day], fromDate: date)
    let timeComponents = calendar.components([.Hour, .Minute, .Second], fromDate: time)

    let components = NSDateComponents()
    components.year = dateComponents.year
    components.month = dateComponents.month
    components.day = dateComponents.day
    components.hour = timeComponents.hour
    components.minute = timeComponents.minute
    components.second = timeComponents.second

    return calendar.dateFromComponents(components)!
}

Ответ 3

Расширение Swift 3:

func combineDateAndTime(date: Date, time: Date) -> Date {

    let calendar = NSCalendar.current

    let dateComponents = calendar.dateComponents([.year, .month, .day], from: date)
    let timeComponents = calendar.dateComponents([.hour, .minute, .second], from: time)

    var components = DateComponents()
    components.year = dateComponents.year
    components.month = dateComponents.month
    components.day = dateComponents.day
    components.hour = timeComponents.hour
    components.minute = timeComponents.minute
    components.second = timeComponents.second

    return calendar.date(from: components)!
}

Ответ 4

(Swift + extension) - ваш друг:

// MARK: - NSDate extension -

extension NSDate {

    static func combineDate(date date: NSDate, withTime time: NSDate) -> NSDate? {
        let gregorian = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)

        let dateComponents = gregorian?.components([.Year, .Month, .Day], fromDate: date)
        let timeComponents = gregorian?.components([.Hour, .Minute, .Second], fromDate: date)

        dateComponents?.second = timeComponents?.second ?? 0
        dateComponents?.minute = timeComponents?.minute ?? 0
        dateComponents?.hour = timeComponents?.hour ?? 0

        if let _ = dateComponents {
            return gregorian?.dateFromComponents(dateComponents!)
        }
        return nil
    }

}