32

我正在寻找一种模糊日期算法。我刚开始写一个,就意识到这是一项多么乏味的任务。它很快退化成许多可怕的代码来处理特殊情况,例如“昨天”、“上周”和“上个月末”之间的差异,所有这些都可以(在某些情况下)指同一天,但单独正确基于今天的日期。

我确信一定有一个开源的模糊日期格式化程序,但我找不到它。理想情况下,我想要使用 NSDate (OSX/iPhone) 及其格式化程序的东西,但这并不难。有谁知道模糊日期格式化程序采用相对于现在的任何时间段并返回一个字符串,例如(但不限于):

  • 几分钟前
  • 在最后五分钟
  • 今天早些时候
  • 今天早上
  • 昨晚
  • 上个星期
  • 上周三
  • 上月初
  • 去年六月
  • 几年前

在一个理想的世界中,我希望字符串尽可能丰富(即返回“Just a moment ago”的随机变体,例如“just now”)。

澄清。我正在寻找比基本的buckts和string更微妙的东西。我想要知道“昨天”和“上周三”都可以指同一时期但今天是星期四时只有一个是正确的。

4

14 回答 14

12

NSDateFormatter 中有一个属性-“doesRelativeDateFormatting”。它仅出现在 10.6/iOS4.0 及更高版本中,但它会将日期格式化为正确区域设置中的相对日期。

来自Apple 的文档

如果日期格式化程序使用相对日期格式化,它会在可能的情况下用表示相对日期的短语(例如“今天”或“明天”)替换其输出的日期部分。可用的短语取决于日期格式化程序的语言环境;而对于未来的日期,英语可能只允许“明天”,法语可能允许“后天后天”,如下例所示。

代码

以下代码将打印出给定语言环境的大量相关字符串。

NSLocale *locale = [NSLocale currentLocale];
//    NSLocale *locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"fr_FR"] autorelease];

NSDateFormatter *relativeDateFormatter = [[NSDateFormatter alloc] init];
[relativeDateFormatter setTimeStyle:NSDateFormatterNoStyle];
[relativeDateFormatter setDateStyle:NSDateFormatterMediumStyle];
[relativeDateFormatter setDoesRelativeDateFormatting:YES];
[relativeDateFormatter setLocale:locale];

NSDateFormatter *normalDateFormatter = [[NSDateFormatter alloc] init];
[normalDateFormatter setTimeStyle:NSDateFormatterNoStyle];
[normalDateFormatter setDateStyle:NSDateFormatterMediumStyle];
[normalDateFormatter setDoesRelativeDateFormatting:NO];
[normalDateFormatter setLocale:locale];

NSString * lastUniqueString = nil;

for ( NSTimeInterval timeInterval = -60*60*24*400; timeInterval < 60*60*24*400; timeInterval += 60.0*60.0*24.0 )
{
    NSDate * date = [NSDate dateWithTimeIntervalSinceNow:timeInterval];

    NSString * relativeFormattedString = [relativeDateFormatter stringForObjectValue:date];
    NSString * formattedString = [normalDateFormatter stringForObjectValue:date];

    if ( [relativeFormattedString isEqualToString:lastUniqueString] || [relativeFormattedString isEqualToString:formattedString] )
        continue;

    NSLog( @"%@", relativeFormattedString );
    lastUniqueString = relativeFormattedString;
}

笔记:

  • 不需要语言环境
  • 英语的替代品并不多。在撰写本文时,有:“昨天,今天,明天”。苹果未来可能会包括更多。
  • 更改语言环境并查看其他语言的可用内容很有趣(例如,法语比英语多一些)
  • 如果在 iOS 上,您可能需要订阅UIApplicationSignificantTimeChangeNotification

界面生成器

您可以在 Interface Builder 中设置“doesRelativeDateFormatting”属性:

  • 选择您的 NSDateFormatter 并选择 Inspector Palette 的“Identity Inspector”选项卡(最后一个 [command-6])。
  • 在名为“用户定义的运行时属性”的小节下,您可以为所选对象(在本例中为您的 NSDateFormatter 实例)上的键添加自己的值。添加“doesRelativeDateFormatting”,选择“Boolean”类型,并确保已选中。
  • 请记住:它可能看起来根本不起作用,但这可能是因为您的语言环境只有几个替代值。在确定是否设置不正确之前,请至少尝试选择昨天、今天和明天的日期。
