Ios Swift:如何将Date()转换为Apple的时区';要验证收据的服务器是什么?

Ios Swift:如何将Date()转换为Apple的时区';要验证收据的服务器是什么?,ios,swift,datetime,in-app-purchase,storekit,Ios,Swift,Datetime,In App Purchase,Storekit,使用Swift 3 当我调用此代码时,它显示为我的时区 let date = Date() let todayDate = formatter.string(from: date) print(todayDate) 我调用StoreKit收据中的JSON响应来检查原始购买日期和过期日期,将其与今天日期进行比较,以验证收据 例如,我想做什么 if (todayDate > expires_date ) { cancel subscription } 如果Apple的购买日期和过期

使用Swift 3

当我调用此代码时,它显示为我的时区

let date = Date()
let todayDate = formatter.string(from: date)
print(todayDate)
我调用StoreKit收据中的JSON响应来检查
原始购买日期
过期日期
,将其与
今天日期
进行比较,以验证收据

例如,我想做什么

if (todayDate > expires_date ) {
    cancel subscription
}
如果Apple的购买日期和过期日期在GMT时区,而todayDate在用户所在的任何时区,则我无法匹配日期

所以我只需要在调用Date()时转换用户所在的时区,并将其转换为GMT,就像苹果的服务器一样,这样我就可以检查todayDate是否已通过自动续费订阅上的过期数据

此外,这是防止应用程序内黑客攻击的好方法吗?我用php从我的服务器上得到了收据,php从苹果那里验证了收据

