Is there any way to get actual current Date irrespective of system time and date?

If I create a form with a date input, I can only send current time and date. But if I change the system time than this will take wrong input. Is there any way to get actual current time and date??

Answered by DTS Engineer in 754364022

While my earlier approach does work, I think there’s an easier solution. This is based on the Posix clock API. The reason why I didn’t consider this earlier is that this API is a relatively recent addition, being added to the system in the 2016 OS release (macOS 10.12, iOS 10, and friends). See the clock_gettime man page for more background on this API.

The key thing to note here is that CLOCK_MONOTONIC ‘counts’ across sleep, unlikely the original Mach absolute time API. This allows your app to initially establish a trusted base time while the app is online and then determine a current trusted time relative to that.

The nice thing here is that there’s no messing around with other clocks, like gettimeofday, or with kern.boottime, which has always been a bit of a worry [1].

The main drawback continues to be that, if the user restarts their device, you can’t re-establish a trusted time until it comes online.

Oh, and it also raises the question about how to detect whether the device has been restarted. My recommendation is that you use a Posix semaphore for that. For example:

func restartState() -> RestartState {
    let sem = sem_open(NAME, O_CREAT | O_EXCL)
    if sem == SEM_FAILED {
        let err = errno
        switch err {
        case EEXIST: return .hasNotRestarted
        default: return .unknown(error: err)
        }
    } else {
        let ok = sem_close(sem) >= 0
        assert(ok)
        return .hasRestarted
    }
}

enum RestartState {
    case hasRestarted
    case hasNotRestarted
    case unknown(error: CInt)
}

The basic idea is:

  • Create a semaphore with the exclusive flag (O_EXCL).

  • If that works, the semaphore previously didn’t exist so this is the first time you’ve run this code since the device was restarted.

  • If it fails, you’ve run this code previously.

This relies on Posix semaphores being cleaned up on restart, which is a reasonable assumption IMO.

For more background on Posix semaphore, see sem_open man page.

The only tricky part here is the value to use for NAME. Posix semaphores are an IPC mechanism and the iOS sandbox puts strict limits on IPC. To avoid conflicts, set NAME to GGG/NNN, where GGG is an app group ID and NNN is a name of your choosing.

IMPORTANT Posix semaphore names are limited to 31 UTF-8 characters (PSEMNAMLEN) so use a short app group ID and name.

Note This convention was documented in the App Sandbox Design Guide, which is no longer available from Apple )-: [2] I’ve filed a bug (r. 110052019) to get it added to the App Groups Entitlement docs, which discusses Posix semaphores in the abstract but misses out this key detail.


Finally, I want to reiterate some points from my earlier post:

  • The best way to get a secure timestamp is to use the network to get it from some trusted source.

  • The technique described above is only relevant if you need to do this while the network is unavailable.

  • If you end up using this technique, please file an enhancement request explaining why you need a secure timestamp. And I’d appreciate you posting your bug number here, just for the record.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] My main concern here is kern.boottime, because it’s a source of entropy. See the footnote in this post.

[2] You can see an old copy of the Wayback Machine.

<https://web.archive.org/web/20221223145702mp_/https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24>

You’ll need to get it from a server, either your own or one (whose security) you trust.

What’s your high-level goal here? KMT et al are correct in that getting a timestamp from a trusted server is the only guaranteed solution to this problem. If that doesn’t work for you then there may be other paths you can take, but this depends on your specific requirements. If you can outline those requirements here, I’d be happy to elaborate.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

We have a option to mark attendance from application. So for that we need the current time to mark attendance. And if user is offline still he can mark attendance and this will sync later. So in this case if some one changes the system time, we can not get the actual time. In this way user can fake his attendance. We need a solution to get actual current time even if the user is offline. Or need to know if the time is mannually set or autometically so that we can restrict user. Please help.

Accepted Answer

As I mentioned earlier there’s no general solution to this problem, but there are steps you can take to improve the situation, either by tracking system clock changes or by detecting attempts to cheat.

There are basically two sources of time on iOS [1]:

  • Wall time, as returned by gettimeofday and things layered on top of that like NSDate

  • Mach absolute time, as returned by mach_absolute_time and things layered on top of that like CACurrentMediaTime

Neither of these will meet your requirements:

  • Wall time can be changed by the user, something you’ve already noticed

  • Mach absolute time gets reset when the device restarts, and stops ‘ticking’ when the device is asleep

Given the above, your only real option is to use the network to get a timestamp from some trusted source.


A common complaint about the above is that it does not work if the device has no Internet connection. Clearly that’s a problem for you, so I recommend that you file an enhancement request describing the trusted timestamp features that you need.

Please post your bug number, just for the record.


As to workarounds, the best workaround I’ve found so far is to exploit the fact that the kern.boottime sysctl variable is modified when a) the device restarts, and b) when the user adjusts the time [2]. So, when you have access to the network you should record a timestamp that consists of:

