swift DateFormatter

一、简介

DateFormatter常用于Date与String的互相转换。通过配置dateFormat属性使其能够转换成不同需求的字符串,配置locale属性使其能够适配不同的语言。

二、API

  1. 格式化上下文
open var formattingContext: Formatter.Context
public enum Context : Int {
        case unknown = 0
        case dynamic = 1
        case standalone = 2
        case listItem = 3
        case beginningOfSentence = 4
        case middleOfSentence = 5
}

该属性用在英文等语言中,输出的字符串首字母是否需要大写。(其它人的文章中说明的,并未测试。)

  1. 通过dateFormat进行日期与字符串的转换
open func string(from date: Date) -> String
open func date(from string: String) -> Date?

默认是使用Asia/Shanghai时区,zh_CN本地化,gregorian日历。

let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss"
let string = df.string(from: Date())
print(string)
//2020-12-16 14:37:55
let d = df.date(from: string)
print(d)
//Optional(2020-12-16 06:37:55 +0000)
  1. 通过dateStyle将日期转换成字符串
open class func localizedString(from date: Date, dateStyle dstyle: DateFormatter.Style, 
                                timeStyle tstyle: DateFormatter.Style) -> String

public enum Style : UInt {
        case none = 0    //无输出
        case short = 1   //2020/12/16 下午2:42
        case medium = 2  //2020年12月16日 下午2:42:21
        case long = 3    //2020年12月16日 GMT+8 下午2:42:21
        case full = 4    //2020年12月16日 星期三 中国标准时间 下午2:42:21
    }
print(DateFormatter.localizedString(from: Date(), dateStyle: .short, timeStyle: .long))
//2020/12/16 GMT+8 下午2:49:49
  1. 模板字符串
  • 将字符串转换成规范的dateFormat字符串
open class func dateFormat(fromTemplate tmplate: String, options opts: Int,
                           locale: Locale?) -> String?
let a = DateFormatter.dateFormat(fromTemplate: "yyayy-MaM-dad", options: 0, 
                                 locale: Locale.current)
//Optional("yy/M/d a")
  • 应用模板字符串
open func setLocalizedDateFormatFromTemplate(_ dateFormatTemplate: String)

其作用是先将dateFormatTemplate转换成规范的dateFormat字符串,再赋值给dateFormat

let df = DateFormatter()
df.setLocalizedDateFormatFromTemplate("yyayy-MaM-dad")
等价于
df.dateFormat = DateFormatter.dateFormat(fromTemplate: "yyayy-MaM-dad", 
                                         options: 0, locale: Locale.current)

print(df.dateFormat)
//Optional("yy/M/d a")
  1. 属性
  • 行为
open class var defaultFormatterBehavior: DateFormatter.Behavior
public enum Behavior : UInt {
        case `default` = 0
        case behavior10_4 = 1040
}

open var formatterBehavior: DateFormatter.Behavior

默认为behavior10_4。

  • 日期格式化字符串
open var dateFormat: String!

默认为""。
dateFormat为yyyy-MM-dd HH:mm:ss,结果为2020-12-16 15:19:55的情况下,在zh_CN本地化来看。

G   Era标志符              公元
y   年份                   2020
Y
M   该年的第几月            12 
w   该年的第几周            51
W   该月的第几周            3
D   该年的第几天            351
d   该月的第几天            16
F   该月的第几星期           3
E   周几                   周三
e   该周的第几天            4
a   Am/pm                 下午
Q   第几季度                4
q   
H   一天的第几小时(0-23)   15  
k   一天的第几小时(1-24)   15  
h   am/pm的第几小时(1-12)  3
K   am/pm的第几小时(0-11)  3
m   该小时的第几分钟         19
s   该分钟的第几秒           55
S   该秒的第几毫秒      978
z   时区                   GMT+8
Z   时区                   +0800

以上的字母支持用多个叠加,比如M:
M 不带前导零 (一月表示为1)。
MM 带前导零 (一月表示为01)。
MMM 缩写形式 (一月为1月)。
MMMM 完整月份名 (一月为一月)。
不同语言下显示不同,如MMM在英语中为JanMMMMJanuary

若要直接显示上面的字母,则需要加上单引号''。

let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(df.string(from: Date()))
//2020-12-16 16:43:30
df.dateFormat = "yyyy-MM-dd HH:mm:'ss'"
print(df.string(from: Date()))
//2020-12-16 16:43:ss
  • 风格
open var dateStyle: DateFormatter.Style
open var timeStyle: DateFormatter.Style

功能与dateFormat(fromTemplate tmplate: String, options opts: Int, locale: Locale?) -> String?方法相同。

let df = DateFormatter()
df.timeStyle = .medium
df.dateStyle = .medium
print(df.string(from: Date()))
//2020年12月16日 下午3:58:27

