Попытка конвертировать временную метку Firebase в NSDate в Swift

Я пытаюсь использовать Firebase timestamps в приложении Swift. Я хотел бы сохранить их в своей Firebase и использовать их как собственные объекты NSDate в своем приложении.

Документы говорят, что они являются временем эпохи unix, поэтому я пробовал:

NSDate(timeIntervalSince1970:FirebaseServerValue.timestamp)

без везения.

Это:

FirebaseServerValue.timestamp

возвращает

0x00000001199298a0

в соответствии с отладчиком. Каков наилучший способ передать эти временные метки?

Ответы

Ответ 1

ServerValue.timestamp() работает немного иначе, чем установка обычных данных в Firebase. На самом деле это не временная метка. Вместо этого он предоставляет значение, которое сообщает серверу Firebase, чтобы заполнить этот node временем. Используя это, ваши временные метки приложения будут поступать из одного источника Firebase, а не из того, что говорит пользовательское устройство.

Когда вы получите значение обратно (от наблюдателя), вы получите время в миллисекундах с эпохи. Для создания NSDate вам нужно будет преобразовать его в несколько секунд. Вот фрагмент кода:

let ref = Firebase(url: "<FIREBASE HERE>")

// Tell the server to set the current timestamp at this location.
ref.setValue(ServerValue.timestamp()) 

// Read the value at the given location. It will now have the time.
ref.observeEventType(.Value, withBlock: { 
    snap in
    if let t = snap.value as? NSTimeInterval {
        // Cast the value to an NSTimeInterval
        // and divide by 1000 to get seconds.
        println(NSDate(timeIntervalSince1970: t/1000))
    }
})

Вы можете обнаружить, что вы получаете два события с очень близкими отметками времени. Это связано с тем, что SDK будет принимать наилучшее "угадывание" на отметке времени, прежде чем он услышит от Firebase. Как только он услышит фактическое значение из Firebase, он снова вызовет событие Value.

Ответ 2

Этот вопрос старый, но у меня недавно была такая же проблема, поэтому я дам ответ.

Здесь вы можете увидеть, как я сохраняю временную метку в базе данных Firebase

 let feed = ["userID": uid,
             "pathToImage": url.absoluteString,
             "likes": 0,
             "author": Auth.auth().currentUser!.displayName!,
             "postDescription": self.postText.text ?? "No Description",
             "timestamp": [".sv": "timestamp"],
             "postID": key] as [String: Any]

 let postFeed = ["\(key)" : feed]

 ref.child("posts").updateChildValues(postFeed)

Особенно актуальной линией кода является "timestamp": [".sv": "timestamp"],

Это сохраняет временную метку как двойную в вашей базе данных. Это время в миллисекундах, поэтому вам нужно разделить на 1000, чтобы получить время в секундах. На этом изображении вы можете увидеть примерную метку времени. Временная метка Firebase

Чтобы преобразовать этот двойник в дату, я написал следующую функцию:

func convertTimestamp(serverTimestamp: Double) -> String {
        let x = serverTimestamp / 1000
        let date = NSDate(timeIntervalSince1970: x)
        let formatter = DateFormatter()
        formatter.dateStyle = .long
        formatter.timeStyle = .medium

        return formatter.string(from: date as Date)
    }

Это дает временную метку, которая выглядит так: Временная метка

Ответ 3

Вы получите нужное время, если используете:

let timestamp = FIRServerValue.timestamp()

let converted = NSDate(timeIntervalSince1970: timestamp / 1000)


let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone.localTimeZone()
dateFormatter.dateFormat = "hh:mm a"
let time = dateFormatter.stringFromDate(converted)

Ответ 4

let serverTimeStamp = ServerValue.timestamp() as! [String:Any]

Хранить в Firebase что-то вроде [ktimeStamp:timestamp as AnyObject] чем после преобразования в секундах с использованием Firebase Server Time:

let timestampDate = NSDate(timeIntervalSince1970: Double(timestamp as! NSNumber)/1000)

