1
0
mirror of https://github.com/danog/Telegram.git synced 2024-11-30 04:29:15 +01:00
Telegram/legacy/TelegraphKit/TGDateUtils.mm
2015-10-01 19:19:52 +03:00

485 lines
17 KiB
Plaintext

#include "TGDateUtils.h"
#include <time.h>
#import "TGStringUtils.h"
#import "TGUser.h"
static bool value_dateHas12hFormat = false;
static __strong NSString *value_monthNamesGenShort[] = {
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil
};
static __strong NSString *value_monthNamesGenFull[] = {
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil
};
static __strong NSString *value_weekdayNamesShort[] = {
nil, nil, nil, nil, nil, nil, nil
};
static __strong NSString *value_weekdayNamesFull[] = {
nil, nil, nil, nil, nil, nil, nil
};
static NSString *value_dialogTimeFormat = nil;
static NSString *value_date_separator = @".";
static bool value_monthFirst = false;
static bool isArabic = false;
static bool isKorean = false;
static bool TGDateUtilsInitialized = false;
static void initializeTGDateUtils()
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[NSLocale currentLocale]];
[dateFormatter setDateStyle:NSDateFormatterNoStyle];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
NSTimeZone *timeZone = [NSTimeZone localTimeZone];
[dateFormatter setTimeZone:timeZone];
NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];
NSRange amRange = [dateString rangeOfString:[dateFormatter AMSymbol]];
NSRange pmRange = [dateString rangeOfString:[dateFormatter PMSymbol]];
value_dateHas12hFormat = !(amRange.location == NSNotFound && pmRange.location == NSNotFound);
dateString = [NSDateFormatter dateFormatFromTemplate:@"MdY" options:0 locale:[NSLocale currentLocale]];
if ([dateString rangeOfString:@"."].location != NSNotFound)
{
value_date_separator = @".";
}
else if ([dateString rangeOfString:@"/"].location != NSNotFound)
{
value_date_separator = @"/";
}
else if ([dateString rangeOfString:@"-"].location != NSNotFound)
{
value_date_separator = @"-";
}
if ([dateString rangeOfString:[NSString stringWithFormat:@"M%@d", value_date_separator]].location != NSNotFound)
{
value_monthFirst = true;
}
NSString *identifier = [[NSLocale currentLocale] localeIdentifier];
if ([identifier isEqualToString:@"ar"] || [identifier hasPrefix:@"ar_"])
{
isArabic = true;
value_date_separator = @"\u060d";
}
else if ([identifier isEqualToString:@"ko"] || [identifier hasPrefix:@"ko-"])
{
isKorean = true;
}
value_monthNamesGenShort[0] = TGLocalized(@"Month.ShortJanuary");
value_monthNamesGenShort[1] = TGLocalized(@"Month.ShortFebruary");
value_monthNamesGenShort[2] = TGLocalized(@"Month.ShortMarch");
value_monthNamesGenShort[3] = TGLocalized(@"Month.ShortApril");
value_monthNamesGenShort[4] = TGLocalized(@"Month.ShortMay");
value_monthNamesGenShort[5] = TGLocalized(@"Month.ShortJune");
value_monthNamesGenShort[6] = TGLocalized(@"Month.ShortJuly");
value_monthNamesGenShort[7] = TGLocalized(@"Month.ShortAugust");
value_monthNamesGenShort[8] = TGLocalized(@"Month.ShortSeptember");
value_monthNamesGenShort[9] = TGLocalized(@"Month.ShortOctober");
value_monthNamesGenShort[10] = TGLocalized(@"Month.ShortNovember");
value_monthNamesGenShort[11] = TGLocalized(@"Month.ShortDecember");
value_monthNamesGenFull[0] = TGLocalized(@"Month.GenJanuary");
value_monthNamesGenFull[1] = TGLocalized(@"Month.GenFebruary");
value_monthNamesGenFull[2] = TGLocalized(@"Month.GenMarch");
value_monthNamesGenFull[3] = TGLocalized(@"Month.GenApril");
value_monthNamesGenFull[4] = TGLocalized(@"Month.GenMay");
value_monthNamesGenFull[5] = TGLocalized(@"Month.GenJune");
value_monthNamesGenFull[6] = TGLocalized(@"Month.GenJuly");
value_monthNamesGenFull[7] = TGLocalized(@"Month.GenAugust");
value_monthNamesGenFull[8] = TGLocalized(@"Month.GenSeptember");
value_monthNamesGenFull[9] = TGLocalized(@"Month.GenOctober");
value_monthNamesGenFull[10] = TGLocalized(@"Month.GenNovember");
value_monthNamesGenFull[11] = TGLocalized(@"Month.GenDecember");
value_weekdayNamesShort[0] = TGLocalized(@"Weekday.ShortMonday");
value_weekdayNamesShort[1] = TGLocalized(@"Weekday.ShortTuesday");
value_weekdayNamesShort[2] = TGLocalized(@"Weekday.ShortWednesday");
value_weekdayNamesShort[3] = TGLocalized(@"Weekday.ShortThursday");
value_weekdayNamesShort[4] = TGLocalized(@"Weekday.ShortFriday");
value_weekdayNamesShort[5] = TGLocalized(@"Weekday.ShortSaturday");
value_weekdayNamesShort[6] = TGLocalized(@"Weekday.ShortSunday");
value_weekdayNamesFull[0] = TGLocalized(@"Weekday.Monday");
value_weekdayNamesFull[1] = TGLocalized(@"Weekday.Tuesday");
value_weekdayNamesFull[2] = TGLocalized(@"Weekday.Wednesday");
value_weekdayNamesFull[3] = TGLocalized(@"Weekday.Thursday");
value_weekdayNamesFull[4] = TGLocalized(@"Weekday.Friday");
value_weekdayNamesFull[5] = TGLocalized(@"Weekday.Saturday");
value_weekdayNamesFull[6] = TGLocalized(@"Weekday.Sunday");
value_dialogTimeFormat = [[TGLocalized(@"Date.DialogDateFormat") stringByReplacingOccurrencesOfString:@"{month}" withString:@"%1$@"] stringByReplacingOccurrencesOfString:@"{day}" withString:@"%2$@"];
TGDateUtilsInitialized = true;
}
static inline bool dateHas12hFormat()
{
if (!TGDateUtilsInitialized)
initializeTGDateUtils();
return value_dateHas12hFormat;
}
bool TGUse12hDateFormat()
{
if (!TGDateUtilsInitialized)
initializeTGDateUtils();
return value_dateHas12hFormat;
}
static inline NSString *weekdayNameShort(int number)
{
if (!TGDateUtilsInitialized)
initializeTGDateUtils();
if (number < 0)
number = 0;
if (number > 6)
number = 6;
if (number == 0)
number = 6;
else
number--;
return value_weekdayNamesShort[number];
}
static inline NSString *weekdayNameFull(int number)
{
if (!TGDateUtilsInitialized)
initializeTGDateUtils();
if (number < 0)
number = 0;
if (number > 6)
number = 6;
if (number == 0)
number = 6;
else
number--;
return value_weekdayNamesFull[number];
}
static inline NSString *monthNameGenFull(int number)
{
if (!TGDateUtilsInitialized)
initializeTGDateUtils();
if (number < 0)
number = 0;
if (number > 11)
number = 11;
return value_monthNamesGenFull[number];
}
static inline NSString *dialogTimeFormat()
{
if (!TGDateUtilsInitialized)
initializeTGDateUtils();
return value_dialogTimeFormat;
}
@implementation TGDateUtils
+ (void)reset
{
TGDateUtilsInitialized = false;
}
+ (NSString *)stringForShortTime:(int)time
{
time_t t = time;
struct tm timeinfo;
localtime_r(&t, &timeinfo);
return [self stringForShortTimeWithHours:timeinfo.tm_hour minutes:timeinfo.tm_min];
}
+ (NSString *)stringForShortTimeWithHours:(int)hours minutes:(int)minutes
{
if (!TGDateUtilsInitialized)
initializeTGDateUtils();
if (isArabic)
{
if (dateHas12hFormat())
{
if (hours < 12)
return [TGStringUtils stringWithLocalizedNumberCharacters:[[NSString alloc] initWithFormat:@"%d:%02d ص", hours == 0 ? 12 : hours, minutes]];
else
return [TGStringUtils stringWithLocalizedNumberCharacters:[[NSString alloc] initWithFormat:@"%d:%02d م", (hours - 12 == 0) ? 12 : (hours - 12), minutes]];
}
else
return [TGStringUtils stringWithLocalizedNumberCharacters:[[NSString alloc] initWithFormat:@"%02d:%02d", hours, minutes]];
}
else if (isKorean)
{
return [[NSString alloc] initWithFormat:@"%02d:%02d", hours, minutes];
}
else
{
if (dateHas12hFormat())
{
if (hours < 12)
return [[NSString alloc] initWithFormat:@"%d:%02d AM", hours == 0 ? 12 : hours, minutes];
else
return [[NSString alloc] initWithFormat:@"%d:%02d PM", (hours - 12 == 0) ? 12 : (hours - 12), minutes];
}
else
return [[NSString alloc] initWithFormat:@"%02d:%02d", hours, minutes];
}
}
+ (NSString *)stringForShortTime:(int)time daytimeVariant:(int *)__unused daytimeVariant
{
return [self stringForShortTime:time];
}
+ (NSString *)stringForDialogTime:(int)time
{
time_t t = time;
struct tm timeinfo;
gmtime_r(&t, &timeinfo);
return [[NSString alloc] initWithFormat:dialogTimeFormat(), monthNameGenFull(timeinfo.tm_mon), [TGStringUtils stringWithLocalizedNumber:timeinfo.tm_mday]];
}
+ (NSString *)stringForDayOfWeek:(int)date
{
time_t t = date;
struct tm timeinfo;
localtime_r(&t, &timeinfo);
return weekdayNameFull(timeinfo.tm_wday);
}
+ (NSString *)stringForMonthOfYear:(int)date
{
time_t t = date;
struct tm timeinfo;
localtime_r(&t, &timeinfo);
NSString *format = TGLocalized([[NSString alloc] initWithFormat:@"Time.MonthOfYear_%d", (int)timeinfo.tm_mon + 1]);
return [[NSString alloc] initWithFormat:format, [[NSString alloc] initWithFormat:@"%d", 2000 + timeinfo.tm_year - 100]];
}
+ (NSString *)stringForFullDateWithDay:(int)day month:(int)month year:(int)year
{
if (isArabic)
{
return [TGStringUtils stringWithLocalizedNumberCharacters:[[NSString alloc] initWithFormat:@"%d%@%d%@%02d", day, value_date_separator, month, value_date_separator, year - 100]];
}
else if (isKorean)
{
return [TGStringUtils stringWithLocalizedNumberCharacters:[[NSString alloc] initWithFormat:@"%04d년 %d월 %d일", year - 100 + 2000, month, day]];
}
else
{
if (value_monthFirst)
{
return [[NSString alloc] initWithFormat:@"%d%@%d%@%02d", month, value_date_separator, day, value_date_separator, year - 100];
}
else
{
return [[NSString alloc] initWithFormat:@"%d%@%02d%@%02d", day, value_date_separator, month, value_date_separator, year - 100];
}
}
}
+ (NSString *)stringForPreciseDate:(int)date
{
time_t t = date;
struct tm timeinfo;
localtime_r(&t, &timeinfo);
NSString *format = TGLocalized([[NSString alloc] initWithFormat:@"Time.PreciseDate_%d", (int)timeinfo.tm_mon + 1]);
return [[NSString alloc] initWithFormat:format, [[NSString alloc] initWithFormat:@"%d", timeinfo.tm_mday], [[NSString alloc] initWithFormat:@"%d", (int)(2000 + timeinfo.tm_year - 100)], [self stringForShortTimeWithHours:timeinfo.tm_hour minutes:timeinfo.tm_min]];
}
+ (NSString *)stringForMessageListDate:(int)date
{
time_t t = date;
struct tm timeinfo;
localtime_r(&t, &timeinfo);
time_t t_now;
time(&t_now);
struct tm timeinfo_now;
localtime_r(&t_now, &timeinfo_now);
if (timeinfo.tm_year != timeinfo_now.tm_year)
{
return [self stringForFullDateWithDay:timeinfo.tm_mday month:timeinfo.tm_mon + 1 year:timeinfo.tm_year];
}
else
{
int dayDiff = timeinfo.tm_yday - timeinfo_now.tm_yday;
if(dayDiff == 0)
return [self stringForShortTime:date];
else if(dayDiff == -1)
return weekdayNameShort(timeinfo.tm_wday);
else if(dayDiff == -2)
return weekdayNameShort(timeinfo.tm_wday);
else if(dayDiff > -7 && dayDiff <= -2)
return weekdayNameShort(timeinfo.tm_wday);
else
return [self stringForFullDateWithDay:timeinfo.tm_mday month:timeinfo.tm_mon + 1 year:timeinfo.tm_year];
}
return nil;
}
+ (NSString *)stringForApproximateDate:(int)date
{
time_t t = date;
struct tm timeinfo;
localtime_r(&t, &timeinfo);
time_t t_now;
time(&t_now);
struct tm timeinfo_now;
localtime_r(&t_now, &timeinfo_now);
if (timeinfo.tm_year != timeinfo_now.tm_year)
return [self stringForFullDateWithDay:timeinfo.tm_mday month:timeinfo.tm_mon + 1 year:timeinfo.tm_year];
else
{
int dayDiff = timeinfo.tm_yday - timeinfo_now.tm_yday;
if(dayDiff == 0 || dayDiff == -1)
return [self stringForTodayOrYesterday:dayDiff == 0 hours:timeinfo.tm_hour minutes:timeinfo.tm_min];
else if (false && dayDiff > -7 && dayDiff <= -2)
return weekdayNameShort(timeinfo.tm_wday);
else
return [self stringForFullDateWithDay:timeinfo.tm_mday month:timeinfo.tm_mon + 1 year:timeinfo.tm_year];
}
return nil;
}
+ (NSString *)stringForTodayOrYesterday:(bool)today hours:(int)hours minutes:(int)minutes
{
NSString *timeString = [self stringForShortTimeWithHours:hours minutes:minutes];
return [[NSString alloc] initWithFormat:today ? TGLocalizedStatic(@"Time.TodayAt") : TGLocalizedStatic(@"Time.YesterdayAt"), timeString];
}
+ (NSString *)stringForLastSeenTodayOrYesterday:(bool)today hours:(int)hours minutes:(int)minutes
{
NSString *timeString = [self stringForShortTimeWithHours:hours minutes:minutes];
return [[NSString alloc] initWithFormat:today ? TGLocalizedStatic(@"LastSeen.TodayAt") : TGLocalizedStatic(@"LastSeen.YesterdayAt"), timeString];
}
+ (NSString *)stringForLastSeen:(int)date
{
time_t t = date;
struct tm timeinfo;
localtime_r(&t, &timeinfo);
time_t t_now;
time(&t_now);
struct tm timeinfo_now;
localtime_r(&t_now, &timeinfo_now);
if (timeinfo.tm_year != timeinfo_now.tm_year)
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"LastSeen.AtDate"), [self stringForFullDateWithDay:timeinfo.tm_mday month:timeinfo.tm_mon + 1 year:timeinfo.tm_year]];
else
{
int dayDiff = timeinfo.tm_yday - timeinfo_now.tm_yday;
if(dayDiff == 0 || dayDiff == -1)
return [self stringForLastSeenTodayOrYesterday:dayDiff == 0 hours:timeinfo.tm_hour minutes:timeinfo.tm_min];
else if (false && dayDiff > -7 && dayDiff <= -2)
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"LastSeen.AtWeekday"), weekdayNameShort(timeinfo.tm_wday)];
else
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"LastSeen.AtDate"), [self stringForFullDateWithDay:timeinfo.tm_mday month:timeinfo.tm_mon + 1 year:timeinfo.tm_year]];
}
return nil;
}
+ (NSString *)stringForRelativeLastSeen:(int)date
{
if (date == -1)
return TGLocalized(@"Presence.invisible");
else if (date == TGUserPresenceValueLately)
return TGLocalized(@"LastSeen.Lately");
else if (date == TGUserPresenceValueWithinAWeek)
return TGLocalized(@"LastSeen.WithinAWeek");
else if (date == TGUserPresenceValueWithinAMonth)
return TGLocalized(@"LastSeen.WithinAMonth");
else if (date == TGUserPresenceValueALongTimeAgo)
return TGLocalized(@"LastSeen.ALongTimeAgo");
else if (date <= 0)
return TGLocalized(@"Presence.offline");
time_t t = date;
struct tm timeinfo;
localtime_r(&t, &timeinfo);
time_t t_now;
time(&t_now);
struct tm timeinfo_now;
localtime_r(&t_now, &timeinfo_now);
if (timeinfo.tm_year != timeinfo_now.tm_year)
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"LastSeen.AtDate"), [self stringForFullDateWithDay:timeinfo.tm_mday month:timeinfo.tm_mon + 1 year:timeinfo.tm_year]];
else
{
int dayDiff = timeinfo.tm_yday - timeinfo_now.tm_yday;
int minutesDiff = (int)((t_now - date) / 60);
int hoursDiff = (int)((t_now - date) / (60 * 60));
if (dayDiff == 0 && hoursDiff <= 23)
{
if (minutesDiff < 1)
return TGLocalizedStatic(@"LastSeen.JustNow");
else if (minutesDiff < 60)
{
if (minutesDiff == 1)
return TGLocalizedStatic(@"LastSeen.MinutesAgo_1");
else if (minutesDiff == 2)
return TGLocalizedStatic(@"LastSeen.MinutesAgo_2");
else if (minutesDiff >= 3 && minutesDiff <= 10)
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"LastSeen.MinutesAgo_3_10"), [TGStringUtils stringWithLocalizedNumber:minutesDiff]];
else
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"LastSeen.MinutesAgo_any"), [TGStringUtils stringWithLocalizedNumber:minutesDiff]];
}
else
{
if (hoursDiff == 1)
return TGLocalizedStatic(@"LastSeen.HoursAgo_1");
else if (hoursDiff == 2)
return TGLocalizedStatic(@"LastSeen.HoursAgo_2");
else if (hoursDiff >= 3 && hoursDiff <= 10)
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"LastSeen.HoursAgo_3_10"), [TGStringUtils stringWithLocalizedNumber:hoursDiff]];
else
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"LastSeen.HoursAgo_any"), [TGStringUtils stringWithLocalizedNumber:hoursDiff]];
}
}
else if (dayDiff == 0 || dayDiff == -1)
return [self stringForLastSeenTodayOrYesterday:dayDiff == 0 hours:timeinfo.tm_hour minutes:timeinfo.tm_min];
else
return [[NSString alloc] initWithFormat:TGLocalizedStatic(@"LastSeen.AtDate"), [self stringForFullDateWithDay:timeinfo.tm_mday month:timeinfo.tm_mon + 1 year:timeinfo.tm_year]];
}
return nil;
}
@end