dateStyletimeStyledateFormat都赋了值后,先赋值的无效。

let df = DateFormatter()
df.timeStyle = .medium
df.dateStyle = .medium
df.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(df.string(from: Date()))
//2020-12-16 16:03:06
  • 本地化、时区、日历
open var locale: Locale!
open var timeZone: TimeZone!
open var calendar: Calendar!

默认都为current,即本地化为zh_CN,时区为Asia/Shanghai,日历为gregorian

let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(df.string(from: Date()))
//2020-12-16 16:13:57
df.locale = Locale(identifier: "en_US")//英语
df.timeZone = TimeZone(secondsFromGMT: 3600)//0100时区
df.calendar = Calendar(identifier: .chinese)//农历
print(df.string(from: Date()))
//0037-11-02 09:13:57
  • 日期
//开始日期
open var twoDigitStartDate: Date?
//默认日期
open var defaultDate: Date?
//公历开始时间
open var gregorianStartDate: Date?

twoDigitStartDate默认为1950-01-01 00:00:00 +0000。
defaultDate默认为nil。
gregorianStartDate默认为1582-10-15 00:00:00 +0000。

  • 其它
open var generatesCalendarDates: Bool
open var isLenient: Bool
open var doesRelativeDateFormatting: Bool

generatesCalendarDates默认为false。当为true时,在解析日期时会返回NSCalendarDate实例而不是NSDate,但NSCalendarDate在Swift中已不可用,因而generatesCalendarDates已失效。

isLenient默认为false,表示要严格按照dateFormat来格式化。当为true时,即使字符串与dateFormat有差距,也能成功转换为Date。

doesRelativeDateFormatting默认为false。当为true时,会以前天、昨天、今天、明天、后天来显示日期而不是通过年月日来显示。

let df = DateFormatter()
df.dateStyle = .medium
df.timeStyle = .medium
print(df.string(from: Date() + 3600*24))
//2020年12月18日 下午4:12:41
df.doesRelativeDateFormatting = true
print(df.string(from: Date() + 3600*24))
//明天 下午4:12:41
  1. 标志符的替换

注意:标志符在不同的本地化下为不同的结果。

  • 纪元标志符
open var eraSymbols: [String]!
open var longEraSymbols: [String]!

eraSymbols默认为 ["公元前", "公元"]。
longEraSymbols默认为 ["公元前", "公元"]。
en_US本地化下,
eraSymbols默认为 ["BC", "AD"]。
longEraSymbols默认为 ["Before Christ", "Anno Domini"]。

dateFormat中输入G、GG、GGG时,则会匹配eraSymbols的内容。
输入GGGG时,则会匹配longEraSymbols的内容。

let df = DateFormatter()
df.locale = Locale(identifier: "en_US")
df.dateFormat = "yyyy-MM-dd HH:mm:ss G GG GGG GGGG GGGGG GGGGGG"
print(df.string(from: Date()))
//2020-12-17 14:29:30 AD AD AD Anno Domini A AD
df.eraSymbols = ["a", "a"]
df.longEraSymbols = ["b", "b"]
print(df.string(from: Date()))
//2020-12-17 14:29:30 a a a b A a
  • 月份标志符
open var monthSymbols: [String]!
open var shortMonthSymbols: [String]!
open var veryShortMonthSymbols: [String]!

open var standaloneMonthSymbols: [String]!
open var shortStandaloneMonthSymbols: [String]!
open var veryShortStandaloneMonthSymbols: [String]!

monthSymbolsstandaloneMonthSymbols默认为 ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]。
shortMonthSymbolsshortStandaloneMonthSymbols默认为 ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"]。
veryShortMonthSymbolsveryShortStandaloneMonthSymbols默认为 ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]。
en_US本地化下,
monthSymbolsstandaloneMonthSymbols默认为 ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]。
shortMonthSymbolsshortStandaloneMonthSymbols默认为 ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]。
veryShortMonthSymbolsveryShortStandaloneMonthSymbols默认为 ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"]。

standaloneMonthSymbolsshortStandaloneMonthSymbolsveryShortStandaloneMonthSymbols这三种并未测试出效果,不知在何处使用。

dateFormat中输入M时,会匹配无前导零的数字。
输入MM时,会匹配有前导零的数字。
输入MMM时,会匹配shortMonthSymbols的内容。
输入MMMM时,则会匹配monthSymbols的内容。
输入MMMMM时,则会匹配veryShortMonthSymbols的内容。

let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss M MM MMM MMMM MMMMM MMMMMM MMMMMMM"
print(df.string(from: Date()))
//2020-12-17 14:41:59 12 12 12月 十二月 12 000012 0000012
df.monthSymbols = ["a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a"]
df.shortMonthSymbols = ["b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b"]
df.veryShortMonthSymbols = ["c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c"]
print(df.string(from: Date()))
//2020-12-17 14:41:59 12 12 b a c 000012 0000012
  • 星期标志符
