为什么苹果在自动续订订阅的App Store收据返回时使用Etc/GMT时区?
Etc/GMT是什么时区?Java SDK是否理解这个时区?还是我需要使用其他第三方库,如Joda-Time?
为什么苹果在自动续订订阅的App Store收据返回时使用Etc/GMT时区?
Etc/GMT是什么时区?Java SDK是否理解这个时区?还是我需要使用其他第三方库,如Joda-Time?
Etc/GMT并不严格等同于UTC或GMT。只有当偏移量为0时,它们才表示相同的时间点。 在所有其他情况下,它们都是完全不同的。
苹果公司在此处解释了该称谓。
链接中的直接引用举了一个例子:
我们在时区名称和输出缩写中使用 POSIX 风格的符号, 即使这与许多人的期望相反。 POSIX 在格林威治以西使用正号,但许多人期望 正号在格林威治以东。例如,TZ = 'Etc / GMT + 4' 使用 缩写“GMT + 4”,对应于比UTC晚4小时 (即在格林威治以西),尽管许多人期望它表示比UTC早4小时(即在格林威治以东)。
理解:
各行业中的不同协议在编号时存在差异。有些人认为UTC之前的偏移量是正数,而其他人则使用负数。同样地,一些人认为UTC之后的偏移量是负数,而其他人则使用正数。
在我看到的大多数现代协议中(如ISO 8601),偏移UTC的地区(向东)的数字是正数,而偏移UTC的地区(向西)则是负数。因此,美洲地区的偏移量使用负数,例如America/Los_Angeles
目前偏移量为-07:00
或-08:00
,因为会受到夏令时的影响而在一年中变化。
java.util.Date
、Calendar
、SimpleDateFormat
等。幸运的是,java.time类可以帮助您解决这个混乱。查看Ole V.V.的正确答案,其中使用了ZoneId
类。
Apple使用Etc/GMT时区的原因
他们指的是偏移量为零,即UTC本身。字符串Etc/GMT
是一个带有零小时-分钟-秒的偏移量从UTC的一个规范标签。
日期时间字符串末尾常见的字母Z
(发音为“Zulu”)意味着相同的事情,即偏移量为零。
Etc/GMT时区到底是什么?
字符串Etc/GMT
是一个时间区域的名称,该时区只有一个来自UTC的偏移量,即零小时-分钟-秒。
大多数其他时区(例如 Europe/Berlin
或 Africa/Casablanca
)的偏移值在历史上有所不同。例如,在摩洛哥的 Africa/Casablanca
时区中,政治家去年决定,他们将全年保持夏令时而不是每年两次切换到标准时间和夏令时,我用笑声说“永久”,因为那其实意味着“直到政治家再次改变主意”。世界各地的政治家频繁重新定义他们的时区。
Java SDK理解这个时区吗?
是的。请参见 Ole V.V. 的 答案:ZoneId.of("Etc/GMT")
还是我必须使用像Joda-Time这样的第三方库?
顺便提一下,Joda-Time 项目现在处于维护模式,建议迁移至 java.time 类。请参见 Oracle 的教程。
您应该使用java.time类来处理所有日期和时间。
Etc/GMT
是标准的表达方式,表示 UTC
、GMT
、GMT0
或者 GMT+00:00
。
Java JDK 可以理解所有这些格式。您可以通过以下操作轻松查看其效果:
import java.util.TimeZone;
public class Playground {
public static void main(String... args) {
for (String s : TimeZone.getAvailableIDs()) {
System.out.println(s);
}
}
}
这将打印出你的Java JDK可以解析的所有不同TimeZone
格式:
...
Etc/GMT
Etc/GMT+0
Etc/GMT-0
Etc/GMT0
Etc/Greenwich
Etc/UCT
Etc/UTC
Etc/Universal
...
TimeZone
类现已被ZoneId
和ZoneOffset
所取代,成为遗留代码。请参阅JSR 310。 - Basil Bourque ZoneId etcGmt = ZoneId.of("Etc/GMT");
我建议您使用一个 Java 库 来处理 App Store 收据,而不要再考虑日期格式。
添加这个 artifact (by.dev.madhead.utils.appstore_receipts_validator:model:2.0.0
)。
使用任何 HTTP 客户端调用 App Store 并获取响应(这里我使用 Ktor):
suspend fun verify(receipt: String, password: String): VerifyReceiptResponse {
val rawResponse = client.post<String> {
url("https://buy.itunes.apple.com/verifyReceipt")
contentType(ContentType.Application.Json)
accept(ContentType.Application.Json)
body = VerifyReceiptRequest(
receipt,
password,
true
)
}
}
使用Jackson解析响应:
val response = objectMapper.readValue(rawResponse)
现在您可以使用普通的Java API来处理响应。