Ответ 5

У Firestore есть API для этого → - (NSDate *) dateValue

Например, если вы сохранили (установили) новый документ с полем "creationAtDate"

    NSDictionary *dataToBeSaved = @{
        //Tell the server to save FIRTimestamps when the document is created
        @"createdAtDate":[FIRFieldValue fieldValueForServerTimestamp],
        @"lastModifiedDate":[FIRFieldValue fieldValueForServerTimestamp],

       //Other fields
       @"userName":@"Joe Blow"
    }

    [myFirReference setData:[dataToBeSaved]
                    options:[FIRSetOptions merge]
                 completion:^(NSError* error) {
  }

Вы можете получить эту информацию либо с помощью запроса get, либо через настройку слушателя. Когда вы вернете моментальный снимок, просто получите доступ к датам, которые вы сохранили, и конвертируйте их в NSDate.

  NSDate *date1 = [snapshot.data[@"createdAtDate"] dateValue];
  NSDate *date2 = [snapshot.data[@"lastModifiedDate"] dateValue];

Точность будет незначительной, но, поскольку большинство людей используют даты для синхронизации или сортировки данных, я не могу вспомнить случай, когда потеря точности была бы проблемой.

Ответ 6

Вы можете создать новый преобразователь для ObjectMapper,

import Foundation
import ObjectMapper

class FirebaseDateTransform: TransformType {
    public typealias Object = Date
    public typealias JSON = Double

    open func transformFromJSON(_ value: Any?) -> Date? {
        if let millisecondsSince1970 = value as? Double {
            return Date(timeIntervalSince1970: millisecondsSince1970 / 1000.0)
        }

        return nil
    }

    open func transformToJSON(_ value: Date?) -> Double? {
        if let date = value {
            return Double(date.timeIntervalSince1970) * 1000.0
        }

        return nil
    }
}

Суть

Ответ 7

Вот некоторый код, основанный на ответе alicanbatur, который позволяет дате быть двойной или серверной меткой времени, и все же работать в слое отображения объектов, таком как ObjectMapper.

enum FirebaseDate {
    case date(Date)
    case serverTimestamp

    var date: Date {
        switch self {
        case .date(let date):
            return date
        case .serverTimestamp:
            return Date()
        }
    }
}

class FirebaseDateTransform: TransformType {
    public typealias Object = FirebaseDate
    public typealias JSON = Any

    open func transformFromJSON(_ value: Any?) -> FirebaseDate? {
        switch value {
        case let millisecondsSince1970 as Double:
            let date = Date(millisecondsSince1970: millisecondsSince1970)
            return .date(date)
        case is [AnyHashable: Any]?:
            return .serverTimestamp
        default:
            return nil
        }
    }

    open func transformToJSON(_ value: FirebaseDate?) -> Any? {
        switch value {
        case .date(let date)?:
            return date.millisecondsSince1970
        case .serverTimestamp?:
            return ServerValue.timestamp()
        default:
            return nil
        }
    }
}

Ответ 8

Вы можете получить приблизительную дату от Firebase. Например, если вы пытаетесь изменить дату создания пользователя Firebase (Timestamp) на Date:

user.creationDate.dateValue()

Ответ 9

Swift 4 и обновленный вариант библиотеки Firebase ответа Katfang:

let currentTimeStamp: TimeInterval?

let ref = Database.database().reference().child("serverTimestamp")

ref.setValue(ServerValue.timestamp())

ref.observe(.value, with: { snap in
    if let t = snap.value as? TimeInterval {
    print(t/1000)
    currentTimeStamp = t/1000
    }
})

Ответ 10

Для меня в Swift 5 использовать в другом классе:

import FirebaseFirestore
init?(document: QueryDocumentSnapshot) {
        let data = document.data()
       guard let stamp = data["timeStamp"] as? Timestamp else {
            return nil
        }
       let date = stamp.dateValue()
}