it-roy-ru.com

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 сентября.

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

17
TSM

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

let timestamp = NSDate().timeIntervalSince1970

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

let myTimeInterval = TimeInterval(timestamp)
let time = NSDate(timeIntervalSince1970: TimeInterval(myTimeInterval))
38
Satish Babariya

Во-первых, я бы порекомендовал вам сохранить вашу временную метку как NSNumber в вашей базе данных Firebase, а не сохранять ее как String.

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

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

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

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

Например, если вы 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 в базе данных. .)

8
Alex

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

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

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

let timestamp = Date().currentTimeMillis()
3
lenooh

Простой способ создания 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
}
2
User558

Когда вы конвертируете метку времени 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 - это тот профиль, который признает практически любой каркас, достойный его внимания.

0
bsod