Swift - iOS - 不同格式的日期和时间

48

我正在为一个使用Swift编写的应用程序工作,我想要操作日期和时间。

let timestamp = NSDateFormatter.localizedStringFromDate(
    NSDate(),
    dateStyle: .ShortStyle,
    timeStyle: .ShortStyle
)

返回

2/12/15, 11:27 PM

如果我想以不同的格式显示日期和时间,例如以欧洲格式显示日期,如dd/mm/yy,并以24小时格式显示小时而不带上午/下午。是否有某个函数可以使用,还是我必须使用N个字符串来重新排序各种元素?


可能是重复的问题,参见如何获取当前时间作为datetime - shim
17个回答

66
func convertDateFormater(date: String) -> String {   
    let dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
    dateFormatter.timeZone = NSTimeZone(name: "UTC")

    guard let date = dateFormatter.dateFromString(date) else {
        assert(false, "no date from string")
        return ""
    }

    dateFormatter.dateFormat = "yyyy MMM EEEE HH:mm"
    dateFormatter.timeZone = NSTimeZone(name: "UTC")
    let timeStamp = dateFormatter.stringFromDate(date)

    return timeStamp
}

Swift 4版修改

func convertDateFormatter(date: String) -> String {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"//this your string date format
    dateFormatter.timeZone = NSTimeZone(name: "UTC") as TimeZone!
    dateFormatter.locale = Locale(identifier: "your_loc_id")
    let convertedDate = dateFormatter.date(from: date)

    guard dateFormatter.date(from: date) != nil else {
        assert(false, "no date from string")
        return ""
    } 

    dateFormatter.dateFormat = "yyyy MMM HH:mm EEEE"///this is what you want to convert format
    dateFormatter.timeZone = NSTimeZone(name: "UTC") as TimeZone!
    let timeStamp = dateFormatter.string(from: convertedDate!)

    return timeStamp
}

20
你应该为你的回答添加更多解释。仅仅复制代码不符合 StackOverflow 的风格 :) - tottotech
4
这个方法看起来很不错,但是它要求输入日期为字符串格式。大多数情况下,您的起点是NSDate类型的。在传递给此函数之前,最好的方法是如何将其格式化为字符串? - tylerSF
+1 for: dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"需要处理带有时区的日期,并使用此方法可以轻松地将格式化程序字符串转换为日期。 - Paula Hasstenteufel

33

正如先前提到的,您需要使用DateFormatter来格式化日期对象。最简单的方法是创建一个只读的计算属性(Date extension)。


只读计算属性

具有getter但没有setter的计算属性称为只读计算属性。只读计算属性始终返回一个值,并且可以通过点语法访问,但不能设置为不同的值。

注意:

您必须使用var关键字声明计算属性,包括只读计算属性,因为它们的值是不固定的。let关键字仅用于常量属性,以表明它们一旦作为实例初始化的一部分被设置,其值就无法更改。

您可以通过删除get关键字及其括号来简化只读计算属性的声明:


extension Formatter {
    static let date = DateFormatter()
}

extension Date {
    var europeanFormattedEn_US : String {
        Formatter.date.calendar = Calendar(identifier: .iso8601)
        Formatter.date.locale   = Locale(identifier: "en_US_POSIX")
        Formatter.date.timeZone = .current
        Formatter.date.dateFormat = "dd/M/yyyy, H:mm"
        return Formatter.date.string(from: self)
    }
}

要将其转换回来,您可以创建另一个只读的计算属性,但作为字符串扩展:

 extension String {
    var date: Date? {
        return Formatter.date.date(from: self)
    }
    func dateFormatted(with dateFormat: String = "dd/M/yyyy, H:mm", calendar: Calendar = Calendar(identifier: .iso8601), defaultDate: Date? = nil, locale: Locale = Locale(identifier: "en_US_POSIX"), timeZone: TimeZone = .current) -> Date? {
        Formatter.date.calendar = calendar
        Formatter.date.defaultDate = defaultDate ?? calendar.date(bySettingHour: 12, minute: 0, second: 0, of: Date())
        Formatter.date.locale = locale
        Formatter.date.timeZone = timeZone
        Formatter.date.dateFormat = dateFormat
        return Formatter.date.date(from: self)
    }
}

