我试图制作一个考勤应用程序,我对iOS和Firebase中的日期和时间感到困惑。
我使用date作为Key,这是我的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日。
使用什么代码是正确的,以便我可以获得正确的日期时间戳和时间戳?
答案 0 :(得分:52)
为了将当前时间保存到firebase数据库,我使用Unic Epoch Conversation:
let timestamp = NSDate().timeIntervalSince1970
和For Decoding Unix Epoch time to Date()。
let myTimeInterval = TimeInterval(timestamp)
let time = NSDate(timeIntervalSince1970: TimeInterval(myTimeInterval))
答案 1 :(得分:11)
首先,我建议您将时间戳存储为Firebase数据库中的NSNumber
,而不是将其存储为String
。
另一件值得一提的是,如果你想用Swift操纵日期,你最好使用Date
代替NSDate
,除非你与某些人交往您应用中的Obj-C代码。
您当然可以使用两者,但文档说明:
日期桥接到NSDate类。您可以互换使用这些 与Objective-C API交互的代码。
现在回答你的问题,我认为这里的问题是因为时区。
例如,如果你print(Date())
,就像现在一样,你会得到:
2017-09-23 06:59:34 +0000
这是格林威治标准时间(GMT)。
因此,根据您所在的位置(或用户所在的位置),您需要在存储Date
之前(或之后,当您尝试访问数据时)调整时区:{/ 1}}
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
。)
答案 2 :(得分:11)
如果只需要unix时间戳,请创建一个扩展名:
extension Date {
func currentTimeMillis() -> Int64 {
return Int64(self.timeIntervalSince1970 * 1000)
}
}
然后,您可以像在其他编程语言中一样使用它:
let timestamp = Date().currentTimeMillis()
答案 3 :(得分:2)
创建当前时间戳的简单方法。像下面一样,
func generateCurrentTimeStamp () -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy_MM_dd_hh_mm_ss"
return (formatter.string(from: Date()) as NSString) as String
}
答案 4 :(得分:2)
在 Swift 5
中extension Date {
static var currentTimeStamp: Int64{
return Int64(Date().timeIntervalSince1970 * 1000)
}
}
像这样打电话:
let timeStamp = Date.currentTimeStamp
print(timeStamp)
感谢@lenooh
答案 5 :(得分:1)
如果您为iOS 13.0或更高版本编写代码并需要时间戳,则可以使用:
let currentDate = NSDate.now
答案 6 :(得分:0)
当您在Swift中将UTC时间戳(即2017-11-06 20:15:33 -08:00)转换为Date()
对象时,Swift将时区归零为格林尼治标准时间(即加号或减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"
(在加德满都某处表示5:00 PM)将打印5:00PM Tue, Nov 6 2018
,并显示本地时间,而不管机器在哪里。而且,当然,如果您不想使用其上下文本地时间对其进行格式化,则只需不设置timeZone属性。
作为对此线程中某些建议的回应,我建议将日期作为字符串存储在Firebase中。将日期存储为字符串,尤其是使用诸如RFC3339之类的格式存储日期,使该数据平台不可知。您可以切换到任何框架中任何平台上的任何数据库,并且无需更改任何逻辑,因为字符串始终只是字符串。 RFC3339是基本上任何值得其认可的框架都可以识别的配置文件。
答案 7 :(得分:0)
您甚至可以创建一个函数来根据需要返回不同的时间戳:
func dataatual(_ tipo:Int) -> String {
let date = Date()
let formatter = DateFormatter()
if tipo == 1{
formatter.dateFormat = "dd/MM/yyyy"
} else if tipo == 2{
formatter.dateFormat = "yyyy-MM-dd HH:mm"
} else {
formatter.dateFormat = "dd-MM-yyyy"
}
return formatter.string(from: date)
}