于 2010-08-22T05:06:47.567 回答
9

这个问题应该让你开始。它有这个网站用来计算其相对时间的代码。它可能没有您想要的特定范围,但是一旦设置好它们就很容易添加。

于 2009-05-04T21:24:18.410 回答
7

您可能想查看我在下面粘贴的date_helper.rbdistance_of_time_in_words中的 Rail函数。

# File vendor/rails/actionpack/lib/action_view/helpers/date_helper.rb, line 59
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
 from_time = from_time.to_time if from_time.respond_to?(:to_time)
 to_time = to_time.to_time if to_time.respond_to?(:to_time)
 distance_in_minutes = (((to_time - from_time).abs)/60).round
 distance_in_seconds = ((to_time - from_time).abs).round

 I18n.with_options :locale => options[:locale], :scope => 'datetime.distance_in_words''datetime.distance_in_words' do |locale|
   case distance_in_minutes
     when 0..1
       return distance_in_minutes == 0 ?
              locale.t(:less_than_x_minutes, :count => 1) :
              locale.t(:x_minutes, :count => distance_in_minutes) unless include_seconds

       case distance_in_seconds
         when 0..4   then locale.t :less_than_x_seconds, :count => 5
         when 5..9   then locale.t :less_than_x_seconds, :count => 10
         when 10..19 then locale.t :less_than_x_seconds, :count => 20
         when 20..39 then locale.t :half_a_minute
         when 40..59 then locale.t :less_than_x_minutes, :count => 1
         else             locale.t :x_minutes,           :count => 1
       end

     when 2..44           then locale.t :x_minutes,      :count => distance_in_minutes
     when 45..89          then locale.t :about_x_hours,  :count => 1
     when 90..1439        then locale.t :about_x_hours,  :count => (distance_in_minutes.to_f / 60.0).round
     when 1440..2879      then locale.t :x_days,         :count => 1
     when 2880..43199     then locale.t :x_days,         :count => (distance_in_minutes / 1440).round
     when 43200..86399    then locale.t :about_x_months, :count => 1
     when 86400..525599   then locale.t :x_months,       :count => (distance_in_minutes / 43200).round
     when 525600..1051199 then locale.t :about_x_years,  :count => 1
     else                      locale.t :over_x_years,   :count => (distance_in_minutes / 525600).round
   end
 end
end
于 2009-05-04T21:35:15.607 回答
6

