cocoa-touchwatchkitwatchos-3

How can I use relative dates like "Today" or "Tomorrow" in a watchOS complication?


I have a watchOS complication that shows information about what's happening either on the current day or on some future day. As with any complication, I have a CLKComplicationDataSource set up with various methods including getCurrentTimelineEntryForComplication:withHandler: and getTimelineEntriesForComplication:afterDate:limit:withHandler:. When these methods are called, I create a CLKComplicationTimelineEntry using a CLKComplicationTemplate subclass that's appropriate for the complication type.

The "Modular Large" complication type (CLKComplicationFamilyModularLarge) is the one that's giving me the most trouble. With this type I want the heading to say "Today" or "Tomorrow" when it's appropriate. Below that will be some text about what's happening that day. Currently I'm using CLKRelativeDateTextProvider for this:

template.headerTextProvider = [CLKRelativeDateTextProvider textProviderWithDate:date style:CLKRelativeDateStyleNatural units:NSCalendarUnitDay];

This doesn't quite do what I want though—it shows something like "0DAYS" or "1DAY". That's acceptable for a smaller complication, but with Modular Large it looks especially awkward. You don't even get a space after the number, no matter how much extra room there is.

I thought I could fix this by just using an NSDateFormatter to generate the string, then using a CLKSimpleTextProvider to display it. Seemed simple enough:

NSDateFormatter *formatter = [NSDateFormatter new];
formatter.doesRelativeDateFormatting = YES;
formatter.dateStyle = NSDateFormatterShortStyle;
formatter.timeStyle = NSDateFormatterNoStyle;
NSString *string = [formatter stringFromDate:date];

But there's a problem: a watchOS complication needs to be able to supply data for dates in the future. As far as I can tell, NSDateFormatter has no way to tell it what date you want the output to be relative to—it's always relative to the current date. So if the date for the complication data is tomorrow, and getTimelineEntriesForComplication:afterDate:limit:withHandler: is called, then all the timeline entries I generate will say "Tomorrow". That will be right for the current day, but when midnight hits, it'll be wrong. It will still say "Tomorrow" until all the complication data is generated again.

I've only been able to think of a couple solutions to this problem, and they both have drawbacks:

That said, I'm not sure what else I could do. I have already filed a Radar (27267550: CLKRelativeDateTextProvider should offer more control) asking for more date formatting options. It's a year old and shows no sign of being addressed in watchOS 4.

What's the best way to solve this?


Solution

  • If you go the route of calculating how many days away it is, you could use a localized .stringsdict and get a localized string based on the number. For English it could be:

    <key>zero</key>
    <string>Today</string>
    <key>one</key>
    <string>Tomorrow</string>
    ...
    <key>other</key>
    <string>%d days</string>
    

    And then for other languages you can add specific rules, like French's "après-demain" for two.

    Feels like a pretty unsatisfying option since you're now taking on the responsibility of managing every language and each possible way of describing future days, but it could work.