Yes, in C language.
However, the function name is different from clock_gettime ()
on Linux and clock_get_time ()
on OS X. The names of structures that represent time in nanoseconds are also different. The procedure for getting a time stamp using that structure is also different.
Swift can use C functions, and Swift is now available on both Linux and OS X, so let's absorb this difference with Swift.
Tried to make it. Then published on GitHub. It's an MIT license.
There is only one file. I tried to name the file TimeSpecification.swift.
And I named the structure in Swift TimeSpecification
. The only properties (stored property) are seconds
and nanoseconds
.
The following is an excerpt and explanation. The order of the explanations and the order of the code in the source do not always match, so don't be afraid ...
I haven't done anything difficult. I can't say that.
ʻImportso that you can use the OS-specific standard library.
Glibc for Linux,
Darwinfor OS X. The nanosecond time is represented by
struct timespec on Linux and
mach_timespec_t (
typedef struct mach_timespec mach_timespec_t;) on OS X. In both cases, seconds are represented by the member
.tv_sec and nanoseconds are represented by the member
.tv_nsec. However,
.tv_sec is
time_tin
struct timespec, but ʻunsigned int
[^ tv_sec_unsigned_int] in mach_timespec_t
, and .tv_nsec
is long
and clock_res_t
(typedef int clock_res_t;
) But the contents are completely different.
So, let's name both CTimeSpec
once with typealias
.
[^ tv_sec_unsigned_int]: 2106 issue is likely to occur
#if os(Linux)
import Glibc
private typealias CTimeSpec = timespec
#elseif os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
import Darwin
private let mach_task_self:() -> mach_port_t = { return mach_task_self_ }
private typealias CTimeSpec = mach_timespec_t
#else
// UNKNOWN OS
#endif
Initializing the Time Specification
with the C Time Spec
is easy. What you can do because the member names are the same for both struct timespec
and mach_timespec_t
:
extension TimeSpecification {
fileprivate init(_ cts:CTimeSpec) {
self.seconds = Int64(cts.tv_sec)
self.nanoseconds = Int32(cts.tv_nsec)
}
}
Considering the usage, let's apply the Comparable
protocol. After that, I thought it would be convenient to apply ʻExpressibleByIntegerLiteral and ʻExpressibleByFloatLiteral
...
Also, when adding or subtracting, let's normalize nanoseconds
so that it is always a non-negative integer so that one time representation is uniquely determined.
public struct TimeSpecification: Comparable,
ExpressibleByIntegerLiteral,
ExpressibleByFloatLiteral {
public var seconds:Int64 = 0
public var nanoseconds:Int32 = 0 {
didSet { self.normalize() }
}
public init(seconds:Int64, nanoseconds:Int32) {
self.seconds = seconds
self.nanoseconds = nanoseconds
self.normalize()
}
public mutating func normalize() {
// `nanoseconds` must be always zero or positive value and less than 1_000_000_000
if self.nanoseconds >= 1_000_000_000 {
self.seconds += Int64(self.nanoseconds / 1_000_000_000)
self.nanoseconds = self.nanoseconds % 1_000_000_000
} else if self.nanoseconds < 0 {
// For example,
// (seconds:3, nanoseconds:-2_123_456_789)
// -> (seconds:0, nanoseconds:876_543_211)
self.seconds += Int64(self.nanoseconds / 1_000_000_000) - 1
self.nanoseconds = self.nanoseconds % 1_000_000_000 + 1_000_000_000
}
}
}
I was wondering what the specification should be, but here I defined a ʻenum called
Clockand tried to get it using that method. For example, get the system clock with
let now = Clock.System.timeSpecification ()`.
In the method, use the C language API as it is. Apparently, it may fail to get it, so I decided to return it as Optional.
If you specify the calendar clock on OS X, it seems that you can only get the time in microseconds.
public enum Clock {
case Calendar
case System
public func timeSpecification() -> TimeSpecification? {
var c_timespec:CTimeSpec = CTimeSpec(tv_sec:0, tv_nsec:0)
let clock_id:CInt
var retval:CInt = -1
#if os(Linux)
clock_id = (self == .Calendar) ? CLOCK_REALTIME : CLOCK_MONOTONIC
retval = clock_gettime(clock_id, &c_timespec)
#elseif os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
var clock_name: clock_serv_t = 0
clock_id = (self == .Calendar) ? CALENDAR_CLOCK : SYSTEM_CLOCK
retval = host_get_clock_service(mach_host_self(), clock_id, &clock_name)
if retval != 0 { return nil }
retval = clock_get_time(clock_name, &c_timespec)
_ = mach_port_deallocate(mach_task_self(), clock_name)
#endif
return (retval == 0) ? TimeSpecification(c_timespec) : nil
}
}
If anything, the Ruby script build-install.rb written to make it easier to build the library. It took a long time. In fact, even though it is a Swift project, Ruby code occupies 40%. Tehe.