DevCali
DevCali

Reputation: 398

Time/Date from NSDate to show just like Message and Mail app in iOS

I'm building an app that requires me to show time and day i.e Sunday if the object was created prior to 24hrs etc. Just like Message and Mail app in iOS would show time for 24Hrs and than change it to show days like 'monday, tuesday..". I was looking if i can find any framework that does exactly like this or do i have to write a code for this?

Upvotes: 2

Views: 2630

Answers (8)

Sreekuttan
Sreekuttan

Reputation: 1964

I have tried all the above solutions but unfortunately, nothing worked for me. Anyway, I ended up with a solution.

Swift version

extension Date {

    func isEqual(to date: Date, toGranularity component: Calendar.Component, in calendar: Calendar = .current) -> Bool {
        calendar.isDate(self, equalTo: date, toGranularity: component)
    }

    func isInSameYear(as date: Date) -> Bool { isEqual(to: date, toGranularity: .year) }
    func isInSameMonth(as date: Date) -> Bool { isEqual(to: date, toGranularity: .month) }
    func isInSameWeek(as date: Date) -> Bool { isEqual(to: date, toGranularity: .weekOfYear) }

    func isInSameDay(as date: Date) -> Bool { Calendar.current.isDate(self, inSameDayAs: date) }

    var isInThisYear:  Bool { isInSameYear(as: Date()) }
    var isInThisMonth: Bool { isInSameMonth(as: Date()) }
    var isInThisWeek:  Bool { isInSameWeek(as: Date()) }

    var isInYesterday: Bool { Calendar.current.isDateInYesterday(self) }
    var isInToday:     Bool { Calendar.current.isDateInToday(self) }
    var isInTomorrow:  Bool { Calendar.current.isDateInTomorrow(self) }

    var isInTheFuture: Bool { self > Date() }
    var isInThePast:   Bool { self < Date() }
    
    func formattedRelativeString() -> String {
        let dateFormatter = DateFormatter()
        
        if self.addingTimeInterval(60) > Date() {
            // less than a minute
            return "Now"
        } else if isInToday || isInYesterday {
            // today and yesterday
            // Today, 3:57 PM
            dateFormatter.doesRelativeDateFormatting = true
            dateFormatter.timeStyle = .short
            dateFormatter.dateStyle = .short
        } else if isInThisWeek {
            // less than a week ago
            // Friday, 4:03 PM
            dateFormatter.dateFormat = "EEEE, h:mm a"
            
        } else if isInThisYear {
            // more than a week ago
            // Fri, 4 Aug, 3:55 AM
            dateFormatter.dateFormat = "E, d MMM, h:mm a"
        } else {
            // more than a year ago
            // 10 Aug, 2016, 3:56 AM
            dateFormatter.dateFormat = "d MMM, yyyy, h:mm a"
        }
            
        return dateFormatter.string(from: self)
    }
}

You can change the date format for each according to your needs. To create your own customized date format refer to this article.

Output

let now = Date().formattedRelativeString()
//  Now

let today = Date(timeInterval: -60*60, since: Date()).formattedRelativeString()
//  Today, 9:06 AM

let yesterday = Date(timeInterval: -24*60*60, since: Date()).formattedRelativeString()
//  Yesterday, 10:06 AM

let weekAgo = Date(timeInterval: -7*24*60*60, since: Date()).formattedRelativeString()
//  Fri, 28 Jul, 10:06 AM

let yearAgo = Date(timeInterval: -366*24*60*60, since: Date()).formattedRelativeString()
//  3 Aug, 2022, 10:06 AM

Upvotes: 0

MQLN
MQLN

Reputation: 2328

Here's how to do it all natively with Swift 4 & 5:

extension Date {

    func formatRelativeString() -> String {
        let dateFormatter = DateFormatter()
        let calendar = Calendar(identifier: .gregorian)
        dateFormatter.doesRelativeDateFormatting = true

        if calendar.isDateInToday(self) {
            dateFormatter.timeStyle = .short
            dateFormatter.dateStyle = .none
        } else if calendar.isDateInYesterday(self){
            dateFormatter.timeStyle = .none
            dateFormatter.dateStyle = .medium
        } else if calendar.compare(Date(), to: self, toGranularity: .weekOfYear) == .orderedSame {
            let weekday = calendar.dateComponents([.weekday], from: self).weekday ?? 0
            return dateFormatter.weekdaySymbols[weekday-1]
        } else {
            dateFormatter.timeStyle = .none
            dateFormatter.dateStyle = .short
        }

        return dateFormatter.string(from: self)
    }
}

Upvotes: 8

Alino
Alino

Reputation: 152

Objective C formating date and time.

Using Matthew York's excellent DateTools methods.

NSDate extension:

