سؤال

أنا أبحث عن غامض تاريخ الخوارزمية.لقد بدأت في كتابة واحدة و أدركت ما مهمة شاقة عليه.فإنه سرعان ما تحولت إلى الكثير من البشعين البرمجية للتعامل مع الحالات الخاصة مثل الفرق بين "أمس" ، "آخر الأسبوع" و "أواخر الشهر الماضي" والتي يمكن أن (في بعض الحالات) راجع نفس اليوم ولكن بشكل فردي الصحيح استنادا إلى تاريخ اليوم.

أنا متأكد من يجب أن يكون هناك مفتوح المصدر غامض تاريخ المنسق ولكن أنا لا يمكن العثور عليه.من الناحية المثالية أريد شيئا استخدام NSDate (OSX/اي فون) و formatters ولكن هذا ليس من الصعب بعض الشيء.لا أحد يعرف من غامض تاريخ المنسق اتخاذ أي الفترة الزمنية النسبية إلى الآن والعودة سلسلة مثل (ولكن ليس على سبيل الحصر):

  • قبل لحظات قليلة
  • في آخر خمس دقائق
  • في وقت سابق اليوم
  • هذا الصباح
  • الليلة الماضية
  • الأسبوع الماضي
  • يوم الأربعاء الماضي
  • في أوائل الشهر الماضي
  • يونيو من العام الماضي
  • بضع سنوات مضت ،

في عالم مثالي أود السلسلة أن تكون غنية ممكن (أيالعودة عشوائية المتغيرات في "منذ قليل" مثل "الآن").

الإيضاح.أنا أبحث عن شيء أكثر دهاء مما الأساسية buckts والسلاسل.أريد شيئا أن يعرف "أمس" و "يوم الأربعاء الماضي" على حد سواء يمكن أن تشير إلى نفس الفترة ولكن واحد فقط هو الصحيح عندما اليوم هو يوم الخميس.

هل كانت مفيدة؟

المحلول

هذا السؤال يجب أن يبدأ. يحتوي على الكود الذي يستخدمه هذا الموقع لحساب الوقت النسبي.قد لا يحتوي على النطاقات المحددة التي تريدها، ولكن من السهل إضافتها بمجرد الانتهاء من إعدادها.

نصائح أخرى

هناك خاصية في NSDateFormatter - "doesRelativeDateFormatting".فإنه يظهر فقط في 10.6/iOS4.0 و في وقت لاحق لكنه تنسيق تاريخ في النسبية التاريخ في الصحيح لغة.

من أبل الوثائق:

إذا كان تاريخ المنسق يستخدم النسبية تاريخ التنسيق, حيث من الممكن فإنه يستبدل تاريخ مكون من انتاجها مع عبارة مثل "اليوم" أو "غدا"—أن يشير إلى النسبية تاريخ.المتاحة العبارات تعتمد على لغة التاريخ المنسق;بينما التواريخ في المستقبل ، الإنجليزية قد تسمح فقط "الغد" ، الفرنسية قد تسمح "اليوم بعد بعد غد" كما هو موضح في المثال التالي.

رمز

وفيما يلي التعليمات البرمجية التي سيتم طباعة عدد كبير من النسبية سلاسل معين لغة.

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;
}

ملاحظات:

  • لغة غير مطلوب
  • هناك غير أن العديد من التبديلات من أجل الإنجليزية.في وقت كتابة هذا التقرير هناك هي:"أمس واليوم وغدا".أبل قد تشمل أكثر في المستقبل.
  • انها متعة تغيير لغة ومعرفة ما هو متاح في اللغات الأخرى (الفرنسية لديها عدد قليل من أكثر من اللغة الإنجليزية ، على سبيل المثال)
  • إذا على دائرة الرقابة الداخلية ، قد ترغب في الاشتراك UIApplicationSignificantTimeChangenotification

واجهة البناء

يمكنك تعيين "doesRelativeDateFormatting" الملكية في واجهة البناء:

  • حدد NSDateFormatter ، اختيار "هوية المفتش" علامة التبويب المفتش لوحة (آخر واحد [الأمر-6]).
  • تحت القسم الفرعي المسمى "المستخدم تحديد وقت التشغيل سمات" ، يمكنك إضافة قيمة مفتاح على الكائن المحدد (في هذه الحالة ، NSDateFormatter سبيل المثال).إضافة "doesRelativeDateFormatting" ، اختر و "منطقية" نوع, و تأكد من انها التحقق.
  • تذكر:قد يبدو أنه لم ينجح في كل شيء ، لكن ربما لأن هناك فقط عدد قليل من استبدال قيم الإعدادات المحلية الخاصة بك.حاول على الأقل من تاريخ أمس واليوم وغدا قبل أن تقرر إذا كان لا إقامة الحق.

