How to Convert Nsdate in to Relative Format as "Today","Yesterday","A Week Ago","A Month Ago","A Year Ago"

How to convert NSDate in to relative format as Today , Yesterday , a week ago , a month ago , a year ago ?

For simplicity I'm assuming that the dates you are formatting are all in the past (no "tomorrow" or "next week"). It's not that it can't be done but it would be more cases to deal with and more strings to return.


You can use components:fromDate:toDate:options: with whatever combination of date components you are looking for to get the number of years, months, weeks, days, hours, etc. between two dates. By then going though them in order from most significant (e.g. year) to least significant (e.g. day), you can format a string based only on the most significant component.

For example: a date that is 1 week, 2 days and 7 hours ago would be formatted as "1 week".

If you want to create special strings for a special number of a unit, like "tomorrow" for "1 day ago" then you can check the value of that component after you have determined that it is the most significant component.

The code would look something like this:

- (NSString *)relativeDateStringForDate:(NSDate *)date
{
NSCalendarUnit units = NSCalendarUnitDay | NSCalendarUnitWeekOfYear |
NSCalendarUnitMonth | NSCalendarUnitYear;

// if `date` is before "now" (i.e. in the past) then the components will be positive
NSDateComponents *components = [[NSCalendar currentCalendar] components:units
fromDate:date
toDate:[NSDate date]
options:0];

if (components.year > 0) {
return [NSString stringWithFormat:@"%ld years ago", (long)components.year];
} else if (components.month > 0) {
return [NSString stringWithFormat:@"%ld months ago", (long)components.month];
} else if (components.weekOfYear > 0) {
return [NSString stringWithFormat:@"%ld weeks ago", (long)components.weekOfYear];
} else if (components.day > 0) {
if (components.day > 1) {
return [NSString stringWithFormat:@"%ld days ago", (long)components.day];
} else {
return @"Yesterday";
}
} else {
return @"Today";
}
}

If your dates could also be in the future then you can check the absolute value of the components in the same order and then check if it's positive or negative to return the appropriate strings. I'me only showing the year below:

if ( abs(components.year > 0) ) { 
// year is most significant component
if (components.year > 0) {
// in the past
return [NSString stringWithFormat:@"%ld years ago", (long)components.year];
} else {
// in the future
return [NSString stringWithFormat:@"In %ld years", (long)components.year];
}
}

Relative string from NSDate

NSDateFormatter will do a great deal of what is mentioned above by using setDoesRelativeDateFormatting: on an instance. From there, you can control the formatting using the date style and the time style to fine tune it to your needs.

If that doesn't get you what you need then check out SORelativeDateTransformer, it is an NSValueTransformer subclass that attempts to provide the same behavior you see with relative dates on SO.

Finally, if you want to roll your own or do more research here is the (likely) original question on the topic... yes it is question 11.

Convert NSDate to time string


I will accept an answer that allows me to cast an NSDate as a Date

Say as Date.

Replacement of date object with “today” and “yesterday” strings in iphone

NSDateFormatter can do this. However this does not work with custom date formats, but in most cases when you need relative dates you are presenting them to the user and you should not use hard coded date formats in the first place.

NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.timeStyle = NSDateFormatterMediumStyle;
df.dateStyle = NSDateFormatterShortStyle;
df.doesRelativeDateFormatting = YES; // this enables relative dates like yesterday, today, tomorrow...

NSLog(@"%@", [df stringFromDate:[NSDate dateWithTimeIntervalSinceNow:-48*60*60]]);
NSLog(@"%@", [df stringFromDate:[NSDate dateWithTimeIntervalSinceNow:-24*60*60]]);
NSLog(@"%@", [df stringFromDate:[NSDate date]]);
NSLog(@"%@", [df stringFromDate:[NSDate dateWithTimeIntervalSinceNow:24*60*60]]);
NSLog(@"%@", [df stringFromDate:[NSDate dateWithTimeIntervalSinceNow:48*60*60]]);

this will print:

