从Scala研习Java的TimeZone库

本文源于学习Spark日期时间函数时对TimeZone的研究。探讨了java.util.TimeZone类,包括有效ID和自定义ID的区别,以及ID的各类形式。通过Scala REPL进行实验,分析了ID的组成和含义,如地名缩写、全名、已废弃时区等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Table of Contents

仅包含一个单词的ID

包含多于两个单词的ID

正好包含两个单词的ID


一切缘起于学习Spark的日期时间函数。其中的to_utc_timestampfrom_utc_timestamp函数会涉及到TimeZone的参数。在Spark的源码中追溯,会发现TimeZone的参数会传到源文件:spark/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala,从而看到Spark实际上用了很多的Java有关时间的库。

...
import java.sql.{Date, Timestamp}
import java.time._
import java.time.Year.isLeap
import java.time.temporal.IsoFields
import java.util.{Locale, TimeZone}
import java.util.concurrent.TimeUnit._
...

于是需要学习这个库:java.util.TimeZone。参考其说明文档:https://docs.oracle.com/javase/8/docs/api/java/util/TimeZone.html。我们使用ID的字符串,通过函数getTimeZone得到相应的TimeZone:

TimeZone tz = TimeZone.getTimeZone(String ID);

而这里的String ID可以有两种形式

  • 一种是有效的ID,例如"America/Los_Angeles",能看出其意义。而这些字符串可以通过函数getAvailableIDs得到;
  • 一种则是自定义的ID(CustomID),就是以GMT开头的一定格式的时区表示。比较简单,参考上面的网页。在实际生成TimeZone的时候,自定义的ID会先转成正规化的自定义ID(NormalizedCustomID)。

现在来看getAvailableIDs得到的有效ID。注意到有效的ID字符串中会包含“/”字符,于是考虑以“/”划分的单词的个数来考察这些ID。而这个库与Spakr没有什么关系,我们可以在Scala的REPL中做一些探索。

import java.util.TimeZone
val timezoneIds = TimeZone.getAvailableIDs

仅包含一个单词的ID

timezoneIds.filter(_.split('/').length<2)

我们可以把结果分成这几个小类:

  1. GMT, GMT0, UCT, UTC,
  2. GB, GB-Eire, NZ, NZ-CHAT, PRC, ROK, W-SU,
  3. Cuba, Egypt, Eire, Greenwich, Hongkong, Iceland, Iran, Israel, Jamaica, Japan, Kwajalein, Libya, Navajo, Poland, Portugal, Singapore, Turkey, Universal, Zulu,
  4. CST6CDT, EST5EDT, MST7MDT, PST8PDT,
  5. CET, EET, MET, WET, 
  6. EST, HST, MST, ACT, AET, AGT, ART, AST, BET, BST, CAT, CNT, CST, CTT, EAT, ECT, IET, IST, JST, MIT, NET, NST, PLT, PNT, PRT, PST, SST, VST

第一类是标准时间。第二类是一些地名的缩写,搜索一下就能知道。第三类则是全的地名。第四类是美国那几个有夏时制的时区。第五类则是欧洲时区,可参考网页:

第六类是那些已经废弃时区缩写,具体内容可以参考网页:https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html。这里看看具体的解释:

EST - -05:00
HST - -10:00
MST - -07:00
ACT - Australia/Darwin
AET - Australia/Sydney
AGT - America/Argentina/Buenos_Aires
ART - Africa/Cairo
AST - America/Anchorage
BET - America/Sao_Paulo
BST - Asia/Dhaka
CAT - Africa/Harare
CNT - America/St_Johns
CST - America/Chicago
CTT - Asia/Shanghai
EAT - Africa/Addis_Ababa
ECT - Europe/Paris
IET - America/Indiana/Indianapolis
IST - Asia/Kolkata
JST - Asia/Tokyo
MIT - Pacific/Apia
NET - Asia/Yerevan
NST - Pacific/Auckland
PLT - Asia/Karachi
PNT - America/Phoenix
PRT - America/Puerto_Rico
PST - America/Los_Angeles
SST - Pacific/Guadalcanal
VST - Asia/Ho_Chi_Minh

 

包含多于两个单词的ID

timezoneIds.filter(_.split('/').length>2)