使用方法:

let dateFormatted = Date().europeanFormattedEn_US         //"29/9/2018, 16:16"
if let date = dateFormatted.date {
    print(date.description(with:.current)) // Saturday, September 29, 2018 at 4:16:00 PM Brasilia Standard Time\n"\
    date.europeanFormattedEn_US                         // "29/9/2018, 16:27"
}

let dateString = "14/7/2016"
if let date = dateString.toDateFormatted(with: "dd/M/yyyy") {
    print(date.description(with: .current))
 // Thursday, July 14, 2016 at 12:00:00 PM Brasilia Standard Time\n"
}

4
为什么需要扩展,简单的方法有什么问题吗? - zaph
1
每个日期格式都有不同的扩展名?扩展名是用户所期望的吗?该扩展名是否通过了is-a测试?asDate是一个字符串? - zaph
找点别的事情做。 - Leo Dabus
15
我不会删除我的答案,因为你不喜欢它。 - Leo Dabus
1
@Zaph 我已添加了一个方法,如你所要求的,以便在需要时自定义日期格式。你还需要什么? - Leo Dabus

12

正如Zaph所说,您需要遵循文档。与其他类参考相比,它可能并不是最直接的。简短的答案是,您可以使用日期字段符号表来确定您想要的格式。一旦您这样做了:

let dateFormatter = NSDateFormatter()
//the "M/d/yy, H:mm" is put together from the Symbol Table
dateFormatter.dateFormat = "M/d/yy, H:mm"
dateFormatter.stringFromDate(NSDate())

如果需要将字符串日期转换为NSDate,您还需要能够使用表格。

let dateAsString = "02/12/15, 16:48"
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "M/d/yyyy, H:mm"
let date = dateFormatter.dateFromString(dateAsString)

11

当前日期时间格式化为字符串:

let currentDate = Date()
let dateFormatter = DateFormatter()

dateFormatter.dateFormat = "dd/MM/yyyy hh:mm:ss a"
let convertedDate: String = dateFormatter.string(from: currentDate) //08/10/2016 01:42:22 AM

更多日期时间格式


5

在一个地方添加了一些格式,希望能帮到某些人。

Xcode 12 - Swift 5.3

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm:ss"
var dateFromStr = dateFormatter.date(from: "12:16:45")!

dateFormatter.dateFormat = "hh:mm:ss a 'on' MMMM dd, yyyy"
//Output: 12:16:45 PM on January 01, 2000

dateFormatter.dateFormat = "E, d MMM yyyy HH:mm:ss Z"
//Output: Sat, 1 Jan 2000 12:16:45 +0600

dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
//Output: 2000-01-01T12:16:45+0600

dateFormatter.dateFormat = "EEEE, MMM d, yyyy"
//Output: Saturday, Jan 1, 2000

dateFormatter.dateFormat = "MM-dd-yyyy HH:mm"
//Output: 01-01-2000 12:16

dateFormatter.dateFormat = "MMM d, h:mm a"
//Output: Jan 1, 12:16 PM

dateFormatter.dateFormat = "HH:mm:ss.SSS"
//Output: 12:16:45.000

dateFormatter.dateFormat = "MMM d, yyyy"
//Output: Jan 1, 2000

dateFormatter.dateFormat = "MM/dd/yyyy"
//Output: 01/01/2000

dateFormatter.dateFormat = "hh:mm:ss a"
//Output: 12:16:45 PM

dateFormatter.dateFormat = "MMMM yyyy"
//Output: January 2000

dateFormatter.dateFormat = "dd.MM.yy"
//Output: 01.01.00

//Output: Customisable AP/PM symbols
dateFormatter.amSymbol = "am"
dateFormatter.pmSymbol = "Pm"
dateFormatter.dateFormat = "a"
//Output: Pm

// Usage
var timeFromDate = dateFormatter.string(from: dateFromStr)
print(timeFromDate)

4

4

如果您想使用面向协议的编程(Swift 3)

1)创建一个可日期化协议(Dateable protocol)

protocol Dateable {
    func userFriendlyFullDate() -> String
    func userFriendlyHours() -> String
}

2) 扩展Date类并实现Dateable协议

