Objective-C中的模糊日期算法

11

我想为iPhone上的Objective-C编写一个模糊日期方法来计算日期。这里有一个流行的解释:

在C#中计算相对时间

然而,它缺少参数。如何在Objective-C中使用它?谢谢。

const int SECOND = 1;
const int MINUTE = 60 * SECOND;
const int HOUR = 60 * MINUTE;
const int DAY = 24 * HOUR;
const int MONTH = 30 * DAY;

if (delta < 1 * MINUTE)
{
  return ts.Seconds == 1 ? "one second ago" : ts.Seconds + " seconds ago";
}
if (delta < 2 * MINUTE)
{
  return "a minute ago";
}
if (delta < 45 * MINUTE)
{
  return ts.Minutes + " minutes ago";
}
if (delta < 90 * MINUTE)
{
  return "an hour ago";
}
if (delta < 24 * HOUR)
{
  return ts.Hours + " hours ago";
}
if (delta < 48 * HOUR)
{
  return "yesterday";
}
if (delta < 30 * DAY)
{
  return ts.Days + " days ago";
}
if (delta < 12 * MONTH)
{
  int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30));
  return months <= 1 ? "one month ago" : months + " months ago";
}
else
{
  int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365));
  return years <= 1 ? "one year ago" : years + " years ago";
}
4个回答

23

在Cocoa中,日期是使用NSDate类表示的。 NSDate实现了一个方便的方法来获取两个日期实例之间以秒为单位的差值,timeIntervalSinceDate:。该方法通过调用NSDate实例,并以另一个NSDate对象作为参数。它返回一个NSTimeInterval(这是double类型的typedef),代表两个日期之间的秒数。

鉴于此,将上述代码适配到Objective-C / Cocoa上下文将非常简单。由于NSDate计算的差值以秒为单位给出,因此,在给定两个日期的情况下,您可以轻松地调整上面的代码:

//Constants
#define SECOND 1
#define MINUTE (60 * SECOND)
#define HOUR (60 * MINUTE)
#define DAY (24 * HOUR)
#define MONTH (30 * DAY)

- (NSString*)timeIntervalWithStartDate:(NSDate*)d1 withEndDate:(NSDate*)d2
{
    //Calculate the delta in seconds between the two dates
    NSTimeInterval delta = [d2 timeIntervalSinceDate:d1];

    if (delta < 1 * MINUTE)
    {
        return delta == 1 ? @"one second ago" : [NSString stringWithFormat:@"%d seconds ago", (int)delta];
    }
    if (delta < 2 * MINUTE)
    {
        return @"a minute ago";
    }
    if (delta < 45 * MINUTE)
    {
        int minutes = floor((double)delta/MINUTE);
        return [NSString stringWithFormat:@"%d minutes ago", minutes];
    }
    if (delta < 90 * MINUTE)
    {
        return @"an hour ago";
    }
    if (delta < 24 * HOUR)
    {
        int hours = floor((double)delta/HOUR);
        return [NSString stringWithFormat:@"%d hours ago", hours];
    }
    if (delta < 48 * HOUR)
    {
        return @"yesterday";
    }
    if (delta < 30 * DAY)
    {
        int days = floor((double)delta/DAY);
        return [NSString stringWithFormat:@"%d days ago", days];
    }
    if (delta < 12 * MONTH)
    {
        int months = floor((double)delta/MONTH);
        return months <= 1 ? @"one month ago" : [NSString stringWithFormat:@"%d months ago", months];
    }
    else
    {
        int years = floor((double)delta/MONTH/12.0);
        return years <= 1 ? @"one year ago" : [NSString stringWithFormat:@"%d years ago", years];
    }
}

然后将通过传递开始和结束的NSDate对象作为参数来调用它,并返回一个包含时间间隔的NSString


3
这个实现的唯一问题是它没有区分一天中的24小时和日历上的一天。比如,如果我在比较晚上11点和凌晨2点的时间差,应该显示为“昨天”,而不是“3小时前”。可以查看NSCalendar及其伴随类NSDateComponents。 - retainCount

1
作为替代方案,您可以通过依赖从两个日期之间获取的日历组件来避免容易出错的日历算术:
NSDate *nowDate =    [[NSDate alloc] init];
NSDate *targetDate = nil; // some other date here of your choosing, obviously nil isn't going to get you very far

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSUInteger unitFlags = NSMonthCalendarUnit | NSWeekCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit;
NSDateComponents *components = [gregorian components:unitFlags
                                            fromDate:dateTime
                                              toDate:nowDate options:0];
NSInteger months = [components month];
NSInteger weeks = [components week];
NSInteger days = [components day];
NSInteger hours = [components hour];
NSInteger minutes = [components minute];

关键是设置单位标志 - 这允许您设置要将日期/时间分解为哪些时间单位。如果您只想要小时,则会设置NSHourCalendarUnit,随着您的日期之间的距离增加,该值将继续增加,因为没有更大的单位开始递增。
一旦您获得了组件,您可以根据自己的选择进行逻辑处理,例如修改@alex的条件流程。
这就是我凑在一起的内容:
if (months > 1) {
    // Simple date/time
    if (weeks >3) {
        // Almost another month - fuzzy
        months++;
    }
    return [NSString stringWithFormat:@"%ld months ago", (long)months];
}
else if (months == 1) {
    if (weeks > 3) {
        months++;
        // Almost 2 months
        return [NSString stringWithFormat:@"%ld months ago", (long)months];
    }
    // approx 1 month
    return [NSString stringWithFormat:@"1 month ago"];
}
// Weeks
else if (weeks > 1) {
    if (days > 6) {
        // Almost another month - fuzzy
        weeks++;
    }
    return [NSString stringWithFormat:@"%ld weeks ago", (long)weeks];
}
else if (weeks == 1 ||
         days > 6) {
    if (days > 6) {
        weeks++;
        // Almost 2 weeks
        return [NSString stringWithFormat:@"%ld weeks ago", (long)weeks];
    }
    return [NSString stringWithFormat:@"1 week ago"];
}
// Days
else if (days > 1) {
    if (hours > 20) {
        days++;
    }
    return [NSString stringWithFormat:@"%ld days ago", (long)days];
}
else if (days == 1) {
    if (hours > 20) {
        days++;
        return [NSString stringWithFormat:@"%ld days ago", (long)days];
    }
    return [NSString stringWithFormat:@"1 day ago"];
}
// Hours
else if (hours > 1) {
    if (minutes > 50) {
        hours++;
    }
    return [NSString stringWithFormat:@"%ld hours ago", (long)hours];
}
else if (hours == 1) {
    if (minutes > 50) {
        hours++;
        return [NSString stringWithFormat:@"%ld hours ago", (long)hours];
    }
    return [NSString stringWithFormat:@"1 hour ago"];
}
// Minutes
else if (minutes > 1) {
    return [NSString stringWithFormat:@"%ld minutes ago", (long)minutes];
}
else if (minutes == 1) {
    return [NSString stringWithFormat:@"1 minute ago"];
}
else if (minutes < 1) {
    return [NSString stringWithFormat:@"Just now"];
}

1

你可以使用timeIntervalSinceDate:方法获取两个NSDate对象之间的差值,这将给出以秒为单位的差值。

通过除以适当的数量,你可以计算出分钟/小时/天/月/年。



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接