出席アプリを作成しようとしていますが、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になります。これは私の場所では9月23日なので間違っています。
正しい日付のタイムスタンプと時刻のタイムスタンプを取得するために使用する適切なコードは何ですか?
現在の時間をfirebaseデータベースに保存するには、Unic Epoch Conversationを使用します。
let timestamp = NSDate().timeIntervalSince1970
そして、Unixエポック時間をDate()にデコードするため。
let myTimeInterval = TimeInterval(timestamp)
let time = NSDate(timeIntervalSince1970: TimeInterval(myTimeInterval))
UNIXタイムスタンプだけが必要な場合は、拡張機能を作成します。
extension Date {
func currentTimeMillis() -> Int64 {
return Int64(self.timeIntervalSince1970 * 1000)
}
}
その後、他のプログラミング言語と同じように使用できます。
let timestamp = Date().currentTimeMillis()
最初に、タイムスタンプをNSNumber
として保存するのではなく、FirebaseデータベースにString
として保存することをお勧めします。
ここで言及する価値のあるもう1つのことは、Swiftで日付を操作する場合は、アプリでObj-Cコードを操作する場合を除いて、Date
の代わりにNSDate
を使用することをお勧めします。
もちろん両方を使用できますが、ドキュメントには次のように記載されています。
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
として直接保存します) )
現在のタイムスタンプを作成する簡単な方法。以下のように、
func generateCurrentTimeStamp () -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy_MM_dd_hh_mm_ss"
return (formatter.string(from: Date()) as NSString) as String
}
UTCタイムスタンプ(2017-11-06 20:15:33 -08:00)をSwiftのDate()
オブジェクトに変換すると、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かそこらのタイムゾーンに最適な方法を使用して入力する必要があります。そして今、その文字列リテラルをよりユーザーフレンドリーなものにフォーマットしたい場合、上記の2つの方法をこのようなものに組み合わせることができます:
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"
は、カトマンズのどこか5:00 PMを表し、5:00PM Tue, Nov 6 2018
を出力し、マシンの場所に関係なく現地時間を表示します。もちろん、コンテキストのローカル時間を使用してフォーマットしたくない場合は、timeZoneプロパティを設定しないでください。
このスレッドのいくつかの提案に対する補足として、日付をFirebaseに文字列として保存することをお勧めします。特にRFC3339のような形式を使用して、日付を文字列として保存すると、このデータプラットフォームは不可知になります。任意のフレームワークの任意のプラットフォーム上の任意のデータベースに切り替えることができ、文字列は常に単なる文字列であるため、ロジックを変更する必要はありません。そして、RFC3339は、基本的にその価値のあるフレームワークが認識する1つのプロファイルです。