extension Date: Dateable {
    var  formatter: DateFormatter { return DateFormatter() }

    /** Return a user friendly hour */
    func userFriendlyFullDate() -> String {
        // Customize a date formatter
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        formatter.timeZone = TimeZone(abbreviation: "UTC")

        return formatter.string(from: self)
    }

    /** Return a user friendly hour */
    func userFriendlyHours() -> String {
        // Customize a date formatter
        formatter.dateFormat = "HH:mm"
        formatter.timeZone = TimeZone(abbreviation: "UTC")

        return formatter.string(from: self)
    }
 
    // You can add many cases you need like string to date formatter

}

3)使用它

let currentDate: Date = Date()
let stringDate: String = currentDate.userFriendlyHours()
// Print 15:16

3
我使用了与@iod07类似的方法,但进行了扩展。同时,我在注释中添加了一些解释以便理解其工作原理。
基本上,只需将以下内容添加到您的视图控制器的顶部或底部即可。
extension NSString {

class func convertFormatOfDate(date: String, originalFormat: String, destinationFormat: String) -> String! {

    // Orginal format :
    let dateOriginalFormat = NSDateFormatter()
    dateOriginalFormat.dateFormat = originalFormat      // in the example it'll take "yy MM dd" (from our call)

    // Destination format :
    let dateDestinationFormat = NSDateFormatter()
    dateDestinationFormat.dateFormat = destinationFormat // in the example it'll take "EEEE dd MMMM yyyy" (from our call)

    // Convert current String Date to NSDate
    let dateFromString = dateOriginalFormat.dateFromString(date)

    // Convert new NSDate created above to String with the good format
    let dateFormated = dateDestinationFormat.stringFromDate(dateFromString!)

    return dateFormated

}
}

示例

假设您想将"16 05 05"转换为"Thursday 05 May 2016",并且您的日期声明如下:let date = "16 06 05"

然后只需调用:

let newDate = NSString.convertFormatOfDate(date, originalFormat: "yy MM dd", destinationFormat: "EEEE dd MMMM yyyy")

希望这能有所帮助!

@Ideaman,如果您需要帮助,请提供一些详细信息或解释。您的问题是什么? - tsnkff
哦,抱歉。它说dateFromString是空的。 - alvarlagerlof

3
以下是适用于Xcode 10.1(2019年2月23日)的解决方案:
func getCurrentDateTime() {

    let now = Date()
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "fr_FR")
    formatter.dateFormat = "EEEE dd MMMM YYYY"
    labelDate.text = formatter.string(from: now)
    labelDate.font = UIFont(name: "HelveticaNeue-Bold", size: 12)
    labelDate.textColor = UIColor.lightGray

    let text = formatter.string(from: now)
    labelDate.text = text.uppercased()
}

“Accueil”标签与代码没有连接。


@mswyss 我们可以使用一个字符串来添加多个国家(“fr_FR”,“en_US”等),还是需要像您所做的那样每次创建新行? - Benjamin Tourin

3

iOS 8+

明确指定 locale 很麻烦且困难,因为你不知道你的应用将在哪里使用。所以我认为,最好将 locale 设置为 Calender.current.locale 并使用 DateFormattersetLocalizedDateFormatFromTemplate 方法。

setLocalizedDateFormatFromTemplate(_:)

使用接收器的指定语言环境,从模板设置日期格式。 - developer.apple.com

extension Date {
    func convertToLocaleDate(template: String) -> String {
        let dateFormatter = DateFormatter()

        let calender = Calendar.current

        dateFormatter.timeZone = calender.timeZone
        dateFormatter.locale = calender.locale
        dateFormatter.setLocalizedDateFormatFromTemplate(template)

        return dateFormatter.string(from: self)
    }
}



Date().convertToLocaleDate(template: "dd MMMM YYYY")

我肯定是。 关于dateFormat,苹果公司表示:“仅在使用固定格式表示时设置此属性,如《使用固定格式日期表示》中所讨论的那样。对于用户可见的表示,您应该使用dateStyletimeStyle属性,或者如果无法使用预定义的样式实现所需的格式,则使用setLocalizedDateFormatFromTemplate(_:)方法;这两个属性和此方法都提供适合显示给用户的本地化日期表示。” - d4Rk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接