# NSDate

# NSDateFormatter

Converting an NSDate object to string is just 3 steps.

# 1. Create an NSDateFormatter object

# Swift

let dateFormatter = NSDateFormatter()

# Swift 3

let dateFormatter = DateFormatter()

# Objective-C

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

# 2. Set the date format in which you want your string

# Swift

dateFormatter.dateFormat = "yyyy-MM-dd 'at' HH:mm"

# Objective-C

dateFormatter.dateFormat = @"yyyy-MM-dd 'at' HH:mm";

# 3. Get the formatted string

# Swift

let date = NSDate() // your NSDate object
let dateString = dateFormatter.stringFromDate(date)

# Swift 3

let date = Date() // your NSDate object
let dateString = dateFormatter.stringFromDate(date)

# Objective-C

NSDate *date = [NSDate date]; // your NSDate object
NSString *dateString = [dateFormatter stringFromDate:date];

This will give output something like this: 2001-01-02 at 13:00

Note

Creating an `NSDateFormatter` instance is an expensive operation, so it is recommended to create it once and reuse when possible.

# Useful extension for converting date to string.

extension Date {
        func toString() -> String {
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "MMMM dd yyyy"
            return dateFormatter.string(from: self)
        }
}

Useful links for swift date-formation swiftly-getting-human-readable-date-nsdateformatter (opens new window).

For constructing date formats see date format patterns (opens new window).

# Date Comparison

There are 4 methods for comparing dates:

# Swift

  • isEqualToDate(anotherDate: NSDate) -> Bool
  • earlierDate(anotherDate: NSDate) -> NSDate
  • laterDate(anotherDate: NSDate) -> NSDate
  • compare(anotherDate: NSDate) -> NSComparisonResult

# Objective-C

  • - (BOOL)isEqualToDate:(NSDate *)anotherDate
  • - (NSDate *)earlierDate:(NSDate *)anotherDate
  • - (NSDate *)laterDate:(NSDate *)anotherDate
  • - (NSComparisonResult)compare:(NSDate *)anotherDate

Let's say we have 2 dates:

# Swift

let date1: NSDate = ... // initialized as  July 7, 2016 00:00:00
let date2: NSDate = ... // initialized as  July 2, 2016 00:00:00

# Objective-C

NSDate *date1 = ... // initialized as  July 7, 2016 00:00:00
NSDate *date2 = ... // initialized as  July 2, 2016 00:00:00

Then, to compare them, we try this code:

# Swift

if date1.isEqualToDate(date2) {
    // returns false, as both dates aren't equal
}

earlierDate: NSDate = date1.earlierDate(date2) // returns the earlier date of the two (date 2)
laterDate: NSDate = date1.laterDate(date2) // returns the later date of the two (date1)

result: NSComparisonResult = date1.compare(date2)

if result == .OrderedAscending {
    // true if date1 is earlier than date2
} else if result == .OrderedSame {
    // true if the dates are the same
} else if result == .OrderedDescending {
    // true if date1 is later than date1
}

# Objective-C

if ([date1 isEqualToDate:date2]) {
    // returns false, as both date are not equal
}

NSDate *earlierDate = [date1 earlierDate:date2]; // returns date which comes earlier from both date, here it will return date2
NSDate *laterDate = [date1 laterDate:date2]; // returns date which comes later from both date, here it will return date1

NSComparisonResult result = [date1 compare:date2];
if (result == NSOrderedAscending) {
    // fails
    // comes here if date1 is earlier then date2, in our case it will not come here
} else if (result == NSOrderedSame){
    // fails
    // comes here if date1 is same as date2, in our case it will not come here
} else{ // NSOrderedDescending
    // succeeds
    // comes here if date1 is later than date2, in our case it will come here
}

If you want to compare dates and handle seconds, weeks, months and years:

# Swift 3

let dateStringUTC = "2016-10-22 12:37:48 +0000"
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss X"
let date = dateFormatter.date(from: dateStringUTC)!

let now = Date()

let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.maximumUnitCount = 2
let string = formatter.string(from: date, to: Date())! + " " + NSLocalizedString("ago", comment: "added after elapsed time to say how long before")

Or you can use this for each component:

// get the current date and time
let currentDateTime = Date()

// get the user's calendar
let userCalendar = Calendar.current

// choose which date and time components are needed
let requestedComponents: Set<Calendar.Component> = [
    .year,
    .month,
    .day,
    .hour,
    .minute,
    .second
]

// get the components
let dateTimeComponents = userCalendar.dateComponents(requestedComponents, from: currentDateTime)

// now the components are available
dateTimeComponents.year 
dateTimeComponents.month 
dateTimeComponents.day  
dateTimeComponents.hour 
dateTimeComponents.minute
dateTimeComponents.second

# Get Historic Time from NSDate (eg: 5s ago, 2m ago, 3h ago)

This can be used in various chat applications, rss feeds, and social apps where you need to have latest feeds with timestamps:

# Objective-C