if parseJSON["status"] as? Int == 0 {

print("Status Code for Receipt = 0!")

// Checking "latest_receipt_info"
if let receiptInfo: NSArray = parseJSON["latest_receipt_info"] as? NSArray {
    let lastReceipt = receiptInfo.lastObject as! NSDictionary

    // Get last receipt
    print("\nLAST RECEIPT INFORMATION: \n", lastReceipt)

    // Format date
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
    formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale!

    // Get "original_purchase_date" as NSDate
    let subscriptionBoughtDate: NSDate = formatter.date(from: lastReceipt["original_purchase_date"] as! String) as NSDate!
    print("\n   - DATE BOUGHT SUBSCRIPTION = \(subscriptionBoughtDate)\n")

    // Get "expires_date" as NSDate
    let subscriptionExpirationDate: NSDate = formatter.date(from: lastReceipt["expires_date"] as! String) as NSDate!
    print("\n   - DATE SUBSCRIPTION EXPIRES = \(subscriptionExpirationDate)\n")

    // Get Todays Date
    let date = Date()
    let todayDate = formatter.string(from: date)
    print("\n   - DATE TODAY = \(todayDate)\n")

    // See if current date has passed expired date
}
JSON响应

LAST RECEIPT INFORMATION: 
{
"expires_date" = "2017-08-03 04:50:08 Etc/GMT";
"expires_date_ms" = 1501735808000;
"expires_date_pst" = "2017-08-02 21:50:08 America/Los_Angeles";
"is_trial_period" = false;
"original_purchase_date" = "2017-08-02 15:27:27 Etc/GMT";
"original_purchase_date_ms" = 1501687647000;
"original_purchase_date_pst" = "2017-08-02 08:27:27 America/Los_Angeles";
"original_transaction_id" = 1000000552288255;
"product_id" = "com.example.gg.month";
"purchase_date" = "2017-08-03 04:45:08 Etc/GMT";
"purchase_date_ms" = 1501735508000;
"purchase_date_pst" = "2017-08-02 21:45:08 America/Los_Angeles";
quantity = 1;
"transaction_id" = 1000000568853433;
"web_order_line_item_id" = 1000000055887122;
}

- DATE BOUGHT SUBSCRIPTION = 2017-08-02 15:27:27 +0000


- DATE SUBSCRIPTION EXPIRES = 2017-08-03 04:50:08 +0000


- DATE TODAY = 2017-08-04 17:26:51 America/New_York

谢谢大家!

您只需将
日期格式化程序的
时区
属性设置为GMT即可

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
formatter.timeZone = TimeZone(secondsFromGMT: 0)

一般建议:当本地
Swift
选项可用时,不要在
Swift
中使用
Foundation
类型,例如
Array
Dictionary
Locale
Date
。使用它们而不是
NSArray
NSDictionary
NSLocale
NSDate
您只需将
日期格式化程序的
时区
属性设置为GMT即可

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
formatter.timeZone = TimeZone(secondsFromGMT: 0)

一般建议:当本地
Swift
选项可用时,不要在
Swift
中使用
Foundation
类型,例如
Array
Dictionary
Locale
Date
。用它们代替
NSArray
NSDictionary
NSLocale
NSDate
,我根本不会弄乱日期格式化程序。JSON中有各种带有后缀“\ms”的日期。这些日期基于Unix“纪元日期”,但乘以1000

如果您需要做的只是查看当前日期是否介于订阅开始日期和结束日期之间,则可以直接将以“\ms”结尾的日期值作为整数值进行比较

如果需要将其中一个日期转换为日期对象,这很容易

下面是一个例子:

let expiresDateValue = Double(lastReceipt["expires_date_ms"]) / 1000
let expiresDate = Date(timeIntervalSince1970: expiresDateValue)
编辑: 斯威夫特的严格类型铸造使这比它应该更痛苦

这样做:

var expiresSeconds: Double = 0
if let expiresString = lastReceipt["expires_date_ms"] as? String,
  let expiresMS = Double(expiresString) {
  expiresSeconds = expiresMS / 1000
}

我一点也不会弄乱日期格式化程序。JSON中有各种带有后缀“\ms”的日期。这些日期基于Unix“纪元日期”,但乘以1000

如果您需要做的只是查看当前日期是否介于订阅开始日期和结束日期之间,则可以直接将以“\ms”结尾的日期值作为整数值进行比较

如果需要将其中一个日期转换为日期对象,这很容易

下面是一个例子:

let expiresDateValue = Double(lastReceipt["expires_date_ms"]) / 1000
let expiresDate = Date(timeIntervalSince1970: expiresDateValue)
编辑: 斯威夫特的严格类型铸造使这比它应该更痛苦

这样做:

var expiresSeconds: Double = 0
if let expiresString = lastReceipt["expires_date_ms"] as? String,
  let expiresMS = Double(expiresString) {
  expiresSeconds = expiresMS / 1000
}

使用ms而不是日期格式化程序有什么好处吗?它更容易、更简单、更干净。我尝试了它,但它在第一行给了我一个错误,即
无法使用类型为“(any?)的参数列表调用类型为“Double”的初始值设定项。
请参见对我答案的编辑。我应该知道在编辑器中输入代码时不需要测试,我已经有两年没有详细看过StoreKit了。我不记得收据验证是如何工作的。然而,在我脑海中,检查日期听起来并没有提供多少安全性。检查收据是否正确签名是你的工作,还是苹果公司的工作?(在Mac OS上,开发人员必须验证应用程序是否正确签名。)使用ms而不是日期格式化程序有什么好处吗?它更容易、更简单、更干净。我尝试过它,但它在第一行给了我一个错误,即
无法使用类型为(any)的参数列表调用类型为“Double”的初始值设定项“
请参见编辑我的答案。我应该知道在编辑器中输入代码时不需要测试,我已经有两年没有详细看过StoreKit了。我不记得收据验证是如何工作的。然而,在我脑海中,检查日期听起来并没有提供多少安全性。检查收据是否正确签名是你的工作,还是苹果公司的工作?(在Mac OS上,开发者必须验证应用程序是否正确签名。)出于好奇,你为什么需要
原始购买日期
todayDate>expires\u date
还不够吗?老实说,这只是增加了安全性,购买日期可能会被修改,所以试用期会更长。出于好奇,你为什么需要
原始购买日期
todayDate>expires\u date
还不够吗?老实说,这只是增加了安全性,购买日期可能会被修改,所以试用期会更长。哇!!这是完美的答案!所有答案都使用不同的日期格式,但这对于收到的收据中的订阅过期日期来说是完美的,以供验证。哇!!这是完美的答案!所有答案都使用不同的日期格式,但这非常适合于收到的收据中的订阅到期日期进行验证。