结果不多,而且第一个单词都是America,总单词的个数都是三:

  • America/Argentina/Buenos_Aires, America/Argentina/Catamarca, America/Argentina/ComodRivadavia, America/Argentina/Cordoba, America/Argentina/Jujuy, America/Argentina/La_Rioja, America/Argentina/Mendoza, America/Argentina/Rio_Gallegos, America/Argentina/Salta, America/Argentina/San_Juan, America/Argentina/San_Luis, America/Argentina/Tucuman, America/Argentina/Ushuaia,
  • America/Indiana/Indianapolis, America/Indiana/Knox, America/Indiana/Marengo, America/Indiana/Petersburg, America/Indiana/Tell_City, America/Indiana/Vevay, America/Indiana/Vincennes, America/Indiana/Winamac,
  • America/Kentucky/Louisville, America/Kentucky/Monticello,
  • America/North_Dakota/Beulah, America/North_Dakota/Center, America/North_Dakota/New_Salem
timezoneIds.filter(_.split('/').length>2).map(_.split('/')(1)).toSet

这个命令可以得到有哪些不同的第二个单词:

  • Argentina, Indiana, Kentucky, North_Dakota

 

正好包含两个单词的ID

这一类ID比较多,因此我们先查看一下有哪些不同的第一个单词:

timezoneIds.filter(_.split('/').length==2).map(_.split('/')(0)).toSet

结果是:

  • US, Mexico, Atlantic, Europe, Arctic, Canada, SystemV, Brazil, Australia, Etc, Asia, Indian, Chile, America, Pacific, Africa, Antarctica

也可以直接做统计:

timezoneIds.filter(_.split('/').length==2).groupBy(_.split('/')(0)).mapValues(_.length)

得到结果:

  • US -> 13, Mexico -> 3, Atlantic -> 12, Europe -> 63, Arctic -> 1, Canada -> 8, SystemV -> 13, Brazil -> 4, Australia -> 23, Etc -> 35, Asia -> 98, Indian -> 11, Chile -> 2, America -> 140, Pacific -> 43, Africa -> 54, Antarctica -> 12

而用下面的命令就可以对不同的第二个单词做分别的列举了:

timezoneId.filter(_.split('/').length==2).filter(_.split('/')(0)=="?")

可以按第二个单词来分作几个小类。第一小类是国家名US, Mexico, Canada, Brazil和Chile

  • US/Alaska, US/Aleutian, US/Arizona, US/Central, US/East-Indiana, US/Eastern, US/Hawaii, US/Indiana-Starke, US/Michigan, US/Mountain, US/Pacific, US/Pacific-New, US/Samoa
  • Mexico/BajaNorte, Mexico/BajaSur, Mexico/General
  • Canada/Atlantic, Canada/Central, Canada/Eastern, Canada/Mountain, Canada/Newfoundland, Canada/Pacific, Canada/Saskatchewan, Canada/Yukon
  • Brazil/Acre, Brazil/DeNoronha, Brazil/East, Brazil/West
  • Chile/Continental, Chile/EasterIsland

第二小类是特殊的两个体系SystemV和Etc

  • SystemV/AST4, SystemV/AST4ADT, SystemV/CST6, SystemV/CST6CDT, SystemV/EST5, SystemV/EST5EDT, SystemV/HST10, SystemV/MST7, SystemV/MST7MDT, SystemV/PST8, SystemV/PST8PDT, SystemV/YST9, SystemV/YST9YDT
  • Etc/GMT, Etc/GMT+0, Etc/GMT+1, Etc/GMT+10, Etc/GMT+11, Etc/GMT+12, Etc/GMT+2, Etc/GMT+3, Etc/GMT+4, Etc/GMT+5, Etc/GMT+6, Etc/GMT+7, Etc/GMT+8, Etc/GMT+9, Etc/GMT-0, Etc/GMT-1, Etc/GMT-10, Etc/GMT-11, Etc/GMT-12, Etc/GMT-13, Etc/GMT-14, Etc/GMT-2, Etc/GMT-3, Etc/GMT-4, Etc/GMT-5, Etc/GMT-6, Etc/GMT-7, Etc/GMT-8, Etc/GMT-9, Etc/GMT0, Etc/Greenwich, Etc/UCT, Etc/UTC, Etc/Universal, Etc/Zulu

剩下的第三小类就是所有ID的主力了,包含了六大洲和四大洋

  • Atlantic -> 12,
  • Europe -> 63,
  • Arctic -> 1,
  • Australia -> 23,
  • Asia -> 98,
  • Indian -> 11,
  • America -> 140,
  • Pacific -> 43,
  • Africa -> 54,
  • Antarctica -> 12

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值