- (NSString *)getHistoricTimeText:(NSDate *)since
{
    NSString *str;
    NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:since];
    if(interval < 60)
        str = [NSString stringWithFormat:@"%is ago",(int)interval];
    else if(interval < 3600)
    {
        int minutes = interval/60;
        str = [NSString stringWithFormat:@"%im ago",minutes];
    }
    else if(interval < 86400)
    {
        int hours =  interval/3600;
        
        str = [NSString stringWithFormat:@"%ih ago",hours];
    }
    else
    {
        NSDateFormatter *dateFormater=[[NSDateFormatter alloc]init];
        [dateFormater setLocale:[NSLocale currentLocale]];
        NSString *dateFormat = [NSDateFormatter dateFormatFromTemplate:@"MMM d, YYYY" options:0 locale:[NSLocale currentLocale]];
        [dateFormater setDateFormat:dateFormat];
        str = [dateFormater stringFromDate:since];
        
    }
    return str;
}

# Get Unix Epoch time

To get Unix Epoch Time (opens new window), use the constant timeIntervalSince1970:

# Swift

let date = NSDate() // current date
let unixtime = date.timeIntervalSince1970

# Objective-C

NSDate *date = [NSDate date]; // current date
int unixtime = [date timeIntervalSince1970];

# Get time cycle type (12-hour or 24-hour)

# Checking whether the current date contains the symbol for AM or PM

# Objective-C

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[NSLocale currentLocale]];
[formatter setDateStyle:NSDateFormatterNoStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
NSString *dateString = [formatter stringFromDate:[NSDate date]];
NSRange amRange = [dateString rangeOfString:[formatter AMSymbol]];
NSRange pmRange = [dateString rangeOfString:[formatter PMSymbol]];
BOOL is24h = (amRange.location == NSNotFound && pmRange.location == NSNotFound);

# Requesting the time cycle type from NSDateFormatter

# Objective-C

NSString *formatStringForHours = [NSDateFormatter dateFormatFromTemplate:@"j" options:0 locale:[NSLocale currentLocale]];
NSRange containsA = [formatStringForHours rangeOfString:@"a"];
BOOL is24h = containsA.location == NSNotFound;

This uses a special date template string called "j" which according to the ICU Spec (opens new window) ...

[...] requests the preferred hour format for the locale (h, H, K, or k), as determined by the preferred attribute of the hours element in supplemental data. [...] Note that use of 'j' in a skeleton passed to an API is the only way to have a skeleton request a locale's preferred time cycle type (12-hour or 24-hour).

That last sentence is important. It "is the only way to have a skeleton request a locale's preferred time cycle type". Since NSDateFormatter and NSCalendar are built on the ICU library, the same holds true here.

Reference

The second option was derived from [this answer](http://stackoverflow.com/a/11660380/410143).

# Get NSDate from JSON Date format "/Date(1268123281843)/"

Prior to Json.NET 4.5 dates were written using the Microsoft format: "/Date(1198908717056)/". If your server sends date in this format you can use the below code to serialize it to NSDate:

# Objective-C

(NSDate*) getDateFromJSON:(NSString *)dateString
{
    // Expect date in this format "/Date(1268123281843)/"
    int startPos = [dateString rangeOfString:@"("].location+1;
    int endPos = [dateString rangeOfString:@")"].location;
    NSRange range = NSMakeRange(startPos,endPos-startPos);
    unsigned long long milliseconds = [[dateString substringWithRange:range] longLongValue];
    NSLog(@"%llu",milliseconds);
    NSTimeInterval interval = milliseconds/1000;
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:interval];
    // add code for date formatter if need NSDate in specific format.
    return date;
}

# Get Current Date

Getting current date is very easy. You get NSDate object of current date in just single line as follows:

# Swift

var date = NSDate()

# Swift 3

var date = Date()

# Objective-C

NSDate *date = [NSDate date];

# Get NSDate Object N seconds from current date

The number of seconds from the current date and time for the new date. Use a negative value to specify a date before the current date.

For doing this we have a method named dateWithTimerIntervalSinceNow(seconds: NSTimeInterval) -> NSDate (Swift) or + (NSDate*)dateWithTimeIntervalSinceNow:(NSTimeInterval)seconds (Objective-C).

Now for example, if you require a date one week from current date and one week to current date, then we can do it as.

# Swift

let totalSecondsInWeek:NSTimeInterval = 7 * 24 * 60 * 60;
//Using negative value for previous date from today
let nextWeek = NSDate().dateWithTimerIntervalSinceNow(totalSecondsInWeek)

//Using positive value for future date from today
let lastWeek = NSDate().dateWithTimerIntervalSinceNow(-totalSecondsInWeek)

# Swift 3

let totalSecondsInWeek:TimeInterval = 7 * 24 * 60 * 60;

//Using positive value to add to the current date
let nextWeek = Date(timeIntervalSinceNow: totalSecondsInWeek)

//Using negative value to get date one week from current date
let lastWeek = Date(timeIntervalSinceNow: -totalSecondsInWeek)

# Objective-C

NSTimeInterval totalSecondsInWeek = 7 * 24 * 60 * 60;
//Using negative value for previous date from today
NSDate *lastWeek = [NSDate dateWithTimeIntervalSinceNow:-totalSecondsInWeek];

//Using positive value for future date from today
NSDate *nextWeek = [NSDate dateWithTimeIntervalSinceNow:totalSecondsInWeek];

NSLog(@"Last Week: %@", lastWeek);
NSLog(@"Right Now: %@", now);
NSLog(@"Next Week: %@", nextWeek);

# Convert NSDate that is composed from hour and minute (only) to a full NSDate

There are many cases when one has created an NSDate from only an hour and minute format, i.e: 08:12 that returns from a server as a String and you initiate an NSDate instance by these values only.

The downside for this situation is that your NSDate is almost completely "naked" and what you need to do is to create: day, month, year, second and time zone in order to this object to "play along" with other NSDate types.

For the sake of the example let's say that hourAndMinute is the NSDate type that is composed from hour and minute format:

# Objective-C

NSDateComponents *hourAndMinuteComponents = [calendar components:NSCalendarUnitHour | NSCalendarUnitMinute
                                                         fromDate:hourAndMinute];
NSDateComponents *componentsOfDate = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear
                                                                     fromDate:[NSDate date]];

NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay: componentsOfDate.day];
[components setMonth: componentsOfDate.month];
[components setYear: componentsOfDate.year];
[components setHour: [hourAndMinuteComponents hour]];
[components setMinute: [hourAndMinuteComponents minute]];
[components setSecond: 0];
[calendar setTimeZone: [NSTimeZone defaultTimeZone]];

NSDate *yourFullNSDateObject = [calendar dateFromComponents:components];

Now your object is the total opposite of being "naked".

# UTC Time offset from NSDate with TimeZone

Here this will calculate the UTC time offset from current data in desired timezone.

+(NSTimeInterval)getUTCOffSetIntervalWithCurrentTimeZone:(NSTimeZone *)current forDate:(NSDate *)date  {
    NSTimeZone *utcTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
    NSInteger currentGMTOffset = [current secondsFromGMTForDate:date];
    NSInteger gmtOffset = [utcTimeZone secondsFromGMTForDate:date];
    NSTimeInterval gmtInterval = currentGMTOffset - gmtOffset;
    return gmtInterval;
}

# Syntax

  • NSDate() // NSDate object init to the current date and time
  • NSDate().timeIntervalSince1970 // Current date and time in number of seconds from 00:00:00 UTC on 1 January 1970.
  • NSDate().compare(other: NSDate) // Returns a comparison of current date to another date returns a NSComparisonResult

# Remarks

There are different types of date format that you can set: Here is full list of them.

Format Meaning/Description Example1 Example2
y A year with at least 1 digit. 175 AD → “175” 2016 AD → “2016”
yy A year with exactly 2 digits. 5 AD → “05” 2016 AD → “16”
yyy A year with at least 3 digits. 5 AD → “005” 2016 AD → “2016”
yyyy A year with at least 4 digits. 5 AD → “0005” 2016 AD → “2016”
M A month with at least 1 digit. July → “7” "November" → "11"
MM A month with at least 2 digits. July → “07” "November" → "11"
MMM Three letter month abbreviation. July → “Jul” "November" → "Nov"
MMMM Full name of month. July → “July” "November" → "November"
MMMMM One letter month abbreviation(Jan,June,July all will have 'J'). July → “J” "November" → "N"
d Day with at least one digit. 8 → “8” 29 → “29”
dd Day with at least two digits. 8 → “08” 29 → “29”
“E”, “EE”, or”EEE” 3 letter day abbreviation of day name. Monday → “Mon” Thursday → “Thu”
EEEE Full Day name. Monday → “Monday” Thursday → “Thursday”
EEEEE 1 letter day abbreviation of day name.(Thu and Tue will be 'T') Monday → “M” Thursday → “T”
EEEEEE 2 letter day abbreviation of day name. Monday → “Mo” Thursday → “Th”
a Period of day (AM/PM). 10 PM → “PM” 2 AM → “AM”
h A 1-12 based hour with at least 1 digit. 10 PM → “10” 2 AM → “2”
hh A 1-12 based hour with at least 2 digits. 10 PM → “10” 2 AM → “02”
H A 0-23 based hour with at least 1 digit. 10 PM → “14” 2 AM → “2”
HH A 0-23 based hour with at least 2 digits. 10 PM → “14” 2 AM → “02”
m A minute with at least 1 digit. 7 → “7” 29 → “29”
mm A minute with at least 2 digits. 7 → “07” 29 → “29”
s A second with at least 1 digit. 7 → “7” 29 → “29”
ss A second with at least 2 digits. 7 → “07” 29 → “29”

There are many more, for getting different time based on zone(z), for getting time with millisecond details(S), etc.