Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get build date and time in Swift

I'm using __DATE__ and __TIME__ in Objective-C to get the build date and time of my app. I can't find a way to get this information in Swift. Is it possible?

like image 861
David Potter Avatar asked Nov 08 '14 01:11

David Potter


People also ask

What is NSDate in Swift?

A representation of a specific point in time, for use when you need reference semantics or other Foundation-specific behavior.

What is timestamp in Swift?

It's a formatter that converts between dates and their textual representations. Instances of DateFormatter create string representations of NSDate objects, and convert textual representations of dates and times into NSDate objects.

How do you initialize a date in Swift?

Creating a Date and Time in Swift Of course, it would be easier to use things like years, months, days and hours (rather than relative seconds) to make a Date . For this you can use DateComponents to specify the components and then Calendar to create the date. The Calendar gives the Date context.


4 Answers

You can get the build date and time without reverting to objective-C. When the app is built, the Info.plist file placed in the bundle is always created from the one in your project. So the creation date of that file matches the build date and time. You can always read files in your app's bundle and get their attributes. So you can get the build date in Swift by accessing its Info.plist file attributes:

 var buildDate:NSDate 
 {
     if let infoPath = NSBundle.mainBundle().pathForResource("Info.plist", ofType: nil),
        let infoAttr = try? NSFileManager.defaultManager().attributesOfItemAtPath(infoPath),
        let infoDate = infoAttr["NSFileCreationDate"] as? NSDate
     { return infoDate }
     return NSDate()
 }

Note: this is the post that got me to use the bridging header when I initially had this problem. I found this "Swiftier" solution since then so I thought I'd share it for future reference.

[EDIT] added compileDate variable to get the latest compilation date even when not doing a full build. This only has meaning during development since you're going to have to do a full build to release the application on the app store but it may still be of some use. It works the same way but uses the bundled file that contains the actual code instead of the Info.plist file.

var compileDate:Date
{
    let bundleName = Bundle.main.infoDictionary!["CFBundleName"] as? String ?? "Info.plist"
    if let infoPath = Bundle.main.path(forResource: bundleName, ofType: nil),
       let infoAttr = try? FileManager.default.attributesOfItem(atPath: infoPath),
       let infoDate = infoAttr[FileAttributeKey.creationDate] as? Date
    { return infoDate }
    return Date()
}
like image 92
Alain T. Avatar answered Sep 19 '22 20:09

Alain T.


You can use #line, #column, and #function.


Original answer:

Create a new Objective-C file in your project, and when Xcode asks, say yes to creating the bridging header.

In this new Objective-C file, add the following the the .h file:

NSString *compileDate();
NSString *compileTime();

And in the .m implement these functions:

NSString *compileDate() {
    return [NSString stringWithUTF8String:__DATE__];
}

NSString *compileTime() {
    return [NSString stringWithUTF8String:__TIME__];
}

Now go to the bridging header and import the .h we created.

Now back to any of your Swift files:

println(compileDate() + ", " + compileTime())
like image 25
nhgrif Avatar answered Sep 19 '22 20:09

nhgrif


Swift 5 version of Alain T's answer:

var buildDate: Date {
    if let infoPath = Bundle.main.path(forResource: "Info", ofType: "plist"),
        let infoAttr = try? FileManager.default.attributesOfItem(atPath: infoPath),
        let infoDate = infoAttr[.modificationDate] as? Date {
        return infoDate
    }
    return Date()
}
like image 40
Brian Hong Avatar answered Sep 19 '22 20:09

Brian Hong


A Tamperproof, Swift-Only Approach:

  1. Add a new Run Script build phase to your app and MAKE SURE it is set to run before the Compile Sources phase.

  2. Add this as the code in that script:

#!/bin/bash

timestamp=$(date +%s)
echo "import Foundation;let appBuildDate: Date = Date(timeIntervalSince1970: $timestamp)" > ${PROJECT_DIR}/Path/To/Some/BuildTimestamp.swift
  1. Create the file BuildTimestamp.swift at some path in your project, then make sure the output path in the script above matches where that file exists, relative to the project's root folder.

  2. You now have a global appBuildDate that can be used anywhere in your project. (Build the project once before using the variable so that the script creates it in the file you specified.)

  3. Optional: if you'd like the date to update in incremental builds, be sure to uncheck the "based on dependency analysis" checkbox in the Run Script phase you created.

Advantages:

  1. It's automatic.

  2. It can't be affected by users changing the modification/creation date of various files in the app bundle (a concern on macOS).

  3. It doesn't need the old __TIME__ and __DATE__ from C.

  4. It's already a Date and ready to be used, as-is.

like image 33
Bryan Avatar answered Sep 19 '22 20:09

Bryan