Swift DateComponentsFormatter删除前导零,但在Minutes位置至少保留一位数字

时间:2019-02-12 01:08:42

标签: ios swift date nsdatecomponents nsdatecomponentsformatter

我在Swift中使用以下DateComponentsFormatter:

function filter_bins(source_group, f) {
    return {
        all:function () {
            return source_group.all().filter(function(d) {
                return f(d.value);
            });
        }
    };
}

var filtered_years_group = filter_bins(FTEMonthGroup, function(d) {
    return !yearsHiddenArray.includes(d.Year);
}
heatMap.group(filtered_years_group);

这将产生类似于2:41(2分钟41秒)和08(8秒)的结果。但是,我想在Minutes位置至少保留一位数字,返回0:08而不是08。DateComponentsFormatter是否可能?我希望有一个返回本地化结果的解决方案。

4 个答案:

答案 0 :(得分:1)

是的。在设置日期组件格式化程序允许的单位时,可以很容易地完成基于时间间隔的三元条件添加操作:


extension Formatter {
    static let positional: DateComponentsFormatter = {
        let positional = DateComponentsFormatter()
        positional.unitsStyle = .positional
        positional.zeroFormattingBehavior = .pad
        return positional
    }()
}

extension TimeInterval {
    var positionalTime: String {
        Formatter.positional.allowedUnits = self >= 3600 ?
                                            [.hour, .minute, .second] :
                                            [.minute, .second]
        return Formatter.positional.string(from: self)!
    }
}

用法

8.0.positionalTime     //    "0:08"
161.0.positionalTime   //    "2:41"
3600.0.positionalTime  // "1:00:00"

答案 1 :(得分:0)

签出一个不同的zeroFormattingBehavior属性值。我用它来获得我认为您正在寻找的结果,但是可以根据需要进行实验...

    formatter.zeroFormattingBehavior = [.pad]

答案 2 :(得分:0)

可以根据持续时间修改allowedUnitszeroFormattingBehavior来创建合适的位置时间字符串。请注意,如果希望只有一个,那么它将在几分钟内填充两个前导零,以便事后以安全的方式进行处理。

let formatter = DateComponentsFormatter()
if duration < 60 {
    formatter.allowedUnits = [.minute, .second]
    formatter.zeroFormattingBehavior = .pad //pad seconds and minutes ie 00:05
} else if duration >= 60*60 {
    formatter.allowedUnits = [.hour, .minute, .second]
}

var formattedDuration = formatter.string(from: duration) ?? "0"
if formattedDuration.hasPrefix("00") {
    formattedDuration = String(formattedDuration.dropFirst()) //remove leading 0 ie 0:05
}

以下是durationformattedDuration的列表:

0 ▶️ 0:00
5 ▶️ 0:05
30 ▶️ 0:30
60 ▶️ 1:00
65 ▶️ 1:05
3600 ▶️ 1:00:00
3665 ▶️ 1:00:05
3660 ▶️ 1:01:00

替代解决方案

您可以通过使用.dropTrailing zeroFormattingBehavior获得相同的结果,而无需检查两个前导零,这很有趣。我会警告,我不完全了解为什么会这样做,也不知道它可能会对本地化产生什么影响。请注意,如果duration为0,则结果为"0",因此在这种情况下,我们可以使用.pad来获得"00:00"的结果。这样一来,您最终会遇到上述相同的情况,但也许您会觉得这是一个不需要处理的极端情况。

let formatter = DateComponentsFormatter()
if duration >= 60 {
    formatter.allowedUnits = [.hour, .minute, .second]
    formatter.zeroFormattingBehavior = .default
} else if duration == 0 {
    formatter.allowedUnits = [.minute, .second]
    formatter.zeroFormattingBehavior = .pad
    //is 00:00 but should be 0:00
} else {
    formatter.allowedUnits = [.minute, .second]
    formatter.zeroFormattingBehavior = .dropTrailing //magic here
}
let formattedDuration = formatter.string(from: duration) ?? "0"

答案 3 :(得分:0)

想出了这个解决方案,使用了一个正则表达式,似乎涵盖了所有情况:

let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = .positional
formatter.zeroFormattingBehavior = .pad

func durationString(for duration: TimeInterval) -> String {
    formatter.string(from: duration)!
        .replacingOccurrences(of: #"^00[:.]0?|^0"#, with: "", options: .regularExpression)
}

durationString(for: 0)      // 0:00
durationString(for: 1)      // 0:01
durationString(for: 10)     // 0:10
durationString(for: 60)     // 1:00
durationString(for: 600)    // 10:00
durationString(for: 3600)   // 1:00:00
durationString(for: 36000)  // 10:00:00