Which Languages offer day-before-yesterday in DateFormatter.doesRelativeDateFormatting?

DateFormatter in Swift / Foundation has an option .doesRelativeDateFormatting that will…

where possible [replace] the date component of its output with a phrase—such as “today” or “tomorrow”—that indicates a relative date. 

Apple Developer Documentation

Seems that in Apple’s Foundation every language has a word or phrase for today and yesterday. But not all languages have one for day before yesterday. Same applies for tomorrow and day after tomorrow respectively.

Question is: which ones have one, which don’t?

I did another Swift Playground to find out. Turns out there are quite a few that do either way. If you want to adjust your code to the user’s current language setting, you could do it like I will:

let pastRelativeDays, futureRelativeDays: Int
switch Locale.current.languageCode {
case "br":
    pastRelativeDays = 2 //day before yesterday, yesterday
    futureRelativeDays = 1 //tomorrow only
case "mgo":
    pastRelativeDays = 1 //yesterday only
    futureRelativeDays = 2 //tomorrow, day after tomorrow
case "af", "am", "ar", "as", "ast", "be", "bg", "bn", "bo", "bs", "ca", "ccp", "cs", "cy", "da", "de", "dz", "ee", "el", "es", "et", "eu", "fa", "fi", "fil", "fo", "fr", "fur", "fy", "ga", "gl", "gsw", "gu", "he", "hi", "hr", "hu", "hy", "id", "ii", "is", "it", "ja", "ka", "kk", "km", "kn", "ko", "ksh", "ky", "lo", "lt", "lv", "mk", "ml", "mn", "ms", "my", "nb", "ne", "nl", "nn", "os", "pl", "pt", "rm", "ro", "ru", "sah", "se", "si", "sk", "sl", "sr", "sv", "sw", "ta", "te", "th", "to", "tr", "uk", "ur", "vi", "wae", "yo", "yue", "zh", "zu":
    pastRelativeDays = 2 //day before yesterday, yesterday
    futureRelativeDays = 2 //tomorrow, day after tomorrow
case "gd":
    pastRelativeDays = 2 //day before yesterday, yesterday
    futureRelativeDays = 3 //tomorrow, day after tomorrow, 2 days after tomorrow
default:
    pastRelativeDays = 1 //yesterday only
    futureRelativeDays = 1 //tomorrow only
}

So now we know.

And here’s the complete playground:

import PlaygroundSupport
import Foundation

let formatter = DateFormatter()
formatter.timeStyle = .none
formatter.dateStyle = .short
formatter.doesRelativeDateFormatting = false
let rFormatter = DateFormatter()
rFormatter.timeStyle = .none
rFormatter.dateStyle = .short
rFormatter.doesRelativeDateFormatting = true

struct ResultRow {
    let localeIdentifier: String
    let pastRelativeDates: Int
    let futureRelativeDates: Int
}

var results: [ResultRow] = []

for identifier in Locale.availableIdentifiers {
    if !identifier.contains("_") {    
        formatter.locale = Locale(identifier: identifier)
        rFormatter.locale = Locale(identifier: identifier)
        var future = 0, past = 0
        for i in 1..<10 {
            var num = 0
            let pastDay: Date = Calendar.current.date(byAdding: .day, value: -i, to: Date())!
            let futureDay: Date = Calendar.current.date(byAdding: .day, value: i, to: Date())!
            let pastRStr = rFormatter.string(from: pastDay)
            let pastStr = formatter.string(from: pastDay)
            let futureRStr = rFormatter.string(from: futureDay)
            let futureStr = formatter.string(from: futureDay)
            if pastStr != pastRStr {
                past = i
            }
            if futureStr != futureRStr {
                future = i
            }
            if pastStr == pastRStr && futureStr == futureRStr {
                break
            }
        }
        results.append(ResultRow(localeIdentifier: identifier, pastRelativeDates: past, futureRelativeDates: future))
    }
}
let sorted = results.sorted(by: { $0.futureRelativeDates > $1.futureRelativeDates || $0.futureRelativeDates == $1.futureRelativeDates && $0.pastRelativeDates > $1.pastRelativeDates ||  ($0.futureRelativeDates == $1.futureRelativeDates && $0.pastRelativeDates == $1.pastRelativeDates && $0.localeIdentifier < $1.localeIdentifier) } ) 
for result in sorted {
    print(result.localeIdentifier, result.futureRelativeDates, result.pastRelativeDates)
}
print("---")
let maxFuture = sorted.reduce(0) { max($1.futureRelativeDates, $0) }
let maxPast = sorted.reduce(0) { max($1.pastRelativeDates, $0) }
for f in 1...maxFuture {
    for p in 1...maxPast {
        let filtered = sorted.filter( { $0.pastRelativeDates == p && $0.futureRelativeDates == f } )
        var switchLine = ""
        for result in filtered {
            let thisOne = "\"" + result.localeIdentifier + "\"" 
            if switchLine == "" {
                switchLine = thisOne
            } else {
                switchLine = switchLine + ", " + thisOne
            }
        }
        if switchLine != "" && !(p == 1 && f == 1) {
            switchLine = "case " + switchLine + ":"
            print(switchLine)
            print("    pastRelativeDays = \(p)")
            print("    futureRelativeDays = \(f)")
        }
    }
}
print("default:")
print("    pastRelativeDays = 1")
print("    futureRelativeDays = 1")