A. The value from your trusted source on the network

B. The value from gettimeofday (or NSDate)

C. The value of kern.boottime

Note You read the kern.boottime sysctl variable using sysctlbyname. For an example of how to do this, check out this post.

Later on, if you no longer have access to the network, you can call gettimeofday again (B'), and use the difference between A and B to calculate A'. You can then get kern.boottime again (C') and, if C' is approximately equal to C, you know that you can reasonably trust A'.

IMPORTANT I recommend that you ignore small changes to kern.boottime to avoid problems when the system does its regular time synchronisation. Some of that is done using adjtime, which doesn’t affect kern.boottime, but that’s not guaranteed to always be the case.

Of course, you should use the network for your default timestamp source and only rely on the above if you can’t get to the network.

The drawback to this approach is that, if the user restarts their device, your app won’t be able to get a trusted time value until they bring the device back on to the network. Ultimately you’ll have to decide if that’s an acceptable tradeoff.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"

[1] There are other sources of time (like GPS time, on devices with GPS, and the cellular network time, on devices with cellular) but neither of these are accessible via an API.

Also, moderns version of iOS have various clocks available via clock_gettime. While these don’t change the story for you, they can be useful in other situations. For example, CLOCK_MONOTONIC_RAW is like mach_absolute_time but it increments while the device is asleep (technically, it’s adjusted as the device comes out of sleep).

Dude. You are a godsend to this community. 👍

Thanks for the kind words. But actually I’m kinda cheating here (-: I didn’t have to research and write the above from scratch; it’s basically a copy’n’paste of a DTS response I sent to a developer last year.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

While my earlier approach does work, I think there’s an easier solution. This is based on the Posix clock API. The reason why I didn’t consider this earlier is that this API is a relatively recent addition, being added to the system in the 2016 OS release (macOS 10.12, iOS 10, and friends). See the clock_gettime man page for more background on this API.

The key thing to note here is that CLOCK_MONOTONIC ‘counts’ across sleep, unlikely the original Mach absolute time API. This allows your app to initially establish a trusted base time while the app is online and then determine a current trusted time relative to that.

The nice thing here is that there’s no messing around with other clocks, like gettimeofday, or with kern.boottime, which has always been a bit of a worry [1].

The main drawback continues to be that, if the user restarts their device, you can’t re-establish a trusted time until it comes online.

Oh, and it also raises the question about how to detect whether the device has been restarted. My recommendation is that you use a Posix semaphore for that. For example:

func restartState() -> RestartState {
    let sem = sem_open(NAME, O_CREAT | O_EXCL)
    if sem == SEM_FAILED {
        let err = errno
        switch err {
        case EEXIST: return .hasNotRestarted
        default: return .unknown(error: err)
        }
    } else {
        let ok = sem_close(sem) >= 0
        assert(ok)
        return .hasRestarted
    }
}

enum RestartState {
    case hasRestarted
    case hasNotRestarted
    case unknown(error: CInt)
}

The basic idea is:

  • Create a semaphore with the exclusive flag (O_EXCL).

  • If that works, the semaphore previously didn’t exist so this is the first time you’ve run this code since the device was restarted.

  • If it fails, you’ve run this code previously.

This relies on Posix semaphores being cleaned up on restart, which is a reasonable assumption IMO.

For more background on Posix semaphore, see sem_open man page.

The only tricky part here is the value to use for NAME. Posix semaphores are an IPC mechanism and the iOS sandbox puts strict limits on IPC. To avoid conflicts, set NAME to GGG/NNN, where GGG is an app group ID and NNN is a name of your choosing.

IMPORTANT Posix semaphore names are limited to 31 UTF-8 characters (PSEMNAMLEN) so use a short app group ID and name.

Note This convention was documented in the App Sandbox Design Guide, which is no longer available from Apple )-: [2] I’ve filed a bug (r. 110052019) to get it added to the App Groups Entitlement docs, which discusses Posix semaphores in the abstract but misses out this key detail.


Finally, I want to reiterate some points from my earlier post:

  • The best way to get a secure timestamp is to use the network to get it from some trusted source.

  • The technique described above is only relevant if you need to do this while the network is unavailable.

  • If you end up using this technique, please file an enhancement request explaining why you need a secure timestamp. And I’d appreciate you posting your bug number here, just for the record.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] My main concern here is kern.boottime, because it’s a source of entropy. See the footnote in this post.

[2] You can see an old copy of the Wayback Machine.

<https://web.archive.org/web/20221223145702mp_/https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24>

There is TrueTime.swift on GitHub: https://github.com/instacart/TrueTime.swift

It uses the NTP based approach

Is there any way to get actual current Date irrespective of system time and date?
 
 
Q