open var weekdaySymbols: [String]!
open var shortWeekdaySymbols: [String]!
open var veryShortWeekdaySymbols: [String]!

open var standaloneWeekdaySymbols: [String]!
open var shortStandaloneWeekdaySymbols: [String]!
open var veryShortStandaloneWeekdaySymbols: [String]!

weekdaySymbolsstandaloneWeekdaySymbols默认为 ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]。
shortWeekdaySymbolsshortStandaloneWeekdaySymbols默认为 ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]。
veryShortWeekdaySymbolsveryShortStandaloneWeekdaySymbols默认为 ["日", "一", "二", "三", "四", "五", "六"]。
en_US本地化下,
weekdaySymbolsstandaloneWeekdaySymbols默认为 ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]。
shortWeekdaySymbolsshortStandaloneWeekdaySymbols默认为 ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]。
veryShortWeekdaySymbolsveryShortStandaloneWeekdaySymbols默认为 ["S", "M", "T", "W", "T", "F", "S"]。

standaloneWeekdaySymbolsshortStandaloneWeekdaySymbolsveryShortStandaloneWeekdaySymbols这三种并未测试出效果,不知在何处使用。

dateFormat中输入E、EE、EEE、eee时,会匹配shortWeekdaySymbols的内容。
输入EEEE、eeee时,则会匹配weekdaySymbols的内容。
输入EEEEE、eeeee时,则会匹配veryShortWeekdaySymbols的内容。
输入e时,会匹配无前导零的数字(该周的第几天)。
输入ee时,会匹配前导零的数字(该周的第几天)。

let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss E EE EEE EEEE EEEEE e ee eee eeee eeeee"
print(df.string(from: Date()))
2020-12-17 16:41:14 周四 周四 周四 星期四 四 5 05 周四 星期四 四
df.weekdaySymbols = ["a", "a", "a", "a", "a", "a", "a"]
df.shortWeekdaySymbols = ["b", "b", "b", "b", "b", "b", "b"]
df.veryShortWeekdaySymbols = ["c", "c", "c", "c", "c", "c", "c"]
print(df.string(from: Date()))
2020-12-17 16:41:14 b b b a c 5 05 b a c
  • 时间段标志符
open var amSymbol: String!
open var pmSymbol: String!

amSymbol默认为 上午。
pmSymbol默认为 下午。
en_US本地化下,
amSymbol默认为 AM。
pmSymbol默认为 PM。

dateFormat中输入a时会匹配amSymbol或pmSymbol的内容,输入多个a无影响。

let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss a aa"
print(df.string(from: Date()))
//2020-12-17 15:15:39 下午 下午
df.amSymbol = "午前"
df.pmSymbol = "午后"
//2020-12-17 15:15:39 午后 午后
print(df.string(from: Date()))
  • 季度标志符
open var quarterSymbols: [String]!
open var shortQuarterSymbols: [String]!

open var standaloneQuarterSymbols: [String]!
open var shortStandaloneQuarterSymbols: [String]!

quarterSymbolsstandaloneQuarterSymbols默认为 ["第一季度", "第二季度", "第三季度", "第四季度"]。
shortQuarterSymbolsshortStandaloneQuarterSymbols默认为 ["1季度", "2季度", "3季度", "4季度"]。
en_US本地化下,
quarterSymbolsstandaloneQuarterSymbols默认为 ["1st quarter", "2nd quarter", "3rd quarter", "4th quarter"]。
shortQuarterSymbolsshortStandaloneQuarterSymbols默认为 ["Q1", "Q2", "Q3", "Q4"]。

dateFormat中输入q、Q时,会匹配无前导零的数字。
输入qq、QQ时,会匹配有前导零的数字。
输入qqq时,会匹配shortStandaloneQuarterSymbols的内容。
输入qqqq时,则会匹配standaloneQuarterSymbols的内容。
输入QQQ时,则会匹配shortQuarterSymbols的内容。
输入QQQQ时,则会匹配quarterSymbols的内容。

let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss q qq qqq qqqq Q QQ QQQ QQQQ"
print(df.string(from: Date()))
//2020-12-17 15:26:16 4 04 4季度 第四季度 4 04 4季度 第四季度
df.quarterSymbols = ["a", "a", "a", "a"]
df.shortQuarterSymbols = ["b", "b", "b", "b"]
df.standaloneQuarterSymbols = ["c", "c", "c", "c"]
df.shortStandaloneQuarterSymbols = ["d", "d", "d", "d"]
print(df.string(from: Date()))
//2020-12-17 15:26:16 4 04 d c 4 04 b a
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容