Относительное форматирование даты NSDateFormatter с пользовательским форматом

Поэтому я намерен вывести даты, которые выглядят следующим образом:

Today, August 28
Tomorrow, August 29
Friday, August 30
...etc

Проблема в том, что кажется, что я могу только приблизиться.

Когда я setDoesRelativeDateFormatting:YES и setDateStyle - Full и setTimeStyle - None, он дает такие результаты:

Today
Tomorrow
Friday, August 30, 2013

Это дает год и не дает месяц и дату на сегодня и завтра.

Другой код, который я пробовал, следующий:

[NSDateFormatter dateFormatFromTemplate:@"eeeedMMM" options:0
                                                     locale:[NSLocale currentLocale]];

и это дает следующее:

Wednesday, August 28
Thursday, August 29
Friday, August 30

По-видимому, dateStyle и timeStyle, или относительное форматирование даты, переопределяют пользовательский формат.

Есть ли способ выполнить этот формат даты, не вдаваясь в пользовательскую реализацию?

Спасибо заранее!

Ответ 1

Основываясь на документации по NSDateFormatter, я считаю, что единственным решением для вашей проблемы является представление двух строк даты в те дни, которые вы хотели бы относительно отобразить. Вы должны иметь в виду, что на разных языках существуют различия в относительных датах. Из документации:

Если форматирование даты использует относительное форматирование даты, по возможности оно заменяет компонент даты своего вывода фразой, такой как "сегодня" или "завтра", что указывает на относительную дату. Доступные фразы зависят от языкового стандарта для форматирования даты; тогда как для дат в будущем английский может позволить только "завтра", французский может разрешить "на следующий день послезавтра".

Я считаю, что если вы определите, что вы собираетесь показывать относительно вчера, сегодня и завтра вы можете использовать 2 NSDateFormatters. С первым вы покажете относительное значение, а со вторым вы увидите фактическую дату. Для не относительных дат вы увидите только относительное значение.

Ответ 2

Я использую этот подход в Swift 3:

struct SharedFormatters {
    private static let dateWithRelativeFormatting: DateFormatter = {
        let df = DateFormatter()
        df.dateStyle = .medium
        df.doesRelativeDateFormatting = true
        return df
    }()
    private static let dateWithoutRelativeFormatting: DateFormatter = {
        let df = DateFormatter()
        df.dateStyle = .medium
        df.doesRelativeDateFormatting = false
        return df
    }()
    private static let longDateWithoutYear: DateFormatter = {
        let df = DateFormatter()
        df.dateFormat = "MMMM d"
        df.doesRelativeDateFormatting = false
        return df
    }()
    static func string(from date: Date) -> String {
        let val = dateWithRelativeFormatting.string(from: date)
        let val2 = dateWithoutRelativeFormatting.string(from: date)
        return val == val2 ? longDateWithoutYear.string(from: date) : val
    }
}

Ответ 3

Кажется, что нет способа выполнить такое форматирование даты, не внося в него особую реализацию. Итак, короткий ответ на этот вопрос: "Нет".

Однако проблема все еще существует, поэтому ниже мое собственное решение проблемы.

Создайте подкласс NSDateFormatter и реализуйте собственный метод init и переопределите stringFromDate:.

- (instancetype)initWithDateFormat:(NSString *)dateFormat
{
    self = [super init];
    if (self) {
        NSLocale *locale = [NSLocale currentLocale];
        self.locale = locale;

        self.timeStyle = NSDateFormatterNoStyle;
        self.dateStyle = NSDateFormatterShortStyle;
        self.doesRelativeDateFormatting = YES;

        self.dateFormat = dateFormat;
    }
    return self;
}

- (NSString *)stringFromDate:(NSDate *)date
{
    NSString *dateFormat = self.dateFormat;
    self.dateFormat = nil;

    BOOL didRelativeDateFormatting = self.doesRelativeDateFormatting;
    self.doesRelativeDateFormatting = YES;

    NSString *result = [super stringFromDate:date];

    if ([result rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location != NSNotFound) {
        self.dateFormat = dateFormat;
        self.doesRelativeDateFormatting = NO;
        result = [super stringFromDate:date];
    }

    self.dateFormat = dateFormat;
    self.doesRelativeDateFormatting = didRelativeDateFormatting;

    return result;
}

Так как doesRelativeDateFormatting и dateFormat являются взаимоисключающими, мы сначала пытаемся использовать относительное форматирование. Учитывая, что мы устанавливаем self.dateStyle = NSDateFormatterShortStyle в методе init, мы знаем, что дата будет содержать десятичные числа, если она не будет заменена словами, означающими "сегодня", "завтра" и все, что может появиться на других языках. Если мы не заметили никаких чисел, мы принимаем этот результат.

Если в строке есть цифровые числа, мы предполагаем, что относительного форматирования не произошло, поэтому мы применяем наш собственный формат даты.