Auch bei Swift Zeitstempel in Nanosekunden!

Zeitstempel in Nanosekunden sind einfach.

Ja, in C-Sprache. Der Funktionsname unterscheidet sich jedoch von "clock_gettime ()" unter Linux und "clock_get_time ()" unter OS X. Der Name der Struktur, die die Zeit in Nanosekunden darstellt, ist ebenfalls unterschiedlich. Das Verfahren zum Abrufen eines Zeitstempels unter Verwendung dieser Struktur ist ebenfalls unterschiedlich. Swift kann C-Sprachfunktionen verwenden, und Swift ist jetzt sowohl unter Linux als auch unter OS X verfügbar. Lassen Sie uns diesen Unterschied also mit Swift aufgreifen.

einpacken

Versuchte es zu schaffen. Und auf GitHub veröffentlicht. Es ist eine MIT-Lizenz.

Quellcode

Es gibt nur eine Datei. Ich habe versucht, die Datei [TimeSpecification.swift] zu benennen (https://github.com/YOCKOW/SwiftTimeSpecification/blob/master/Sources/Library/TimeSpecification.swift). Und ich habe versucht, die Struktur in Swift "Time Specification" zu benennen. Die einzigen Eigenschaften (gespeicherte Eigenschaft) sind "Sekunden" und "Nanosekunden". Das Folgende ist ein Auszug und eine Erklärung. Die Reihenfolge der Erklärungen und die Reihenfolge des Codes in der Quelle stimmen nicht immer überein, also keine Angst ... Ich habe nichts Schwieriges getan. Das kann ich nicht sagen.

Ein Zauber, der den Unterschied im Betriebssystem aufnimmt

Importieren, damit Sie die standardmäßige betriebssystemspezifische Bibliothek verwenden können. Glibc für Linux, Darwin für OS X. Die Nanosekundenzeit wird unter Linux durch "struct timespec" und unter OS X durch "mach_timespec_t" ("typedef struct mach_timespec mach_timespec_t;") dargestellt. In beiden Fällen werden Sekunden durch das Element ".tv_sec" und Nanosekunden durch das Element ".tv_nsec" dargestellt. ".Tv_sec" ist jedoch "time_t" in "struct timespec", aber "unsigned int" [^ tv_sec_unsigned_int] in "mach_timespec_t" und ".tv_nsec" ist "long" und "clock_res_t" ("typedef int clock_res_t"). `) Aber der Inhalt ist völlig anders. Nennen wir beide "CTimeSpec" einmal mit "typealias".

[^ tv_sec_unsigned_int]: 2106 issue tritt wahrscheinlich auf

#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

Das Initialisieren der "Zeitspezifikation" mit der "C-Zeitspezifikation" ist einfach. Was Sie tun können, weil die Mitgliedsnamen für struct timespec und mach_timespec_t gleich sind:

extension TimeSpecification {
  fileprivate init(_ cts:CTimeSpec) {
    self.seconds = Int64(cts.tv_sec)
    self.nanoseconds = Int32(cts.tv_nsec)
  }
}

Nun die Definition der Zeitspezifikation

In Anbetracht der Verwendung wenden wir das Protokoll "Vergleichbar" an. Außerdem dachte ich, es wäre bequem, "ExpressibleByIntegerLiteral" und "ExpressibleByFloatLiteral" anzuwenden ... Wenn wir addieren oder subtrahieren, normalisieren wir auch "Nanosekunden", so dass es immer eine nicht negative ganze Zahl ist, so dass ein einmaliger Ausdruck eindeutig bestimmt wird.

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
    }
  }
}

Wie bekomme ich einen Zeitstempel?

Ich habe mich gefragt, welche Art von Spezifikation ich verwenden soll, aber hier habe ich eine Aufzählung namens "Clock" definiert und versucht, sie mit dieser Methode zu erhalten. Holen Sie sich beispielsweise die Systemuhr mit let now = Clock.System.timeSpecification (). Verwenden Sie in der Methode die C-Sprach-API unverändert. Anscheinend kann es fehlschlagen, also habe ich beschlossen, es als optional zurückzugeben. Wenn Sie die Kalenderuhr in OS X angeben, können Sie die Zeit anscheinend nur in Mikrosekunden abrufen.

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
  }
}

Bonus

Wenn überhaupt, das Ruby-Skript build-install.rb, mit dem die Bibliothek einfach erstellt werden kann Es dauerte eine lange Zeit. Obwohl es sich um ein Swift-Projekt handelt, macht Ruby-Code 40% aus. Tehe.

Recommended Posts

Auch bei Swift Zeitstempel in Nanosekunden!
Teilen wird in Swift zu 0
Mehrdimensionales Array in Swift
Fotobibliothek mit Swift UI