【问题标题】:Auto-renewable subscription receipt date format自动续订订阅收据日期格式
【发布时间】:2011-09-05 18:43:18
【问题描述】:

我正在努力弄清楚以下日期的格式:

2011-05-24 19:02:32 Etc/GMT

此日期是从 Apple 的收据验证服务返回的,我需要将其转换为 NSDate 以进行一些比较操作。真正的麻烦与时区有关。

这是我已经编写的一些代码:

        NSDictionary *receiptData = [info valueForKey:@"expires_date"];

        NSDateFormatter *f = [[NSDateFormatter alloc] init];

        [f setLocale:[NSLocale currentLocale]];
        [f setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
        [f setDateFormat:@"yyyy-MM-dd HH:mm:ss vvvv"];

        NSLog(@"%@", [f stringFromDate:[NSDate date]]);

        NSDate *subPurchaseDate = [f dateFromString:[receiptData valueForKey:@"original_purchase_date"]];

        [f release];

我已经尝试了所有我能想到的 'v's 和 'Z's 组合。有什么见解吗?

【问题讨论】:

  • 您对此感到高兴吗?当我遇到你的问题时,我正要发布同样的问题。
  • Apple 返回此字符串但 Apple 框架无法解析它,还有其他人对此感到奇怪吗?
  • 不,但这主要是因为我已经使用 Apple 技术工作了几年。一段时间后你会习惯疼痛。
  • 将近 9 年过去了,这仍然和当时一样痛苦。

标签: iphone objective-c ios nsdateformatter subscription


【解决方案1】:

通过查看日期格式文档,我得到了正确的格式,对我来说效果很好:

        NSDateFormatter * formatter = [NSDateFormatter new];
        formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss VV";

        NSDate * purchaseDate = [formatter dateFromString:latestTransaction[@"original_purchase_date"]];
        NSDate * expirationDate = [formatter dateFromString:latestTransaction[@"expires_date"]];

不需要在格式化程序上设置时区,因为它嵌入在字符串中。
操纵日期字符串来解析它不是一个好主意。

来源:http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns

【讨论】:

  • 这项工作我不会像接受的答案那样删除时区。您应该切换日期和月份:yyyy-dd-MM => yyyy-MM-dd
  • 由于某种原因,这种格式不适用于在以色列购买的客户:O
  • 我不确定收据中的字符串是什么,但[formatter dateFromString:latestTransaction[@"expires_date"]]; 为在以色列购买的客户返回了NULL。在美国工作得很好。
  • 有趣。如果您可以发布字符串,我们可以确定它是否已本地化。以色列时间就像欧洲 - “dd/MM/yyyy”
  • > "不需要在格式化程序上设置时区,因为它嵌入在字符串中。"我的经验表明,在格式化程序上设置时区至关重要——否则它会覆盖字符串中嵌入的内容。至少在 iOS 13.4.1 和 iOS 13.5 中使用 Swift 时。
【解决方案2】:

在做了更多研究之后,我在这里使用的代码有效,但值得怀疑;

   NSString *purchaseDateString = [@"2011-05-24 19:02:32 Etc/GMT" stringByReplacingOccurrencesOfString:@" Etc/GMT" withString:@""];
   NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
   NSLocale *POSIXLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease];
   [formatter setLocale:POSIXLocale];
   [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
   [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

   NSDate *purchaseDate = [formatter dateFromString:purchaseDateString];

我不喜欢我对传入日期字符串所做的假设,因此我假设此代码可能会在其他商店中中断(我正在针对英国商店进行测试)。因此,尽管这种方法适用于我自己的情况,但我真的很想看到一个更强大的解决方案,它可以根据原始问题正确解析时区字符串。

我不敢相信 Apple 在这些重要的日期字符串中使用了已弃用的时区(所有 Etc/* 都已正式弃用)!

编辑:

我注意到你正在使用

NSDictionary *receiptData = [info valueForKey:@"expires_date"];

这实际上不是字符串according to the documentation,它应该是“订阅收据的到期日期,表示为自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数”

但是问题仍然有效,因为您在处理恢复的订阅时必须使用 purchase_date 字段,并且该字段采用您描述的文本格式。

【讨论】:

  • 我最终在我的代码中进行了相同的查找/替换,但我将 'Etc/GMT' 替换为 'GMT' 以使我的生活更轻松一些。此外,我对使用此解决方案也有同样的保留,但坦率地说,我找不到其他可行的方法。感谢您确认我的解决方案。
  • 我会添加一个检查字符串是否以“Etc/GMT”结尾,如果它不是真的做一些日志记录(弹出一个 MFMailComposeViewController 并要求用户发送错误报告? )。有点乱,不过还好。
  • 为什么要删除 Etc/GMT?这是一个合法的时区,所以看起来。例如。 php.net/manual/en/timezones.others.php
  • @Tudorizer,主要是因为 NSDateFormatter 似乎无法解析它。
  • 绝对可以解析,只要使用正确的格式即可。下面看看我的回答
【解决方案3】:

下面的代码可以用来解析RFC 3339 dates found in App Store receipts

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

let date = formatter.date(from: "2020-06-17 10:59:33 Etc/GMT")

请注意,必须设置timeZonelocale。根据Technical Q&A QA1480,在dateFormat 之前设置locale 也很重要。

Apple recommends 在 iOS 10+ 和 macOS 10.12+ 上使用更新的 ISO8601DateFormatter API。

【讨论】:

    【解决方案4】:

    这是我在 Swift 3 上所做的,将日期从收据的自动更新日期转换。

    let expirationDate = "2017-08-16 23:10:35 Etc/GMT"
    let receiptDateFormat = "yyyy-MM-dd HH:mm:ss VV"
    let theDateFormat = DateFormatter.Style.medium
    let theTimeFormat = DateFormatter.Style.medium
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = receiptDateFormat
    let firstDate = dateFormatter.date(from: stringDate)
    dateFormatter.dateStyle = theDateFormat
    dateFormatter.timeStyle = theTimeFormat
    
    let result = dateFormatter.string(from: firstDate!)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-08
      • 2020-08-23
      相关资源
      最近更新 更多