2013-06-06 09:13:22.844 x 2[11732:c07] 6/4/13, 9:13:22 AM
2013-06-06 09:13:22.845 x 2[11732:c07] Yesterday, 9:13:22 AM
2013-06-06 09:13:22.845 x 2[11732:c07] Today, 9:13:22 AM
2013-06-06 09:13:22.846 x 2[11732:c07] Tomorrow, 9:13:22 AM
2013-06-06 09:13:22.846 x 2[11732:c07] 6/8/13, 9:13:22 AM

On a device with german locale this will print "Vorgestern" (the day before yesterday) and "Übermorgen" (the day after tomorrow) for the first and last date.

Short formatted relative time in iOS?

You can not achieve this without changing the third-party class.
In your situation, NSDate-TimeAgo library is too powerful for you. You even don't need any 'ago' result. So, personally I suggest you to convert time string on your own code, something like (just an example, maybe there are some performance issues here, you can use Time Profile to test it):

+ (NSString *)stringForDisplayFromDate:(NSDate *)date
{
if (!date) {
return nil;
}

NSDate *currentDate = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(kCFCalendarUnitYear
|kCFCalendarUnitMonth
|kCFCalendarUnitWeek
|kCFCalendarUnitDay
|kCFCalendarUnitHour
|kCFCalendarUnitMinute)
fromDate:date
toDate:currentDate
options:0];
if (components.year == 0) {
// same year
if (components.month == 0) {
// same month
if (components.week == 0) {
// same week
if (components.day == 0) {
// same day
if (components.hour == 0) {
// same hour
if (components.minute < 10) {
// in 10 mins
return @"now";
} else {
// 10 mins age
return [NSString stringWithFormat:@"%dm", (int)(components.minute/10)*10];
}
} else {
// different hour
return [NSString stringWithFormat:@"%dh", components.hour];
}
} else {
// different day
return [NSString stringWithFormat:@"%dd", components.day];
}
} else {
// different week
return [NSString stringWithFormat:@"%dW", components.week];
}
} else {
// different month
return [NSString stringWithFormat:@"%dM", components.month];
}
} else {
// different year
return [NSString stringWithFormat:@"%dY", components.year];
}

return [self stringForDisplayFromDate:date prefixed:NO];
}

get NSDate today, yesterday, this Week, last Week, this Month, last Month... variables

Might be a better way to write this but here what i came up on Ben's NSCalendar suggestion and working from there to NSDateComponents

NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond ) fromDate:[[NSDate alloc] init]];

[components setHour:-[components hour]];
[components setMinute:-[components minute]];
[components setSecond:-[components second]];
NSDate *today = [cal dateByAddingComponents:components toDate:[[NSDate alloc] init] options:0]; //This variable should now be pointing at a date object that is the start of today (midnight);

[components setHour:-24];
[components setMinute:0];
[components setSecond:0];
NSDate *yesterday = [cal dateByAddingComponents:components toDate: today options:0];

components = [cal components:NSWeekdayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:[[NSDate alloc] init]];

[components setDay:([components day] - ([components weekday] - 1))];
NSDate *thisWeek = [cal dateFromComponents:components];

[components setDay:([components day] - 7)];
NSDate *lastWeek = [cal dateFromComponents:components];

[components setDay:([components day] - ([components day] -1))];
NSDate *thisMonth = [cal dateFromComponents:components];

[components setMonth:([components month] - 1)];
NSDate *lastMonth = [cal dateFromComponents:components];

NSLog(@"today=%@",today);
NSLog(@"yesterday=%@",yesterday);
NSLog(@"thisWeek=%@",thisWeek);
NSLog(@"lastWeek=%@",lastWeek);
NSLog(@"thisMonth=%@",thisMonth);
NSLog(@"lastMonth=%@",lastMonth);

Convert date string to NSDate

Your date format and your time string should be same. In your case it should be like,

 let formatterJsonDate = DateFormatter()
formatterJsonDate.dateFormat = "yyy-MM-dd HH:mm:ss"

print(formatterJsonDate.date(from: "2016-10-08 00:20:00"))

Or change dateformatter like,

  "yyyy-MM-dd HH:mm:ss.SSSSSS"

And hh should be capital for 24 - hour format!!!! like HH!

iPhone: Convert date string to a relative time stamp


