Fuzzy date algorithm
我正在寻找模糊日期算法。我刚刚开始写一个,并意识到它是一个繁琐的任务。它迅速退化为许多可怕的代码,以应对特殊情况,如"昨天","上周"和"上个月末"之间的差异,所有这些都可以(在某些情况下)指的是同一天但是个别正确根据今天的日期。
我确信必须有一个开源模糊日期格式化器,但我找不到它。理想情况下,我喜欢使用NSDate(OSX / iPhone)及其格式化程序,但这并不困难。有没有人知道模糊日期格式化程序相对于现在采取任何时间段并返回像(但不限于)的字符串:
- 不久前
- 在最后五分钟
- 今日早些时候
- 今天早上
- 昨晚
- 上个星期
- 上周三
- 上个月初
- 去年6月
- 几年前
在一个理想的世界中,我希望字符串尽可能丰富(即在"刚才之前"返回随机变体,例如"刚才")。
澄清。我正在寻找比基本的buckts和字符串更微妙的东西。我想要一些知道"昨天"和"上周三"的东西都可以指同一时期,但只有一个是正确的,今天是星期四。
NSDateFormatter中有一个属性 -"doesRelativeDateFormatting"。它仅出现在10.6 / iOS4.0及更高版本中,但它会将日期格式化为正确语言环境中的相对日期。
来自Apple的文档:
If a date formatter uses relative date
formatting, where possible it replaces
the date component of its output with
a phrase—such as"today" or
"tomorrow"—that indicates a relative
date. The available phrases depend on
the locale for the date formatter;
whereas, for dates in the future,
English may only allow"tomorrow,"
French may allow"the day after the
day after tomorrow," as illustrated in
the following example.
码
以下是为给定语言环境打印出大量相对字符串的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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; } |
笔记:
- 不需要语言环境
-
有
没有那么多替换
英语。在那里写作
是:"昨天,今天,明天"。
Apple可能会在未来包含更多内容。 -
更改区域设置并查看是很有趣的
什么是其他语言版本
(法语比英语多一点,
例如) - 如果在iOS上,您可能希望订阅UIApplicationSignificantTimeChangeNotification
Interface Builder
您可以在Interface Builder中设置"doesRelativeDateFormatting"属性:
-
选择你的NSDateFormatter和
选择"Identity Inspector"选项卡
Inspector Palette(最后一个)
一个[command-6])。 -
在名为"用户"的子节下
定义运行时属性",你可以
为所选对象上的键添加自己的值(在本例中为NSDateFormatter实例)。加
"didRelativeDateFormatting",选择
一个"布尔"类型,并确保它
检查。 - 请记住:它可能看起来根本不起作用,但这可能是因为您的语言环境只有少数替换值。在您决定是否设置正确之前,请至少尝试昨天,今天和明天的日期。
这个问题应该让你开始。它具有此站点用于计算其相对时间的代码。它可能没有您想要的特定范围,但是一旦您完成设置它们就很容易添加。
你可能想看看我在下面粘贴的date_helper.rb中的Rail的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # 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 |
这是基于漂亮和人性日期和代码。时间线程。我添加了"上周一,下午5点"的处理,因为我喜欢它超过x天前。这可以处理过去和未来几个世纪。我热衷于国际化方面,所以最终需要做更多的工作。计算在当地时区。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 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); } } } |
所以,这是我在NSDate上为那些仍然感兴趣的人写的类别。问题是那些变得有点不切实际的问题之一。它基本上是一个巨大的开关声明(虽然我在一系列级联if()中实现它以使其更具可读性。
对于每个时间段,我然后从一组随机的时间中选择。
总而言之,这让我们的一些用户感到高兴,但我不确定这是值得的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | 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. } |
对不起发布这个花了这么长时间......
我不确定你为什么说这是一个可怕的编码练习。每个返回字符串实际上是父集的子集,因此您可以在if / elseif链中非常优雅地执行此操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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" |
我对另一个问题的解决方案不满意。所以使用Date时间类创建了我自己的。 IMO,它更清洁。在我的测试中,它像我想要的那样工作。希望这有助于某人。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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"; } |
我知道表达这样的时间最近变得非常流行,但请考虑让它成为切换相对'模糊'日期和正常绝对日期的选项。
例如,知道5分钟前发表评论很有用,但是告诉我评论A是4小时前评论B并且评论B是9小时前的时间是上午11点,而且我宁愿知道评论A是今天早上有人醒来时写的评论B是由熬夜的人写的(假设我知道他们在我的时区)。
-
编辑:仔细看看你的问题,你似乎在某种程度上通过提及时间而不是"X前"来避免这种情况,但另一方面,如果用户处于不同的时区,你可能会给人一种错误的印象,因为你的"今天早晨"可能是在相关用户的半夜。
根据其他用户的时区,用相对时间来增加时间可能很酷,但这假设用户愿意提供它并且它是正确的。
不用说(但无论如何我会说)不要使用每年365天减少的where循环,即使在366天的闰年(或者你会发现自己在Zune开发者的行列)
这是一个c#版本:
Creating Twitter-esque Relative Dates in C#
根据我的经验,这些类型的日期生成器根本不是"模糊"的。实际上,它们只是一堆if语句的时间段。例如,任何小于30秒的时间都是"很久以前",360到390天是"仅一年前",等等。其中一些将使用目标日期来计算特殊名称(6月,星期三等)。
很抱歉打破你的幻想。
查看Chrono的Javascript启发式日期解析器。
Chrono支持大多数日期和时间格式,例如:
1 2 3 4 5 6 | 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
我的公司有这个.NET库,可以完成你想要的一些,因为它可以进行非常灵活的日期时间解析(包括一些相对格式),但它只做非相对输出。
您可能会发现timeago的来源很有用。该插件的描述是"一个jQuery插件,可以很容易地支持自动更新模糊时间戳(例如"4分钟前"或"约1天前")。"
它本质上是一个嵌入jQuery插件的Rail的
这几乎总是使用巨大的switch语句来完成,并且实现起来很简单。
请记住以下几点:
- 始终首先测试最小的时间跨度
- 不要忘记让你的字符串可以本地化。