-(NSString *)formatDateTimeToString{
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc]init];
    [dateFormatter setLocale: [[NSLocale alloc] initWithLocaleIdentifier: [[NSLocale currentLocale] localeIdentifier]]];

    if ([[NSCalendar currentCalendar] isDateInToday:self])
    {
        [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
        [dateFormatter setDateStyle:NSDateFormatterNoStyle];
    }
    else if ([[NSCalendar currentCalendar] isDateInYesterday:self])
    {
        [dateFormatter setDoesRelativeDateFormatting:YES];
        [dateFormatter setTimeStyle:NSDateFormatterNoStyle];
        [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
    }
    else if ([self daysAgo]<6)
    {
        [dateFormatter setDateFormat:@"EEEE"];
    }
    else
    {
        [dateFormatter setTimeStyle:NSDateFormatterNoStyle];
        [dateFormatter setDateStyle:NSDateFormatterShortStyle];
    }
    return  [dateFormatter stringFromDate:self];
}


-(NSInteger)daysAgo{
    return [self daysEarlierThan:[NSDate date]];
}

-(NSInteger)daysEarlierThan:(NSDate *)date{
    return ABS(MIN([self daysFrom:date], 0));
}
-(NSInteger)daysFrom:(NSDate *)date{
    return [self daysFrom:date calendar:nil];
}
-(NSInteger)daysFrom:(NSDate *)date calendar:(NSCalendar *)calendar{
    NSDate *earliest = [self earlierDate:date];
    NSDate *latest = (earliest == self) ? date : self;
    NSInteger multiplier = (earliest == self) ? -1 : 1;
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay fromDate:earliest toDate:latest options:0];
    return multiplier*components.day;
}

Upvotes: 0

Hashem Aboonajmi
Hashem Aboonajmi

Reputation: 13900

updated for swift 4:

 extension NSDate {

    func formattedRelativeString() -> String 
    {
        let dateFormatter = DateFormatter()

        if isInToday || isInYesterday {
            /// today and yesterday
            /// Today, 3:57 PM
            dateFormatter.doesRelativeDateFormatting = true
            dateFormatter.timeStyle = .short
            dateFormatter.dateStyle = .short
        } else if isLessThanAweekAgo {

            /// less than a week ago
            /// Friday, 4:03 PM
            dateFormatter.dateFormat = "EEEE, h:mm a"
         } else if isInThisYear {

            // more than a week ago
            // Fri, 4 Aug, 3:55
            dateFormatter.dateFormat = "E, d MMM, h:mm a"
         } else {
            // more than a year ago
            // Aug 10, 2016, 3:56
            dateFormatter.dateFormat = "MMM d, yyyy, h:mm a"
         }

        return dateFormatter.string(from: self)
    }

}

you can test it in playground with these sample dates:

let now = Date()
let yesterday = Date(timeInterval: -24*60*60, since: Date())
let weekAgo = Date(timeInterval: -7*24*60*60, since: Date())
let yearAgo = Date(timeInterval: -366*24*60*60, since: Date())

Upvotes: 2

Den Telezhkin
Den Telezhkin

Reputation: 631

Swift 3 version of @avf response:

extension NSDate {
    func formattedRelativeString() -> String 
    {
        let dateFormatter = DateFormatter()
        dateFormatter.doesRelativeDateFormatting = true

        if isToday() {
            dateFormatter.timeStyle = .short
            dateFormatter.dateStyle = .none
        } else if isYesterday() {
            dateFormatter.timeStyle = .none
            dateFormatter.dateStyle = .medium
        } else if daysAgo() < 6 {
            return dateFormatter.weekdaySymbols[weekday()-1]
        } else {
            dateFormatter.timeStyle = .none
            dateFormatter.dateStyle = .short
        }

        return dateFormatter.string(from: self as Date)
    }
}

Upvotes: 2

avf
avf

Reputation: 860

I needed this too, so I wrote the following NSDate extension:

extension NSDate {

    func formattedRelativeString() -> String {
        let dateFormatter = NSDateFormatter()
        dateFormatter.doesRelativeDateFormatting = true

        if isToday() {
            dateFormatter.timeStyle = .ShortStyle
            dateFormatter.dateStyle = .NoStyle
        } else if isYesterday() {
            dateFormatter.timeStyle = .NoStyle
            dateFormatter.dateStyle = .MediumStyle
        } else if daysAgo() < 6 {
            return dateFormatter.weekdaySymbols[weekday()-1]
        } else {
            dateFormatter.timeStyle = .NoStyle
            dateFormatter.dateStyle = .ShortStyle
        }

        return dateFormatter.stringFromDate(self)
    }
}

This requires Matthew York's excellent DateTools to work.

Upvotes: 3

rist
rist

Reputation: 578

Use a NSDateFormatter and set it's doesRelativeDateFormatting property to YES.

Upvotes: -1

Saad Chaudhry
Saad Chaudhry

Reputation: 1410

NSString *dateString = [NSDateFormatter localizedStringFromDate:[NSDate date]
                                                              dateStyle:NSDateFormatterShortStyle
                                                              timeStyle:NSDateFormatterFullStyle];
        NSLog(@"%@",dateString);

Try this code, modify it as per your requirement.

Upvotes: 0

Related Questions