代码之家  ›  专栏  ›  技术社区  ›  Rog

模糊数据算法

  •  32
  • Rog  · 技术社区  · 15 年前

    我在找一个模糊日期算法。我刚开始写一本书,意识到这是一项多么乏味的工作。为了应付“昨天”、“上周”和“上月下旬”之间的差异等特殊情况,它很快就退化为许多可怕的代码,这些代码(在某些情况下)都可以指同一天,但根据今天的日期,它们各自是正确的。

    我确信一定有一个开源的模糊日期格式化程序,但我找不到它。理想情况下,我希望使用nsdate(osx/iphone)及其格式化程序,但这并不困难。是否有人知道模糊日期格式化程序会占用相对于现在的任何时间段并返回字符串,例如(但不限于):

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

    在理想的世界中,我希望字符串尽可能丰富(即返回“刚才”的随机变量,如“刚才”)。

    澄清。我在找一些比基本的雄鹿和弦更微妙的东西。我想知道“昨天”和“上星期三”都可以指同一时期,但只有一个是正确的,当今天是星期四。

    14 回复  |  直到 8 年前
        1
  •  9
  •   Community CDub    7 年前

    This question should get you started. 它有这个站点用来计算其相对时间的代码。它可能没有您想要的特定范围,但是一旦您设置好,它们就可以很容易地添加。

        2
  •  12
  •   Michael Bishop    14 年前

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

    Apple's Documentation :

    如果日期格式化程序使用相对日期 格式,如果可能,它将替换 其输出的日期组件 一个短语,如“今日”或 __明日___ 日期。可用短语取决于 日期格式化程序的区域设置; 鉴于,对于未来的日期, 英语只能允许__明天,__ 法语允许在 后天,如图所示 以下示例。

    代码

    下面的代码将打印出给定区域设置的大量相对字符串。

    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并 选择“身份检查器”选项卡 检查面板(最后一个 一个[命令-6])。
    • 在名为“用户”的小节下 定义的运行时属性”,您可以 为所选对象上的键添加您自己的值(在本例中为nsdateFormatter实例)。添加 “DoesRelativeDateFormatting”,选择 一个“布尔”类型,并确保 选中的。
    • 记得 :它看起来可能根本不起作用,但这可能是因为您的区域设置只有几个替代值。在决定是否设置正确之前,请至少为昨天、今天和明天确定一个日期。
        3
  •  7
  •   Andrew Cholakian    15 年前

    你可能想看看铁路 distance_of_time_in_words 功能在 date_helper.rb ,我贴在下面。

    # 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
    
        4
  •  6
  •   Rog    13 年前

    所以,这里是我在nsdate上为那些仍然感兴趣的人写的类别。问题是其中一个变得有点不切实际。它基本上是一个巨大的开关语句(尽管我在一系列级联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.
    }
    

    抱歉,发布这个邮件花了这么长时间…

        5
  •  6
  •   Dirk Bester    13 年前

    这是基于漂亮和人性化的日期和时间线程中的代码。我增加了“上星期一下午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);
            }
        }
    }
    
        6
  •  3
  •   The Unknown    15 年前

    我不知道你为什么说这将是一个可怕的编码实践。每个返回字符串实际上都是父集合的一个子集,因此您可以在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"
    
        7
  •  1
  •   Craig    15 年前

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

        8
  •  1
  •   missaghi    15 年前

    不用说(但我还是要说),不要使用一个每年减少365天的where循环,即使是在366天的闰年(或者你会发现自己处于zune开发者的行列中)。

    以下是C版本:

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

        9
  •  1
  •   pimlottc    15 年前

    我知道这样的表达时间最近很流行,但是请考虑让它成为一个选择,切换到相对的“模糊”日期和正常的绝对日期。

    例如,知道5分钟前有一条评论是有用的,但告诉我评论A是4小时前的,而评论B是9小时前的11点,我更愿意知道评论A是今早有人醒来时写的,评论B是有人熬夜写的(假设我知道他们在我的时区)。e)。

    —— 编辑:仔细观察你的问题,你似乎在某种程度上避免了这个问题,因为你提到的是一天中的某个时间而不是“x之前”,但另一方面,如果用户在不同的时区,你可能会给人一个错误的印象,因为你的“今早”可能是相关用户的午夜。

    根据另一个用户的时区,用一天中的相对时间来增加时间可能很酷,但前提是用户愿意提供时间,并且时间是正确的。

        10
  •  1
  •   Mahmood    12 年前

    我对另一个问题的解决方案不满意。所以我用了日期时间课。IMO,它的清洁剂。在我的测试中,它像我想要的那样工作。希望这能帮助别人。

    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";
    }
    
        11
  •  0
  •   rein    15 年前

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

    请记住以下几点:

    • 总是先测试最小的时间跨度
    • 别忘了保持字符串的可本地化。
        12
  •  0
  •   Zack The Human Kunal    15 年前

    你可以找到 source from timeago 有用的。插件的描述是“一个jquery插件,它可以很容易地支持自动更新模糊时间戳(例如,“4分钟前”或“大约1天前”)。

    它本质上是Rail的一个javascript端口 distance_of_time_in_words 函数被塞进jquery插件中。

        13
  •  0
  •   BCS    15 年前

    我公司有 this .NET library 这可以实现一些您想要的功能,因为它可以非常灵活地进行日期时间分析(包括一些相对格式),但它只执行非相对输出。

        14
  •  0
  •   Nick Woodhams    8 年前

    查看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/wanasit/chrono