-(NSString *)dateDiff:(NSString *)origDate {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setFormatterBehavior:NSDateFormatterBehavior10_4];
[df setDateFormat:@"EEE, dd MMM yy HH:mm:ss VVVV"];
NSDate *convertedDate = [df dateFromString:origDate];
[df release];
NSDate *todayDate = [NSDate date];
double ti = [convertedDate timeIntervalSinceDate:todayDate];
ti = ti * -1;
if(ti < 1) {
return @"never";
} else if (ti < 60) {
return @"less than a minute ago";
} else if (ti < 3600) {
int diff = round(ti / 60);
return [NSString stringWithFormat:@"%d minutes ago", diff];
} else if (ti < 86400) {
int diff = round(ti / 60 / 60);
return[NSString stringWithFormat:@"%d hours ago", diff];
} else if (ti < 2629743) {
int diff = round(ti / 60 / 60 / 24);
return[NSString stringWithFormat:@"%d days ago", diff];
} else {
return @"never";
}
}

Reformat and rearrange dateString

I will answer in objective-C because i'm sure you can extract the swift out of it, here is a method that will react differently if the given date is earlier than today, today exactly, or a week from now, or month, or year(s).

+ (NSString*)cellDateFormatWithDate:(NSDate*)date{
NSCalendarUnit units = NSDayCalendarUnit | NSWeekOfYearCalendarUnit |
NSMonthCalendarUnit | NSYearCalendarUnit;

// if `date` is before "now" (i.e. in the past) then the components will be positive
NSDateComponents *components = [[NSCalendar currentCalendar] components:units
fromDate:date
toDate:[NSDate date]
options:0];

NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
if (components.year > 0) {
[formatter setDateFormat:@"dd/MM/yy"];
} else if (components.month > 0) {
[formatter setDateFormat:@"dd/MM/yy"];
} else if (components.weekOfYear > 0) {
[formatter setDateFormat:@"dd/MM HH:mm"];
} else if (components.day > 0) {
if (components.day > 1) {
[formatter setDateFormat:@"dd/MM HH:mm"];
} else {
[formatter setDateFormat:@"dd/MM HH:mm"];
}
} else {
[formatter setDateFormat:@"HH:mm"];
}

NSString *cellDate = [formatter stringFromDate:date];

return cellDate;
}

To fit your question, you just need to add an

NSString* relativeString;

and in each if/else, change it accordingly

relativeString = @"Today";
relativeString = @"Yesterday";
relativeString = @"A week ago";

and so on.

This other method does pretty much the same but with second/minute accuracy

+ (NSString *)dateDiff:(NSString *)origDate{
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setFormatterBehavior:NSDateFormatterBehavior10_4];

[df setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
NSDate *convertedDate = [df dateFromString:origDate];

NSDate *todayDate = [NSDate date];
double ti = [convertedDate timeIntervalSinceDate:todayDate];
ti = ti * -1;

if(ti < 1) {
return NSLocalizedString(@"REL_TIME_NOW", nil);
} else if (ti < 60) {
return NSLocalizedString(@"REL_TIME_LESS_THAN_MINUTE", nil);
} else if (ti < 3600) {
int diff = round(ti / 60);
if (diff < 2){
return [NSString stringWithFormat:NSLocalizedString(@"REL_TIME_MINUTE", nil), diff];
}else{
return [NSString stringWithFormat:NSLocalizedString(@"REL_TIME_MINUTES", nil), diff];
}
} else if (ti < 86400) {
int diff = round(ti / 60 / 60);
if (diff < 2){
return [NSString stringWithFormat:NSLocalizedString(@"REL_TIME_HOUR", nil), diff];
}else{
return [NSString stringWithFormat:NSLocalizedString(@"REL_TIME_HOURS", nil), diff];
}
} else {
int diff = round(ti / 60 / 60 / 24);
if (diff < 2){
return [NSString stringWithFormat:NSLocalizedString(@"REL_TIME_DAY", nil), diff];
}else{
return [NSString stringWithFormat:NSLocalizedString(@"REL_TIME_DAYS", nil), diff];
}
}
}

Though I can't be bothered renaming all my localized strings, they just show

"less than a minute ago"
"%d minute ago"
"%d minutes ago"
"%d hour ago

"
and so on



Related Topics



Leave a reply



Submit