قد ترغب في إلقاء نظرة على Rail's 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

لذا، هذه هي الفئة التي كتبتها على NSDate لأولئك الذين ما زالوا مهتمين.المشكلة هي واحدة من تلك التي تصبح خيالية بعض الشيء.إنها في الأساس بيان تبديل ضخم (على الرغم من أنني قمت بتطبيقه في سلسلة من if()s المتتالية لإبقائه أكثر قابلية للقراءة.

لكل فترة زمنية أقوم بالاختيار من بين مجموعة عشوائية من الطرق لمعرفة الوقت.

وبشكل عام، أسعد هذا عددًا قليلاً من مستخدمينا ولكني لست متأكدًا من أنه كان يستحق كل هذا الجهد.

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 مساءً"، لأنني أحب ذلك منذ أكثر من 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);
        }
    }
}

لست متأكدًا من سبب قولك إنها ستكون ممارسة ترميز فظيعة.كل سلسلة من السلاسل المرجعة هي في الواقع مجموعة فرعية من المجموعة الأصلية، لذا يمكنك القيام بذلك بأناقة تامة في سلسلة 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"

في تجربتي، هذه الأنواع من مولدات التاريخ ليست "غامضة" على الإطلاق.في الواقع، فهي مجرد مجموعة من النطاقات الزمنية القائمة على البيانات.على سبيل المثال، أي وقت أقل من 30 ثانية هو "منذ لحظات"، أو 360 إلى 390 يومًا هو "منذ عام واحد فقط"، وما إلى ذلك.سيستخدم بعض هؤلاء التاريخ المستهدف لحساب الأسماء الخاصة (يونيو، الأربعاء، إلخ).آسف لتبديد الأوهام التي كانت لديك.

وغني عن القول (لكنني سأقول ذلك على أي حال) لا تستخدم حلقة حيث تنقص 365 يومًا سنويًا حتى في 366 يومًا كبيسة (أو ستجد نفسك في صفوف مطوري Zune)

إليك نسخة c#:

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

أنا أعرف التعبير عن مثل هذه الأوقات أصبحت شعبية جدا في الآونة الأخيرة, ولكن يرجى النظر مما يجعل خيار للتبديل تم النسبية 'غامض' التواريخ الطبيعي المطلق التواريخ.

على سبيل المثال ، فإنه من المفيد أن نعرف أن أشير إلى 5 دقائق ، لكنه أقل فائدة أن تقول لي تعليق على 4 ساعات و التعليق ب 9 ساعات مضت عندما الساعة 11 صباحا و كنت أعرف أن هذا التعليق كان مكتوب عند شخص استيقظت هذا الصباح و التعليق ب كانت مكتوبة من قبل شخص البقاء حتى وقت متأخر (على افتراض وأنا أعلم أنهم في التوقيت).

-- تحرير:أبحث عن قرب على سؤالك يبدو أنك تجنبت هذا إلى درجة بالإشارة إلى الوقت من اليوم بدلا من "X قبل", ولكن من ناحية أخرى ، قد تعطي انطباعا خاطئا إذا كان المستخدمون في منطقة زمنية مختلفة ، منذ "هذا الصباح" قد يكون في منتصف الليل المستخدم ذات الصلة.

قد يكون بارد لزيادة مرات مع النسبية الوقت من اليوم اعتمادا على المستخدم الآخر التوقيت ، ولكن هذا يفترض أن المستخدمين هم على استعداد لتوريد ذلك وهذا هو الصحيح.

لم أكن سعيدًا بالحل في السؤال الآخر.لذلك قمت بعمل خاصيتي باستخدام فئة التاريخ والوقت.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";
}

يتم ذلك دائمًا تقريبًا باستخدام بيان تبديل عملاق وهو أمر تافه للتنفيذ.

ضع في اعتبارك ما يلي:

  • اختبر دائمًا أصغر فترة زمنية أولاً
  • لا تنس أن تبقي سلاسلك قابلة للترجمة.

قد تجد المصدر من زمن مضى مفيد.وصف البرنامج المساعد هو "مكون إضافي لـ jQuery يجعل من السهل دعم التحديث التلقائي للطوابع الزمنية الغامضة (على سبيل المثال."منذ 4 دقائق" أو "منذ يوم واحد تقريبًا""."

إنه في الأساس منفذ JavaScript لـ Rail's distance_of_time_in_words وظيفة محشورة في البرنامج المساعد مسج.

شركتي لديها مكتبة .NET هذه يقوم ببعض ما تريده من حيث أنه يقوم بتحليل مرن للغاية للتاريخ والوقت (بما في ذلك بعض التنسيقات النسبية) ولكنه لا يقوم إلا بمخرجات غير نسبية.

تحقق من Chrono للحصول على محلل تاريخ جافا سكريبت الإرشادي.

يدعم 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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top