iOS Swift - получить текущее местное время и дату

Я пытаюсь сделать приложение для посещения, и я действительно смущен датой и временем в iOS и Firebase.

Я использую дату как ключ, это структура моей базы данных Firebase.

--Employees
  --Unique_ID
     --Details
          Name: John
     --Attendance
          --dateToday
              Timein: 8:00 AM
              Timeout: 5:00 PM
              BreakStart: 12:00 PM
              BreakFinish: 1:00 PM

Это мой код, чтобы получить метку даты, которую я использовал в качестве ключа

 override func viewDidLoad() {
     super.viewDidLoad()

     let now = NSDate()
     let nowTimeStamp = self.getCurrentTimeStampWOMiliseconds(dateToConvert: now)

     // I save this dateToday as Key in Firebase
     dateToday = nowTimeStamp
}


func getCurrentTimeStampWOMiliseconds(dateToConvert: NSDate) -> String {
    let objDateformat: DateFormatter = DateFormatter()
    objDateformat.dateFormat = "yyyy-MM-dd"
    let strTime: String = objDateformat.string(from: dateToConvert as Date)
    let objUTCDate: NSDate = objDateformat.date(from: strTime)! as NSDate
    let milliseconds: Int64 = Int64(objUTCDate.timeIntervalSince1970)
    let strTimeStamp: String = "\(milliseconds)"
    return strTimeStamp
}

Но когда я конвертирую его обратно, я получаю 2017-09-22 16:00:00 +0000, что неверно, потому что это 23 сентября в моем местоположении.

Каков правильный код для использования, чтобы я мог получить правильную метку даты и временную метку времени?

Ответы

Ответ 1

Для экономии текущего времени для базы данных firebase я использую Unic Epoch Conversation:

let timestamp = NSDate().timeIntervalSince1970

и для декодирования Unix Epoch time to Date().

let myTimeInterval = TimeInterval(timestamp)
let time = NSDate(timeIntervalSince1970: TimeInterval(myTimeInterval))

Ответ 2

Сначала я бы рекомендовал вам сохранить вашу метку времени как NSNumber в вашей базе данных Firebase, вместо того, чтобы хранить ее как String.

Еще одна вещь, о которой стоит упомянуть, заключается в том, что если вы хотите манипулировать датами с помощью Swift, вам лучше использовать Date вместо NSDate, за исключением случаев, когда вы взаимодействуете с некоторым кодом Obj-C в своем приложении.

Конечно, вы можете использовать оба варианта, но в документации указано:

Мосты даты в класс NSDate. Вы можете использовать их взаимозаменяемо в коде, который взаимодействует с API-интерфейсом Objective-C.

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

Например, если вы print(Date()), на данный момент вы получите:

2017-09-23 06:59:34 +0000

Это среднее время по Гринвичу (GMT).

Поэтому, в зависимости от того, где вы находитесь (или где находятся ваши пользователи), вам необходимо настроить часовой пояс до (или после того, как вы попытаетесь получить доступ к данным, например), сохраняя Date:

    let now = Date()

    let formatter = DateFormatter()

    formatter.timeZone = TimeZone.current

    formatter.dateFormat = "yyyy-MM-dd HH:mm"

    let dateString = formatter.string(from: now)

Затем у вас есть правильно отформатированная String, отражающая текущее время в вашем местоположении, и вы можете делать все, что хотите, с ней :) (конвертируйте его в Date/NSNumber или храните непосредственно в виде String в базе данных..)

Ответ 3

Если вы просто хотите использовать метку времени Unix, создайте расширение:

extension Date {
    func currentTimeMillis() -> Int64 {
        return Int64(self.timeIntervalSince1970 * 1000)
    }
}

Тогда вы можете использовать его, как и в других языках программирования:

let timestamp = Date().currentTimeMillis()

Ответ 4

Простой способ создания Current TimeStamp. как ниже,

func generateCurrentTimeStamp () -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy_MM_dd_hh_mm_ss"
    return (formatter.string(from: Date()) as NSString) as String
}

Ответ 5

Когда вы конвертируете метку времени UTC (то есть 2017-11-06 20:15:33 -08: 00) в объект Date() в Swift, Swift обнуляет часовой пояс по GMT (который равен плюс или минус 0). Для расчета временного интервала это не представляет проблемы, потому что сколько бы часов (и минут не было, поскольку есть количество часовых поясов, которые не разделены на час, но в: 45 или: 30) добавляются или вычитаются из нуля Из часового пояса добавляются или вычитаются значения часов (а иногда и минут) даты, поэтому абсолютный момент времени никогда не меняется. Однако при преобразовании этого объекта даты в строку с использованием DateFormatter() или ISO8601DateFormatter() это создает проблему, поскольку исходный часовой пояс обнуляется.

Теперь я предпочитаю использовать RFC3339 (то есть 2017-11-06T20: 15: 33 -08: 00), дружественный к Интернету формат для стандартного формата времени ISO8601. Скорее всего, сторонний API, к которому вы когда-нибудь подключитесь, будет использовать его, поэтому я думаю, что мы все должны использовать его сейчас. Формат в Swift: yyyy-MM-dd'T'HH:mm:ssXXXXX. Swift также имеет ISO8601DateFormatter() который может очень просто конвертировать строковые литералы в объекты даты:

func getDateFromUTC(RFC3339: String) -> Date? {
    let formatter = ISO8601DateFormatter()
    return formatter.date(from: RFC3339)
}

А использование формата RFC3339 также делает извлечение часового пояса очень простым:

func getTimeZoneFromUTC(RFC3339: String) -> TimeZone? {
    switch RFC3339.suffix(6) {
    case "+05:45":
        return TimeZone(identifier: "Asia/Kathmandu")
    default:
        return nil
    }
}

Конечно, вам нужно будет заполнить остальные 37 или около того часовых поясов, используя любые методы, которые вам подходят. И теперь, если вы хотите отформатировать этот строковый литерал во что-то более удобное для пользователя, вы можете объединить два вышеупомянутых метода в нечто вроде этого:

func getFormattedDateFromUTC(RFC3339: String) -> String? {
    guard let date = getDateFromUTC(RFC3339: RFC3339),
        let timeZone = getTimeZoneFromUTC(RFC3339: RFC3339) else {
            return nil
    }
    let formatter = DateFormatter()
    formatter.dateFormat = "h:mma EEE, MMM d yyyy"
    formatter.amSymbol = "AM"
    formatter.pmSymbol = "PM"
    formatter.timeZone = timeZone // preserve local time zone
    return formatter.string(from: date)
}

И поэтому эта строка "2018-11-06T17:00:00+05:45", которая выражает 17:00 где-то в Катманду, напечатает 5:00PM Tue, Nov 6 2018, отображая местное время, независимо от того, где находится машина является. И, конечно, если вы не хотите форматировать его, используя контекстное местное время, просто не устанавливайте свойство timeZone.

Как примечание в ответ на некоторые предложения в этой теме, я бы рекомендовал хранить даты в виде строк в Firebase. Хранение дат в виде строк, особенно с использованием формата, подобного RFC3339, делает эту платформу данных независимой. Вы можете переключиться на любую базу данных на любой платформе в любой среде, и вам не нужно будет менять логику, потому что строки всегда являются строками. И RFC3339 - это тот профиль, который признает практически любой каркас, достойный его внимания.

Ответ 6

Swift 4

Date().timeIntervalSince1970