NSDateFormatter relative date formatting with custom format

荒凉一梦 提交于 2019-12-21 07:34:24

问题


So my intention is to put out dates that would look like the following:

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

The issue is that it seems I can only get so close.

When I setDoesRelativeDateFormatting:YES and setDateStyle to Full and setTimeStyle to None, it yields results like this:

Today
Tomorrow
Friday, August 30, 2013

This yields the year and does not yield month and date for today and tomorrow.

The other code I've tried is this:

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

and that yields the following:

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

Seemingly, the dateStyle and timeStyle, or the relative date formatting overrides the custom format.

Is there a way to accomplish this date format without going into a custom implementation?

Thanks in advance!


回答1:


Based on the documentation about NSDateFormatter I think that the only solution for your issue is to present two date strings for the days you would like to be relatively shown. You should keep in mind that in different languages there are differences in the relative dates. From the documentation:

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".

I believe that if you define that you're going to show relatively for example yesterday, today and tomorrow you can use 2 NSDateFormatters. With the first one you will show the relative value and with the second you will display the actual date. For the non-relative dates you will display only the non-relative value.




回答2:


It seems there is no way to accomplish this kind of date formatting without going into a custom implementation. So, the short answer to this question is 'No'.

However, the problem still exists, so below is my own solution to the problem.

Make a subclass of NSDateFormatter and implement custom init and override stringFromDate: method.

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

Since doesRelativeDateFormatting and dateFormat are mutually exclusive we try to use relative formatting first. Given that we set self.dateStyle = NSDateFormatterShortStyle in the init method, we know the date will contain decimal numbers unless it is replaced with words meaning 'today', 'tomorrow' and anything that may appear in other languages. If we did not spot any numbers we accept this result.

If there are digital numbers in the string we assume the relative formatting did not happen, so we apply our own date format.




回答3:


I use this approach in 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
    }
}


来源:https://stackoverflow.com/questions/18498561/nsdateformatter-relative-date-formatting-with-custom-format

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!