ファジー日付アルゴリズム
-
03-07-2019 - |
質問
ファジー日付アルゴリズムを探しています。ちょうど書き始めて、それがどれほど退屈な作業であるかに気づきました。これは、「昨日」、「先週」、「先月末」の違いのような特殊なケースに対処するために、すぐに多くの恐ろしいコードに変質しました。これらはすべて (場合によっては) 同じ日を参照できますが、個別には正しいものです。今日の日付に基づいて。
オープンソースのあいまい日付フォーマッタがきっとあるはずだと思うのですが、見つかりません。理想的には、NSDate (OSX/iPhone) とそのフォーマッタを使用するものが欲しいですが、それは難しいことではありません。現在を基準とした任意の期間を取得し、次のような文字列を返すファジー日付フォーマッタを知っている人はいますか(ただし、これに限定されません)。
- 数分前
- 最後の5分で
- 今日の早い時間に
- 今朝
- 昨晩
- 先週
- 先週の水曜日
- 先月初め
- 去年の6月
- 2〜3年前
理想的な世界では、文字列ができるだけ豊富であることが望ましいです (つまり、「今」など、「ほんの少し前」のランダムなバリエーションを返します)。
説明。基本的なバケツやストリングよりも繊細なものを探しています。「昨日」と「先週の水曜日」はどちらも同じ期間を指すことができますが、今日が木曜日の場合はどちらか一方のみが正しいことがわかるものが必要です。
解決
この質問はあなたを始めるはずです。このコードは非常にサイトはその相対時間を計算するために使用します。必要な特定の範囲がない場合もありますが、セットアップしたら簡単に追加できます。
他のヒント
NSDateFormatterにはプロパティがあります-" doesRelativeDateFormatting"。 10.6 / iOS4.0以降でのみ表示されますが、正しいロケールで日付を相対日付にフォーマットします。
日付フォーマッターが相対日付を使用する場合 フォーマット、可能な場合は置き換えます 出力の日付コンポーネント —“ today”などのフレーズまたは “明日”—それは親relativeを示します 日付。利用可能なフレーズは 日付フォーマッタのロケール。 一方、将来の日付については、 英語では、明日のみを許可する場合があります。” フランス人は“ 明後日、”に示すように 次の例。
コード
次は、指定されたロケールの適切な数の相対文字列を出力するコードです。
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
インターフェイスビルダー
&quot; doesRelativeDateFormatting&quot;を設定できます。 Interface Builderのプロパティ:
- NSDateFormatterを選択し、 「Identity Inspector」を選択します;タブ インスペクターパレット(最後の 1つ[command-6])。
- &quot; Userという名前のサブセクションの下 定義済みのランタイム属性&quot; 選択したオブジェクト(この場合はNSDateFormatterインスタンス)のキーに独自の値を追加します。追加する &quot; doesRelativeDateFormatting&quot ;、選択 &quot;ブール値&quot;入力して、それが
- 覚えておく:まったく機能しなかったように見えるかもしれませんが、ロケールの置換値が数個しかないためかもしれません。正しく設定されていないかどうかを判断する前に、少なくとも昨日、今日、明日の日付を試してください。
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で私がまだ興味を持っている人のために書いたカテゴリはここにあります。問題は、少し不安定になる問題の1つです。基本的には巨大なスイッチ文です(読みやすくするために一連のカスケード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.
}
これを投稿するのに時間がかかりました...
これは、Pretty and Humane dateおよび&amp;のコードに基づいています。タイムスレッド。 「先週の月曜日、午後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"
私の経験では、この種の日付ジェネレーターはまったく「あいまい」ではありません。実際、これらは時間帯に基づいた if ステートメントの束にすぎません。たとえば、30 秒未満は「ほんの少し前」、360 ~ 390 日は「ちょうど 1 年前」などとなります。これらの中には、特別な名前 (6 月、水曜日など) を計算するために対象の日付を使用するものもあります。幻想を打ち破ってごめんなさい。
言うまでもありませんが(とにかく言う)366日のうるう年でも年365日減るwhereループを使用しないでください(または、Zune開発者の仲間入りをします)
これはC#バージョンです:
http:// tiredblogger.wordpress.com/2008/08/21/creating-twitter-esque-relative-dates-in-c/
最近、このような時間を表現することは非常に一般的になっていますが、相対的な「あいまいな」日付と通常の絶対日付を切り替えるオプションにすることを検討してください。
たとえば、5分前にコメントが作成されたことを知っておくと便利ですが、午前11時にコメントAが4時間前で、コメントBが9時間前だったと言うのはあまり役に立ちません。コメントAは今朝誰かが目覚めたときに書かれ、コメントBは遅い時間に起きた誰かによって書かれました(彼らが私のタイムゾーンにいることを知っていると仮定して)。
- 編集:質問を詳しく見ると、「X前」ではなく時刻を参照することである程度これを回避しているように見えますが、一方で、ユーザーが異なるタイムゾーンにいる場合は誤った印象を与えている可能性があります、「今朝」から該当するユーザーの深夜かもしれません。
他のユーザーのタイムゾーンに応じて相対的な時刻で時間を増やすことはクールかもしれませんが、それはユーザーがそれを提供する意思があり、正しいことを前提としています。
他の質問の解決策に満足していませんでした。そのため、Date timeクラスを使用して独自に作成しました。 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";
}
これはほとんどの場合、巨大なswitchステートメントを使用して行われ、実装は簡単です。
次のことに注意してください:
- 常に最小の期間を最初にテストする
- 文字列をローカライズ可能な状態に保つことを忘れないでください。
timeagoのソースが役立つ場合があります。プラグインの説明は「ファジータイムスタンプの自動更新を簡単にサポートできるjQueryプラグインです(例:「4分前」または「約1日前」)。
基本的には、jQueryプラグインに詰め込まれたRailの distance_of_time_in_words
関数のJavaScriptポートです。
私の会社にはこの.NETライブラリ非常に柔軟な日時解析(一部の相対形式を含む)を行うという点で、必要な機能の一部を実行しますが、非相対出力のみを実行します。
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