计算两个时区之间偏移量的最简单方法 Scala/Java
Easiest way to calculate offset between two timezones Scala/Java
我找不到很好的答案如何轻松计算 Scala/Java 中给定时间点的时区偏移量。
鉴于:
- 日期与时间
- 时区 1
- 时区 2
要求:
计算时区 1 中特定日期的偏移量,需要将此日期移动到时区 2。
示例:
日期时间 = 2017-10-23 00:00:00 America/Los_Angeles
时区 1,
时区 2 = Europe/Paris
偏移量应等于+9,可用于将日期从时区 1 移动到时区 2。
据我所知,最简单的方法是计算每个时区的 GMT 增量偏移量,然后将它们相加:
package dates;
import java.time.ZoneId
import java.util.TimeZone
import java.util.concurrent.TimeUnit
/**
* Returns timezone GMT delta offset for given point of time.
*/
def timezoneOffset(millis: Long, tz: ZoneId): Int = {
TimeUnit.MILLISECONDS.toHours(TimeZone.getTimeZone(tz).getOffset(millis)).toInt
}
/**
* Returns offset required to move `millis` from `baseTz` to `targetTz`:
*
* @example
* PDT(Los_Angeles) is -7 from GMT
* EDT(Paris) is +2 from GMT
*
* timezoneOffsetBetween(millisInPdt, PDT, EDT) == +9
* timezoneOffsetBetween(millisInEdt, EDT, PDT) == -9
*/
def timezoneOffsetBetween(millis: Long, baseTz: ZoneId, targetTz: ZoneId): Int = {
-(timezoneOffset(millis, baseTz) - timezoneOffset(millis, targetTz))
}
这是测试用例:
package dates;
import java.time.{ZoneId, ZonedDateTime}
import org.scalatest.{FreeSpec, Matchers}
class DateSpec extends FreeSpec with Matchers {
val laTz = ZoneId.of("America/Los_Angeles")
val gmtTz = ZoneId.of("GMT")
val sydneyTz = ZoneId.of("Australia/Sydney")
val parisTz = ZoneId.of("Europe/Paris")
"timezoneOffset should be" - {
"-7 for PDT millis" in {
val pdtMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffset(pdtMillis, laTz) shouldEqual -7
}
"-8 for PST millis" in {
val pstMillis = ZonedDateTime.of(2017, 11, 6, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffset(pstMillis, laTz) shouldEqual -8
}
"0 for GMT millis" in {
val gmtMillis = ZonedDateTime.of(2017, 11, 6, 0, 0, 0, 0, gmtTz).toInstant.toEpochMilli
dates.timezoneOffset(gmtMillis, gmtTz) shouldEqual 0
}
"10 for AEST millis" in {
val aestMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, sydneyTz).toInstant.toEpochMilli
dates.timezoneOffset(aestMillis, sydneyTz) shouldEqual 10
}
"11 for AEDT millis" in {
val aedtMillis = ZonedDateTime.of(2017, 10, 10, 0, 0, 0, 0, sydneyTz).toInstant.toEpochMilli
dates.timezoneOffset(aedtMillis, sydneyTz) shouldEqual 11
}
}
"timezoneOffsetBetween should be" - {
"17 between PDT and AEST millis" in {
val pdtMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(pdtMillis, laTz, sydneyTz) shouldEqual 17
}
"18 between PDT and AEDT millis" in {
val pdtMillis = ZonedDateTime.of(2017, 10, 10, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(pdtMillis, laTz, sydneyTz) shouldEqual 18
}
"19 between PST and AEDT millis" in {
val pstMillis = ZonedDateTime.of(2017, 11, 6, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(pstMillis, laTz, sydneyTz) shouldEqual 19
}
"-19 between AEDT and PST millis" in {
val aedtMillis = ZonedDateTime.of(2017, 11, 6, 0, 0, 0, 0, sydneyTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(aedtMillis, sydneyTz, laTz) shouldEqual -19
}
"0 between PDT and PDT" in {
val pdtMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(pdtMillis, laTz, laTz) shouldEqual 0
}
"8 between EDT and AEST" in {
val edtMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, parisTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(edtMillis, parisTz, sydneyTz) shouldEqual 8
}
"-8 between AEST and EDT" in {
val aestMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, sydneyTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(aestMillis, sydneyTz, parisTz) shouldEqual -8
}
}
}
import java.time._
val date: LocalDate = ???
val zone1: ZoneId = ???
val zone2: ZoneId = ???
val duration: Duration = Duration.between(date.atStartOfDay(zone1), date.atStartOfDay(zone2))
然后你可以从持续时间中提取你需要的东西,很可能.getHours
这样不行吗?
import java.time.{LocalDateTime, ZoneId}
import java.time.temporal.ChronoUnit
val dateOfInterest = LocalDateTime.parse("2020-02-02T12:00")
ChronoUnit.HOURS.between(dateOfInterest.atZone(ZoneId.of("Europe/Paris"))
,dateOfInterest.atZone(ZoneId.of("America/Los_Angeles")))
//res0: Long = 9
我找不到很好的答案如何轻松计算 Scala/Java 中给定时间点的时区偏移量。
鉴于:
- 日期与时间
- 时区 1
- 时区 2
要求: 计算时区 1 中特定日期的偏移量,需要将此日期移动到时区 2。
示例:
日期时间 = 2017-10-23 00:00:00 America/Los_Angeles
时区 1,
时区 2 = Europe/Paris
偏移量应等于+9,可用于将日期从时区 1 移动到时区 2。
据我所知,最简单的方法是计算每个时区的 GMT 增量偏移量,然后将它们相加:
package dates;
import java.time.ZoneId
import java.util.TimeZone
import java.util.concurrent.TimeUnit
/**
* Returns timezone GMT delta offset for given point of time.
*/
def timezoneOffset(millis: Long, tz: ZoneId): Int = {
TimeUnit.MILLISECONDS.toHours(TimeZone.getTimeZone(tz).getOffset(millis)).toInt
}
/**
* Returns offset required to move `millis` from `baseTz` to `targetTz`:
*
* @example
* PDT(Los_Angeles) is -7 from GMT
* EDT(Paris) is +2 from GMT
*
* timezoneOffsetBetween(millisInPdt, PDT, EDT) == +9
* timezoneOffsetBetween(millisInEdt, EDT, PDT) == -9
*/
def timezoneOffsetBetween(millis: Long, baseTz: ZoneId, targetTz: ZoneId): Int = {
-(timezoneOffset(millis, baseTz) - timezoneOffset(millis, targetTz))
}
这是测试用例:
package dates;
import java.time.{ZoneId, ZonedDateTime}
import org.scalatest.{FreeSpec, Matchers}
class DateSpec extends FreeSpec with Matchers {
val laTz = ZoneId.of("America/Los_Angeles")
val gmtTz = ZoneId.of("GMT")
val sydneyTz = ZoneId.of("Australia/Sydney")
val parisTz = ZoneId.of("Europe/Paris")
"timezoneOffset should be" - {
"-7 for PDT millis" in {
val pdtMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffset(pdtMillis, laTz) shouldEqual -7
}
"-8 for PST millis" in {
val pstMillis = ZonedDateTime.of(2017, 11, 6, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffset(pstMillis, laTz) shouldEqual -8
}
"0 for GMT millis" in {
val gmtMillis = ZonedDateTime.of(2017, 11, 6, 0, 0, 0, 0, gmtTz).toInstant.toEpochMilli
dates.timezoneOffset(gmtMillis, gmtTz) shouldEqual 0
}
"10 for AEST millis" in {
val aestMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, sydneyTz).toInstant.toEpochMilli
dates.timezoneOffset(aestMillis, sydneyTz) shouldEqual 10
}
"11 for AEDT millis" in {
val aedtMillis = ZonedDateTime.of(2017, 10, 10, 0, 0, 0, 0, sydneyTz).toInstant.toEpochMilli
dates.timezoneOffset(aedtMillis, sydneyTz) shouldEqual 11
}
}
"timezoneOffsetBetween should be" - {
"17 between PDT and AEST millis" in {
val pdtMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(pdtMillis, laTz, sydneyTz) shouldEqual 17
}
"18 between PDT and AEDT millis" in {
val pdtMillis = ZonedDateTime.of(2017, 10, 10, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(pdtMillis, laTz, sydneyTz) shouldEqual 18
}
"19 between PST and AEDT millis" in {
val pstMillis = ZonedDateTime.of(2017, 11, 6, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(pstMillis, laTz, sydneyTz) shouldEqual 19
}
"-19 between AEDT and PST millis" in {
val aedtMillis = ZonedDateTime.of(2017, 11, 6, 0, 0, 0, 0, sydneyTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(aedtMillis, sydneyTz, laTz) shouldEqual -19
}
"0 between PDT and PDT" in {
val pdtMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, laTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(pdtMillis, laTz, laTz) shouldEqual 0
}
"8 between EDT and AEST" in {
val edtMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, parisTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(edtMillis, parisTz, sydneyTz) shouldEqual 8
}
"-8 between AEST and EDT" in {
val aestMillis = ZonedDateTime.of(2018, 9, 10, 0, 0, 0, 0, sydneyTz).toInstant.toEpochMilli
dates.timezoneOffsetBetween(aestMillis, sydneyTz, parisTz) shouldEqual -8
}
}
}
import java.time._
val date: LocalDate = ???
val zone1: ZoneId = ???
val zone2: ZoneId = ???
val duration: Duration = Duration.between(date.atStartOfDay(zone1), date.atStartOfDay(zone2))
然后你可以从持续时间中提取你需要的东西,很可能.getHours
这样不行吗?
import java.time.{LocalDateTime, ZoneId}
import java.time.temporal.ChronoUnit
val dateOfInterest = LocalDateTime.parse("2020-02-02T12:00")
ChronoUnit.HOURS.between(dateOfInterest.atZone(ZoneId.of("Europe/Paris"))
,dateOfInterest.atZone(ZoneId.of("America/Los_Angeles")))
//res0: Long = 9