所以,这是我在 NSDate 上为那些仍然感兴趣的人写的类别。问题是其中一个变得有点不切实际的问题。它基本上是一个巨大的 switch 语句(尽管我在一系列级联 if() 中实现了它以使其更具可读性。

然后,对于每个时间段,我从一组随机的时间告诉方式中进行选择。

总而言之,这让我们的一些用户感到高兴,但我不确定这是否值得。

NSTimeInterval const kTenSeconds = (10.0f );
NSTimeInterval const kOneMinute = (60.0f);
NSTimeInterval const kFiveMinutes = (5.0f*60.0f);
NSTimeInterval const kFifteenMinutes = (15.0f*60.0f) ;
NSTimeInterval const kHalfAnHour = (30.0f*60.0f) ;
NSTimeInterval const kOneHour = 3600.0f;    // (60.0f * 60.0f);
NSTimeInterval const kHalfADay = (3600.0f * 12.0f);
NSTimeInterval const kOneDay = (3600.0f * 24.0f);
NSTimeInterval const kOneWeek = (3600.0f * 24.0f * 7.0f);

@implementation NSDate (Fuzzy)

-(NSString*)fuzzyStringRelativeToNow;
{
    static NSArray* secondsStrings;
    static NSArray* minuteStrings;
    static NSArray* fiveMinuteStrings;
    static NSArray* halfHourStrings;
    static NSArray* earlyMonthStrings;

    NSTimeInterval timeFromNow = [self timeIntervalSinceNow];
    if((timeFromNow < 0))       // In the past
    {
        timeFromNow = - timeFromNow;

        if ( (timeFromNow <  kTenSeconds))
        {
            if(!secondsStrings)
            {   
                secondsStrings = [[NSArray arrayWithObjects:@"just now",
                                                            //@"a few seconds ago",
                                                            //@"right this instant",
                                                            @"moments ago",
                                                            nil] retain];
            }

            unsigned int index = random() % ([secondsStrings count] - 1);
            return [secondsStrings objectAtIndex:index];
        }

        if ( (timeFromNow < kOneMinute))
        {
            if(!minuteStrings)
            {

                minuteStrings = [[NSArray arrayWithObjects:@"just now",
                                  @"very recently",
                                  @"in the last minute",
                                  nil] retain];
            }

            unsigned int index = random() % ([minuteStrings count] - 1);
            return [minuteStrings objectAtIndex:index];
        }

        if (timeFromNow < kFiveMinutes)
        {
            if(!fiveMinuteStrings)
            {
                fiveMinuteStrings = [[NSArray arrayWithObjects:@"just now",
                                      @"very recently",
                                      //@"in the last minute",
                                      @"a few minutes ago",
                                      //@"in the last five minutes",
                                      nil] retain];
            }
            unsigned int index = random() % ([fiveMinuteStrings count] - 1);
            return [fiveMinuteStrings objectAtIndex:index];
        }

        if (timeFromNow < kFifteenMinutes)
        {
            return @"in the last 15 minutes";
        }

        if (timeFromNow < kHalfAnHour)
        {
            if(!halfHourStrings)
            {
                halfHourStrings = [[NSArray arrayWithObjects:@"in the last half hour",
                                                            //@"in the last half an hour",
                                                            @"in the last 30 minutes",
                                                            //@"about half an hour ago",
                                                            @"fairly recently",
                                                            nil] retain];
            }
            unsigned int index = random() % ([halfHourStrings count] - 1);
            return [halfHourStrings objectAtIndex:index];
        }

        if (timeFromNow < kOneHour)
        {
            return @"in the last hour";
        }

        if ((timeFromNow < (kOneHour + kFiveMinutes)) && (timeFromNow > (kOneHour - kFiveMinutes)))
        {
            return @"about an hour ago";
        }

        if((timeFromNow < ((kOneHour*2.0f) + kFiveMinutes ))&& (timeFromNow > ((kOneHour*2.0f) - kFiveMinutes)))
        {
            return @"a couple of hours ago";
        }

        // Now we're over an hour, we need to calculate a few specific dates to compare against

        NSDate *today = [NSDate date];

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

        NSUInteger unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
        NSDateComponents* todayComponents = [gregorian components:unitFlags fromDate:today];

        todayComponents.hour = 12;

        NSDate* noonToday = [gregorian dateFromComponents:todayComponents];


        NSTimeInterval timeSinceNoonToday = [self timeIntervalSinceDate:noonToday];

        if (timeSinceNoonToday > 0)                         // sometime since noon
        {
            if (timeSinceNoonToday > kOneHour * 9)          // i.e. after 9pm today
                return @"earlier tonight";
            if (timeSinceNoonToday > kOneHour * 7)          // i.e. after 7pm today
                return @"earlier this evening";
            if (timeSinceNoonToday < kOneHour * 1)          // between noon and 1pm
                return @"early this afternoon";

            return @"this afternoon";
        }


        NSTimeInterval timeSinceMidnight = kHalfADay -timeSinceNoonToday;   // Note sign is reversed.   

        if ((timeSinceNoonToday < 0) & (timeSinceNoonToday > -kHalfADay))       // between midnight and noon today
        {
            if (timeSinceMidnight < kFiveMinutes)
                return @"around midnight";
            if (timeSinceMidnight < kOneHour * 2)           // up to 2am
                return @"very early this morning";
            if (timeSinceMidnight < kOneHour * 5)           // up to 5am
                return @"early this morning";
            else if (timeSinceMidnight < kOneHour * 11)
                return @"late this morning";
            else
                return @"this morning";
        }


        // NSTimeInterval timeSinceNoonYesterday = timeSinceNoonToday - kOneDay;

        // timeSinceMidnight = -timeSinceMidnight;

        if (timeSinceMidnight < kOneHour * 24)      // not the day before...
        {

            if (timeSinceMidnight < kFiveMinutes)
                return @"around midnight";
            if (timeSinceMidnight < kFifteenMinutes)
                return @"just before midnight";
            if (timeSinceMidnight < kOneHour * 2)           // after 10pm
                return @"late last night";
            if (timeSinceMidnight < kOneHour * 5)           // After 7
                return @"yesterday evening";
            else if (timeSinceMidnight < kOneHour * 7)
                return @"yesterday evening";                // after 5pm
            else if (timeSinceMidnight < kOneHour * 7)
                return @"yesterday evening";                // after 5pm
            else if (timeSinceMidnight < kOneHour * 10)
                return @"yesterday afternoon";              // after 5pm
            else if (timeSinceMidnight < kOneHour * 12)
                return @"early yesterday afternoon";        // before 1pm
            else if (timeSinceMidnight < kOneHour * 13)
                return @"late yesterday morning";           // after 11m
            else if (timeSinceMidnight < kOneHour * 17)
                return @"yesterday morning";                
            else 
                return @"early yesterday morning";
        }

        NSDateFormatter* formatter = [[[NSDateFormatter alloc] init] autorelease];

        int integerSeconds = timeSinceMidnight;
        int integerDay = kOneDay;
        int secondsIntoDay = integerSeconds % integerDay;
        NSString* formatString = @"last %@";

        if (timeFromNow < kOneWeek)
        {
            if (secondsIntoDay < kFifteenMinutes)
                formatString = @"around midnight on %@";
            //else if (secondsIntoDay < kFifteenMinutes)
            //  formatString = @"just before midnight on %@";
            else if (secondsIntoDay < kOneHour * 2)         // after 10pm
                formatString = @"late on %@ night";
            else if (secondsIntoDay < kOneHour * 5)         // After 7
                formatString = @"on %@ evening";
            else if (secondsIntoDay < kOneHour * 10)
                formatString = @"on %@ afternoon";              // after 5pm
            else if (secondsIntoDay < kOneHour * 12)
                formatString = @"early on %@ afternoon";        // before 1pm
            else if (secondsIntoDay < kOneHour * 13)
                formatString = @"late on %@ morning";           // after 11am
            else if (secondsIntoDay < kOneHour * 17)
                formatString = @"on %@ morning";                
            else if (secondsIntoDay < kOneHour * 24)        // not the day before...
                formatString = @"early on %@ morning";

            [formatter setDateFormat:@"EEEE"];  /// EEEE is long format of day of the week see: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
            return [NSString stringWithFormat:formatString, [formatter stringFromDate: self]]; 
        }

        //formatString = @"on %@ the week before last";
        /*if (secondsIntoDay < kOneHour * 2)            // after 10pm
            formatString = @"early on %@ the week before last";
        else if (timeSinceMidnight > kOneHour * 13)
            formatString = @"late on %@ the week before last";          // after 11m*/

        //if (timeFromNow < kOneWeek * 2)
        //{
        //  [formatter setDateFormat:@"EEE"];           /// EEE is short format of day of the week see: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
        //  return [NSString stringWithFormat:formatString, [formatter stringFromDate: self]]; 
        //}

        if (timeFromNow < kOneWeek * 2)
            {
            return @"the week before last";
            }

        NSDateComponents* myComponents = [gregorian components:unitFlags fromDate:self];

        int monthsAgo = myComponents.month - todayComponents.month;

        int yearsAgo = myComponents.year - todayComponents.year;
        if (yearsAgo == 0)
        {
            if (monthsAgo == 0)
            {
                if(myComponents.day > 22)
                    return @"late this month";
                if(myComponents.day < 7)
                {

                    if(!earlyMonthStrings)
                    {   
                        earlyMonthStrings = [[NSArray arrayWithObjects:@"earlier this month",
                                                                       //@"at the beginning of the month",
                                                                       @"early this month",
                                                                       nil] retain];
                    }

                    unsigned int index = random() % ([earlyMonthStrings count] - 1);
                    return [earlyMonthStrings objectAtIndex:index];
                }
                return @"earlier this month";
            }

            if (monthsAgo == 1)
            {
                if(myComponents.day > 22)
                    return @"late last month";
                if(myComponents.day < 7)
                    return @"early last month";
                return @"last month";
            }

            formatString  = @"in %@ this year";
            /*if(myComponents.day > 22)
                formatString  = @"late in %@ this year";
            if(myComponents.day < 7)
                formatString  = @"early in %@ this year";*/


            [formatter setDateFormat:@"MMMM"];          /// MMM is longformat of month see: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
            return [NSString stringWithFormat:formatString, [formatter stringFromDate: self]];  
        }

        if (yearsAgo == 1)
        {
            formatString  = @"in %@ last year";
            /*if(myComponents.day > 22)
                formatString  = @"late in %@ last year";
            if(myComponents.day < 7)
                formatString  = @"late in %@ last year";*/


            [formatter setDateFormat:@"MMM"];           /// MMM is longformat of month see: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
            return [NSString stringWithFormat:formatString, [formatter stringFromDate: self]];  
        }

        // int daysAgo = integerSeconds / integerDay;

    // Nothing yet...
        [formatter setDateStyle:kCFDateFormatterMediumStyle];
        //[formatter setTimeStyle:kCFDateFormatterShortStyle];

        return [NSString stringWithFormat:@"on %@",[formatter stringFromDate: self]];

    }
    else
    if(timeFromNow > 0) // The future
    {
        AICLog(kErrorLogEntry, @"FuzzyDates: Time marked as in the future: referenced date is %@, local time is %@", self, [NSDate date]);
        return @"moments ago";

    }
    else
        return @"right now";    // this seems unlikely.

    return [self description];  // should never get here.
}

抱歉这么久才发这个。。。

于 2011-06-29T15:37:18.677 回答
6

这是基于 Pretty and Humane 日期和时间线程中的代码。我添加了对“上周一下午 5 点”的处理,因为我在 x 天前更喜欢它。这可以处理长达几个世纪的过去和未来。我热衷于国际化方面,所以这最终需要做更多的工作。计算采用当地时区。

public static class DateTimePretty
{
    private const int SECOND = 1;
    private const int MINUTE = 60 * SECOND;
    private const int HOUR = 60 * MINUTE;
    private const int DAY = 24 * HOUR;
    private const int WEEK = 7 * DAY;
    private const int MONTH = 30 * DAY;

    private const int YEAR = 365;

    const string now = "just now";
    const string secondsFuture = "in {0} seconds", secondsPast = "{0} seconds ago";
    const string minuteFuture = "in about a minute", minutePast = "about a minute ago";
    const string minutesFuture = "in about {0} minutes", minutesPast = "about {0} minutes ago";
    const string hourFuture = "in about an hour", hourPast = "about an hour ago";
    const string hoursFuture = "in about {0} hours", hoursPast = "about {0} hours ago";
    const string tomorrow = "tomorrow, {0}", yesterday = "yesterday, {0}";
    const string nextDay = "{0}", nextWeekDay = "next {0}", lastDay = "last {0}";
    //const string daysFuture = "in about {0} days", daysPast = "about {0} days ago";
    const string weekFuture = "in about a week", weekPast = "about a week ago";
    const string weeksFuture = "in about {0} weeks", weeksPast = "about {0} weeks ago";
    const string monthFuture = "in about a month", monthPast = "about a month ago";
    const string monthsFuture = "in about {0} months", monthsPast = "about {0} months ago";
    const string yearFuture = "in about a year", yearPast = "about a year ago";
    const string yearsFuture = "in about {0} years", yearsPast = "about {0} years ago";
    const string centuryFuture = "in about a century", centuryPast = "about a century ago";
    const string centuriesFuture = "in about {0} centuries", centuriesPast = "about {0} centuries ago";

    /// <summary>
    /// Returns a pretty version of the provided DateTime: "42 years ago", or "in 9 months".
    /// </summary>
    /// <param name="dateTime">DateTime in local time format, not Utc</param>
    /// <returns>A pretty string</returns>
    public static string GetPrettyDate(DateTime dateTime)
    {
        DateTime dateTimeNow = DateTime.Now;
        bool isFuture = (dateTimeNow.Ticks < dateTime.Ticks);
        var ts = isFuture ? new TimeSpan(dateTime.Ticks - dateTimeNow.Ticks) : new TimeSpan(dateTimeNow.Ticks - dateTime.Ticks);

        double delta = ts.TotalSeconds;

        if (delta < 10)
            return now;
        if (delta < 1 * MINUTE)
            return isFuture ? string.Format(secondsFuture, ts.Seconds) : string.Format(secondsPast, ts.Seconds);
        if (delta < 2 * MINUTE)
            return isFuture ? minuteFuture : minutePast;
        if (delta < 45 * MINUTE)
            return isFuture ? string.Format(minutesFuture, ts.Minutes) : string.Format(minutesPast, ts.Minutes);
        if (delta < 2 * HOUR)
            return isFuture ? hourFuture : hourPast;
        if (delta < 7 * DAY)
        {
            string shortTime = DateTimeFormatInfo.CurrentInfo.ShortTimePattern;
            string shortWeekdayTime = "dddd, " + shortTime;
            int dtDay = (int) dateTime.DayOfWeek;
            int nowDay = (int) dateTimeNow.DayOfWeek;
            if (isFuture)
            {
                if (dtDay == nowDay)
                {
                    if (delta < DAY)
                        return string.Format(hoursFuture, ts.Hours);
                    else
                        return string.Format(nextWeekDay, dateTime.ToString(shortWeekdayTime));
                }
                else if (dtDay - nowDay == 1 || dtDay - nowDay == -6)
                    return string.Format(tomorrow, dateTime.ToString(shortTime));
                else
                    return string.Format(nextDay, dateTime.ToString(shortWeekdayTime));
            }
            else
            {
                if (dtDay == nowDay)
                {
                    if (delta < DAY)
                        return string.Format(hoursPast, ts.Hours);
                    else
                        return string.Format(lastDay, dateTime.ToString(shortWeekdayTime));
                }
                else if (nowDay - dtDay == 1 || nowDay - dtDay == -6)
                    return string.Format(yesterday, dateTime.ToString(shortTime));
                else
                    return string.Format(lastDay, dateTime.ToString(shortWeekdayTime));
            }
        }
        //if (delta < 7 * DAY)
        //    return isFuture ? string.Format(daysFuture, ts.Days) : string.Format(daysPast, ts.Days);
        if (delta < 4 * WEEK)
        {
            int weeks = Convert.ToInt32(Math.Floor((double) ts.Days / 30));
            if (weeks <= 1)
                return isFuture ? weekFuture : weekPast;
            else
                return isFuture ? string.Format(weeksFuture, weeks) : string.Format(weeksPast, weeks);
        }
        if (delta < 12 * MONTH)
        {
            int months = Convert.ToInt32(Math.Floor((double) ts.Days / 30));
            if (months <= 1)
                return isFuture ? monthFuture : monthPast;
            else
                return isFuture ? string.Format(monthsFuture, months) : string.Format(monthsPast, months);
        }

        // Switch to days to avoid overflow
        delta = ts.TotalDays;
        if (delta < 100 * YEAR)
        {
            int years = Convert.ToInt32(Math.Floor((double) ts.TotalDays / 365.25));
            if (years <= 1)
                return isFuture ? yearFuture : yearPast;
            else
                return isFuture ? string.Format(yearsFuture, years) : string.Format(yearsPast, years);
        }
        else
        {
            int centuries = Convert.ToInt32(Math.Floor((double) ts.TotalDays / 365.2425));
            if (centuries <= 1)
                return isFuture ? centuryFuture : centuryPast;
            else
                return isFuture ? string.Format(centuriesFuture, centuries) : string.Format(centuriesPast, centuries);
        }
    }
}
于 2011-09-05T03:35:10.847 回答
3

我不知道你为什么说这将是一种可怕的编码实践。每个返回字符串实际上都是父集的一个子集,因此您可以非常优雅地在 if/elseif 链中执行此操作。

if timestamp < 5sec
    "A moment ago"
elseif timestamp < 5min 
    "Few minutes ago"
elseif timestamp < 12hr && timestamp < noon
    "Today Morning"
...
elseif timestamp < 1week 
    "Few days ago"
elseif timestamp < 1month
    "Few weeks ago"
elseif timestamp < 6month
    "Few Months ago" 
...
else
    "Really really long time ago"
于 2009-05-04T21:31:03.167 回答
1

根据我的经验,这些类型的日期生成器根本不是“模糊的”。事实上,它们只是一堆基于时间段的 if 语句。例如,任何小于 30 秒的时间是“片刻前”,360 到 390 天是“一年前”等。其中一些将使用目标日期来计算特殊名称(六月、星期三等)。很抱歉打破了你的幻想。

于 2009-05-04T21:26:23.910 回答
1

不用说(但我还是会说)不要使用每年减少 365 天的 where 循环,即使在 366 天闰年(否则你会发现自己处于 Zune 开发人员的行列)

这是 ac# 版本:

http://tiredblogger.wordpress.com/2008/08/21/creating-twitter-esque-relative-dates-in-c/

于 2009-05-04T21:34:30.973 回答
1

我知道这样的表达时间最近变得非常流行,但请考虑将其作为切换相对“模糊”日期和正常绝对日期的选项。

例如,知道一条评论是在 5 分钟前发表的很有用,但告诉我评论 A 是 4 小时前,评论 B 是 9 小时前,当时是上午 11 点,我宁愿知道评论 A 是今天早上有人醒来时写的,评论 B 是有人熬夜写的(假设我知道他们在我的时区)。

- 编辑:仔细观察您的问题,您似乎通过引用一天中的时间而不是“X 前”在某种程度上避免了这种情况,但另一方面,如果用户处于不同的时间,您可能会给人一种错误的印象区域,因为您的“今天早上”可能是相关用户的半夜。

根据其他用户的时区,用一天中的相对时间来增加时间可能很酷,但这假设用户愿意提供它并且它是正确的。

于 2009-05-04T22:37:06.970 回答
1

我对另一个问题的解决方案不满意。所以我自己使用日期时间类。海事组织,它的清洁剂。在我的测试中,它像我想要的那样工作。希望这可以帮助某人。

DateTime now = DateTime.Now;

long nowticks = now.Ticks;
long thenticks = dt.Ticks;

long diff = nowticks - thenticks;

DateTime n = new DateTime(diff);

if (n.Year > 1)
{
    return n.Year.ToString() + " years ago";
}
else if (n.Month > 1)
{
    return n.Month.ToString() + " months ago";
}
else if (n.Day > 1)
{
    return n.Day.ToString() + " days ago";
}
else if (n.Hour > 1)
{
    return n.Hour.ToString() + " hours ago";
}
else if (n.Minute > 1)
{
    return n.Minute.ToString() + " minutes ago";
}
else
{
    return n.Second.ToString() + " seconds ago";
}
于 2012-04-09T10:40:10.340 回答
0

这几乎总是使用巨大的 switch 语句来完成,而且实现起来很简单。

请记住以下几点:

  • 始终首先测试最小的时间跨度
  • 不要忘记保持字符串可本地化。
于 2009-05-04T21:27:23.143 回答
0

您可能会发现timeago 的源代码很有用。该插件的描述是“一个 jQuery 插件,可以轻松支持自动更新模糊时间戳(例如“4 分钟前”或“大约 1 天前”)。

它本质上是 Raildistance_of_time_in_words函数的 JavaScript 端口,塞进了一个 jQuery 插件。

于 2009-05-04T21:31:45.693 回答
0

我的公司有这个 .NET 库,它可以做一些你想做的事情,因为它可以进行非常灵活的日期时间解析(包括一些相对格式),但它只做非相对输出。

于 2009-05-04T22:13:04.720 回答
0

查看 Chrono 以获取 Javascript 启发式日期解析器。

Chrono 支持大多数日期和时间格式,例如:

Today, Tomorrow, Yesterday, Last Friday, etc
17 August 2013 - 19 August 2013
This Friday from 13:00 - 16.00
5 days ago
Sat Aug 17 2013 18:40:39 GMT+0900 (JST)
2014-11-30T08:15:30-05:30

https://github.com/wanait/chrono

于 2016-05-12T05:44:09.673 回答