java国际化之时区问题处理

2017-10-12 19:30:59来源:作者:人点击

分享

在国际化的项目中需要处理的日期时间问题主要有两点:

1、日期时间的国际化格式问题处理;

2、日期时间的时区问题处理,这两个问题要区分开,不要弄混了。

 

日期时间国际化化格式处理

 

对应的关键词:Locale

日期时间的国际化格式指的是在不同的国家和地区对日期时间的显示方式不同,主要通过不同国家地区不同的语言习惯,对同一个实现的呈现方式不同。在java中需要结合Locale类进行处理:

public static void main(String[] args) {Date date = new Date();Locale locale = Locale.CHINA;DateFormat shortDf = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.MEDIUM, locale);System.out.println("中国格式:"+shortDf.format(date)); locale = Locale.ENGLISH;shortDf = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.MEDIUM, locale);System.out.println("英国格式:"+shortDf.format(date));} 

 执行mian方法,结果为:

中国格式:2017-10-12 10:29:44英国格式:Oct 12, 2017 10:29:44 AM 

 

在Spring MVC项目中,一般可以借助spring自动的国际化解决方案,在视图层对不同的国家使用不同的locale参数进行处理。

 

日期时间国际化化时区处理

 

对应的关键词:TimeZone

日期时间的时区问题,指的是在同一时刻,地球上的各个地区的日期时间不同。全球划分为24个时区,每个相邻时区时间相差一个小时(中国为了方便统一,虽然跨越5个时区,但都使用同一个时区时间),也就是说在同一时刻,全球同一时刻对应的当地时间的小时数有可能是0-23点之间的一个值。这里拿中国上海和英国伦敦举例:

public static void main(String[] args) {Date date = new Date();Locale locale = Locale.CHINA;DateFormat shortDf = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.MEDIUM, locale);shortDf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));//Asia/ChongqingSystem.out.println(TimeZone.getDefault().getID());System.out.println("中国当前日期时间:" + shortDf.format(date)); locale = Locale.ENGLISH;shortDf = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.MEDIUM, locale);shortDf.setTimeZone(TimeZone.getTimeZone("Europe/London"));System.out.println("英国当前日期时间:"+shortDf.format(date)); } 

 

执行main方法,运行结果为:

中国当前日期时间:2017-10-12 10:55:55英国当前日期时间:Oct 12, 2017 3:55:55 AM

说明同一时刻,中国上海和英国伦敦相差7个小时,也就是相差7个时区。

 

时区对国际化项目带来的问题

 

日期时间的国际化格式处理 只是显示风格问题 相对来说比较简单,但日期时间的国际化时区问题 确比较麻烦,如果处理不当会引起一些兼容性问题。

 

拿最近做的一个泰国项目举例,我们一个活动页创建项目部署在泰国。如果在中国创建一个活动页,通过时间控件选择活动的开始时间,这时获取的时间是从浏览器获取 为中国时区时间。需要把这个时间传到后端服务器,存储到数据库,但服务器的时间为泰国时区的时间。中国是东八区 泰国是东七区,相差一个小时。这时有两种处理办法:

1、前端传给后端的是字符串,比如开始时间为“2017-10-12 08:00:00”, 后端直接使用这个字符串转换为泰国的Date 存入数据库即可。

public static void main(String[] args) throws Exception{String t="2017-10-12 08:00:00";DateFormat format =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date date = format.parse(t);System.out.println(date); } 

 

看起来比较简单,但关键是这个字符串,前面说了 不同的语言国家这个字符的格式不同,后端需要根据不同的格式进行Format操作。假设换成在英国创建活动,这个Format又得改成英国的格式。

 

2、前端传给后端的是时间戳,比如开始时间为“2017-10-12 08:00:00”,对应的中国的时间戳为:1507766400000,转换成泰国的时间就变成:“2017-10-12 07:00:00”,模拟代码如下:

 

public static void main(String[] args) throws Exception{String t="2017-10-12 08:00:00";//页面传入的时间DateFormat format =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date date = format.parse(t);System.out.println("中国:"+t);  long tl = date.getTime();//模拟前端转换为中国的时间戳TimeZone timeZone2 = TimeZone.getTimeZone("Asia/Bangkok");format.setTimeZone(timeZone2);String d2 = format.format(tl);System.out.println("泰国:"+d2);//存入数据库的时间}

 

 

执行结果为:

中国:2017-10-12 08:00:00泰国:2017-10-12 07:00:00

说明直接传给后端时间搓有问题,但有解决办法:首先后端封装一个接口后获取服务器相对GMT(格林尼治标准时间)时间的偏移量:

TimeZone zone = TimeZone.getDefault();System.out.println(zone.getRawOffset());

这段代码放在不同时区的服务器上执行结果会不同(前提是服务器的时区设置跟本地时区一致)。如果在泰国执行结果为25200000ms,换算成小时为7,说明泰国的时区的偏移量相对于GMT标准时间相差7小时。下文简称“时区偏移量”。

 

以下操作都在浏览器中通过js代码实现:

前端首先调用该接口获取服务器的时区偏移量,再在浏览器上获取本地的时区偏移量,计算出两个偏移量的差值。本地浏览器上获取当前的时间戳,减去上一步计算出来的差值即可得到服务器这个时间的时间戳,把这个时间戳传给后端 再转换成时间,就是服务器对应的时间,存入数据库即可。

 //服务的时区偏移量,通过接口获得,注意换成负值var serveroffset=-25200000;var d = new Date();//获取本地浏览器的时区偏移量var localOffset = d.getTimezoneOffset() * 60000;//的到本地和偏移量的差值var deffoffset=localOffset-(serveroffset);//获取本地浏览器时间戳var localTime = d.getTime();//计算出传到服务器的时间戳var servertime=localTime+deffoffset;

通过上述方式,可以实现服务器全球各地部署,系统都可以正常使用。

 

Java中的TimeZone类

 

Java中处理时区使用的是TimeZone类,通过TimeZone.getTimeZone(String id)方法可以获取到指定时区的TimeZone实例,通过TimeZone实例可以获取到相对于GMT标准时间的偏移量。该方法的参数ID可以是GMT、 UTC、CST等时区,也可以是城市名:

 

public static void main(String[] args) throws Exception{ TimeZone timeZone1 = TimeZone.getDefault();//获取当前服务器时区TimeZone timeZone2 = TimeZone.getTimeZone("Asia/Shanghai");//获取上海时区TimeZone timeZone3 = TimeZone.getTimeZone("GMT");//获取格林威治标准时区TimeZone timeZone4 = TimeZone.getTimeZone("GMT+8");//获取东八区时区TimeZone timeZone5 = TimeZone.getTimeZone("UTC");//获取UTC标准时间TimeZone timeZone6 = TimeZone.getTimeZone("CST");//获取CST时区 System.out.println(timeZone1.getRawOffset());System.out.println(timeZone2.getRawOffset());System.out.println(timeZone3.getRawOffset());System.out.println(timeZone4.getRawOffset());System.out.println(timeZone5.getRawOffset());System.out.println(timeZone6.getRawOffset()); } 

 

GMT和 UTC可以视为几乎是等同的,UTC更精准,有闰秒的概念。

其中TimeZone.getTimeZone("Asia/Shanghai")和TimeZone.getTimeZone("GMT+8")是相同的,可以相互替换使用。又比如泰国的时区ID使用"Asia/Bangkok"和"GMT+7"是相同。

 

通过阅读jdk源码可以发现,TimeZone ID是在java里ZoneInfoFile类加载的。在jvm初始化的时候,会读取jdk安装目录下的 ${ java.home } /jre/lib/tzdb.dat,放到其成员变量为zones的ConcurrentHashMap里。当调用TimeZone.getTimeZone(id)方法时,会用id到这个map里进行匹配获取到指定id的时区。

 

最后附上TimeZone 的ID列表,要获取对应城市的时区,需要先查询到其对应的ID。

 Etc/GMT+12Etc/GMT+11MITPacific/ApiaPacific/MidwayPacific/NiuePacific/Pago_PagoPacific/SamoaUS/SamoaAmerica/AdakAmerica/AtkaEtc/GMT+10HSTPacific/FakaofoPacific/HonoluluPacific/JohnstonPacific/RarotongaPacific/TahitiSystemV/HST10US/AleutianUS/HawaiiPacific/MarquesasASTAmerica/AnchorageAmerica/JuneauAmerica/NomeAmerica/YakutatEtc/GMT+9Pacific/GambierSystemV/YST9SystemV/YST9YDTUS/AlaskaAmerica/DawsonAmerica/EnsenadaAmerica/Los_AngelesAmerica/TijuanaAmerica/VancouverAmerica/WhitehorseCanada/PacificCanada/YukonEtc/GMT+8Mexico/BajaNortePSTPST8PDTPacific/PitcairnSystemV/PST8SystemV/PST8PDTUS/PacificUS/Pacific-NewAmerica/BoiseAmerica/Cambridge_BayAmerica/ChihuahuaAmerica/Dawson_CreekAmerica/DenverAmerica/EdmontonAmerica/HermosilloAmerica/InuvikAmerica/MazatlanAmerica/PhoenixAmerica/ShiprockAmerica/YellowknifeCanada/MountainEtc/GMT+7MSTMST7MDTMexico/BajaSurNavajoPNTSystemV/MST7SystemV/MST7MDTUS/ArizonaUS/MountainAmerica/BelizeAmerica/CancunAmerica/ChicagoAmerica/Costa_RicaAmerica/El_SalvadorAmerica/GuatemalaAmerica/Indiana/KnoxAmerica/Indiana/Tell_CityAmerica/Knox_INAmerica/ManaguaAmerica/MenomineeAmerica/MeridaAmerica/Mexico_CityAmerica/MonterreyAmerica/North_Dakota/CenterAmerica/North_Dakota/New_SalemAmerica/Rainy_RiverAmerica/Rankin_InletAmerica/ReginaAmerica/Swift_CurrentAmerica/TegucigalpaAmerica/WinnipegCSTCST6CDTCanada/CentralCanada/East-SaskatchewanCanada/SaskatchewanChile/EasterIslandEtc/GMT+6Mexico/GeneralPacific/EasterPacific/GalapagosSystemV/CST6SystemV/CST6CDTUS/CentralUS/Indiana-StarkeAmerica/AtikokanAmerica/BogotaAmerica/CaymanAmerica/Coral_HarbourAmerica/DetroitAmerica/Fort_WayneAmerica/Grand_TurkAmerica/GuayaquilAmerica/HavanaAmerica/Indiana/IndianapolisAmerica/Indiana/MarengoAmerica/Indiana/PetersburgAmerica/Indiana/VevayAmerica/Indiana/VincennesAmerica/Indiana/WinamacAmerica/IndianapolisAmerica/IqaluitAmerica/JamaicaAmerica/Kentucky/LouisvilleAmerica/Kentucky/MonticelloAmerica/LimaAmerica/LouisvilleAmerica/MontrealAmerica/NassauAmerica/New_YorkAmerica/NipigonAmerica/PanamaAmerica/PangnirtungAmerica/Port-au-PrinceAmerica/ResoluteAmerica/Thunder_BayAmerica/TorontoCanada/EasternCubaESTEST5EDTEtc/GMT+5IETJamaicaSystemV/EST5SystemV/EST5EDTUS/East-IndianaUS/EasternUS/MichiganAmerica/CaracasAmerica/AnguillaAmerica/AntiguaAmerica/ArubaAmerica/AsuncionAmerica/BarbadosAmerica/Blanc-SablonAmerica/Boa_VistaAmerica/Campo_GrandeAmerica/CuiabaAmerica/CuracaoAmerica/DominicaAmerica/EirunepeAmerica/Glace_BayAmerica/Goose_BayAmerica/GrenadaAmerica/GuadeloupeAmerica/GuyanaAmerica/HalifaxAmerica/La_PazAmerica/ManausAmerica/MarigotAmerica/MartiniqueAmerica/MonctonAmerica/MontserratAmerica/Port_of_SpainAmerica/Porto_AcreAmerica/Porto_VelhoAmerica/Puerto_RicoAmerica/Rio_BrancoAmerica/SantiagoAmerica/Santo_DomingoAmerica/St_BarthelemyAmerica/St_KittsAmerica/St_LuciaAmerica/St_ThomasAmerica/St_VincentAmerica/ThuleAmerica/TortolaAmerica/VirginAntarctica/PalmerAtlantic/BermudaAtlantic/StanleyBrazil/AcreBrazil/WestCanada/AtlanticChile/ContinentalEtc/GMT+4PRTSystemV/AST4SystemV/AST4ADTAmerica/St_JohnsCNTCanada/NewfoundlandAGTAmerica/AraguainaAmerica/Argentina/Buenos_AiresAmerica/Argentina/CatamarcaAmerica/Argentina/ComodRivadaviaAmerica/Argentina/CordobaAmerica/Argentina/JujuyAmerica/Argentina/La_RiojaAmerica/Argentina/MendozaAmerica/Argentina/Rio_GallegosAmerica/Argentina/SaltaAmerica/Argentina/San_JuanAmerica/Argentina/San_LuisAmerica/Argentina/TucumanAmerica/Argentina/UshuaiaAmerica/BahiaAmerica/BelemAmerica/Buenos_AiresAmerica/CatamarcaAmerica/CayenneAmerica/CordobaAmerica/FortalezaAmerica/GodthabAmerica/JujuyAmerica/MaceioAmerica/MendozaAmerica/MiquelonAmerica/MontevideoAmerica/ParamariboAmerica/RecifeAmerica/RosarioAmerica/SantaremAmerica/Sao_PauloAntarctica/RotheraBETBrazil/EastEtc/GMT+3America/NoronhaAtlantic/South_GeorgiaBrazil/DeNoronhaEtc/GMT+2America/ScoresbysundAtlantic/AzoresAtlantic/Cape_VerdeEtc/GMT+1Africa/AbidjanAfrica/AccraAfrica/BamakoAfrica/BanjulAfrica/BissauAfrica/CasablancaAfrica/ConakryAfrica/DakarAfrica/El_AaiunAfrica/FreetownAfrica/LomeAfrica/MonroviaAfrica/NouakchottAfrica/OuagadougouAfrica/Sao_TomeAfrica/TimbuktuAmerica/DanmarkshavnAtlantic/CanaryAtlantic/FaeroeAtlantic/FaroeAtlantic/MadeiraAtlantic/ReykjavikAtlantic/St_HelenaEireEtc/GMTEtc/GMT+0Etc/GMT-0Etc/GMT0Etc/GreenwichEtc/UCTEtc/UTCEtc/UniversalEtc/ZuluEurope/BelfastEurope/DublinEurope/GuernseyEurope/Isle_of_ManEurope/JerseyEurope/LisbonEurope/LondonGBGB-EireGMTGMT0GreenwichIcelandPortugalUCTUTCUniversalWETZuluAfrica/AlgiersAfrica/BanguiAfrica/BrazzavilleAfrica/CeutaAfrica/DoualaAfrica/KinshasaAfrica/LagosAfrica/LibrevilleAfrica/LuandaAfrica/MalaboAfrica/NdjamenaAfrica/NiameyAfrica/Porto-NovoAfrica/TunisAfrica/WindhoekArctic/LongyearbyenAtlantic/Jan_MayenCETECTEtc/GMT-1Europe/AmsterdamEurope/AndorraEurope/BelgradeEurope/BerlinEurope/BratislavaEurope/BrusselsEurope/BudapestEurope/CopenhagenEurope/GibraltarEurope/LjubljanaEurope/LuxembourgEurope/MadridEurope/MaltaEurope/MonacoEurope/OsloEurope/ParisEurope/PodgoricaEurope/PragueEurope/RomeEurope/San_MarinoEurope/SarajevoEurope/SkopjeEurope/StockholmEurope/TiraneEurope/VaduzEurope/VaticanEurope/ViennaEurope/WarsawEurope/ZagrebEurope/ZurichMETPolandARTAfrica/BlantyreAfrica/BujumburaAfrica/CairoAfrica/GaboroneAfrica/HarareAfrica/JohannesburgAfrica/KigaliAfrica/LubumbashiAfrica/LusakaAfrica/MaputoAfrica/MaseruAfrica/MbabaneAfrica/TripoliAsia/AmmanAsia/BeirutAsia/DamascusAsia/GazaAsia/IstanbulAsia/JerusalemAsia/NicosiaAsia/Tel_AvivCATEETEgyptEtc/GMT-2Europe/AthensEurope/BucharestEurope/ChisinauEurope/HelsinkiEurope/IstanbulEurope/KaliningradEurope/KievEurope/MariehamnEurope/MinskEurope/NicosiaEurope/RigaEurope/SimferopolEurope/SofiaEurope/TallinnEurope/TiraspolEurope/UzhgorodEurope/VilniusEurope/ZaporozhyeIsraelLibyaTurkeyAfrica/Addis_AbabaAfrica/AsmaraAfrica/AsmeraAfrica/Dar_es_SalaamAfrica/DjiboutiAfrica/KampalaAfrica/KhartoumAfrica/MogadishuAfrica/NairobiAntarctica/SyowaAsia/AdenAsia/BaghdadAsia/BahrainAsia/KuwaitAsia/QatarAsia/RiyadhEATEtc/GMT-3Europe/MoscowEurope/VolgogradIndian/AntananarivoIndian/ComoroIndian/MayotteW-SUAsia/Riyadh87Asia/Riyadh88Asia/Riyadh89Mideast/Riyadh87Mideast/Riyadh88Mideast/Riyadh89Asia/TehranIranAsia/BakuAsia/DubaiAsia/MuscatAsia/TbilisiAsia/YerevanEtc/GMT-4Europe/SamaraIndian/MaheIndian/MauritiusIndian/ReunionNETAsia/KabulAsia/AqtauAsia/AqtobeAsia/AshgabatAsia/AshkhabadAsia/DushanbeAsia/KarachiAsia/OralAsia/SamarkandAsia/TashkentAsia/YekaterinburgEtc/GMT-5Indian/KerguelenIndian/MaldivesPLTAsia/CalcuttaAsia/ColomboAsia/KolkataISTAsia/KathmanduAsia/KatmanduAntarctica/MawsonAntarctica/VostokAsia/AlmatyAsia/BishkekAsia/DaccaAsia/DhakaAsia/NovosibirskAsia/OmskAsia/QyzylordaAsia/ThimbuAsia/ThimphuBSTEtc/GMT-6Indian/ChagosAsia/RangoonIndian/CocosAntarctica/DavisAsia/BangkokAsia/Ho_Chi_MinhAsia/HovdAsia/JakartaAsia/KrasnoyarskAsia/Phnom_PenhAsia/PontianakAsia/SaigonAsia/VientianeEtc/GMT-7Indian/ChristmasVSTAntarctica/CaseyAsia/BruneiAsia/ChoibalsanAsia/ChongqingAsia/ChungkingAsia/HarbinAsia/Hong_KongAsia/IrkutskAsia/KashgarAsia/Kuala_LumpurAsia/KuchingAsia/MacaoAsia/MacauAsia/MakassarAsia/ManilaAsia/ShanghaiAsia/SingaporeAsia/TaipeiAsia/Ujung_PandangAsia/UlaanbaatarAsia/Ulan_BatorAsia/UrumqiAustralia/PerthAustralia/WestCTTEtc/GMT-8HongkongPRCSingaporeAustralia/EuclaAsia/DiliAsia/JayapuraAsia/PyongyangAsia/SeoulAsia/TokyoAsia/YakutskEtc/GMT-9JSTJapanPacific/PalauROKACTAustralia/AdelaideAustralia/Broken_HillAustralia/DarwinAustralia/NorthAustralia/SouthAustralia/YancowinnaAETAntarctica/DumontDUrvilleAsia/SakhalinAsia/VladivostokAustralia/ACTAustralia/BrisbaneAustralia/CanberraAustralia/CurrieAustralia/HobartAustralia/LindemanAustralia/MelbourneAustralia/NSWAustralia/QueenslandAustralia/SydneyAustralia/TasmaniaAustralia/VictoriaEtc/GMT-10Pacific/GuamPacific/Port_MoresbyPacific/SaipanPacific/TrukPacific/YapAustralia/LHIAustralia/Lord_HoweAsia/MagadanEtc/GMT-11Pacific/EfatePacific/GuadalcanalPacific/KosraePacific/NoumeaPacific/PonapeSSTPacific/NorfolkAntarctica/McMurdoAntarctica/South_PoleAsia/AnadyrAsia/KamchatkaEtc/GMT-12KwajaleinNSTNZPacific/AucklandPacific/FijiPacific/FunafutiPacific/KwajaleinPacific/MajuroPacific/NauruPacific/TarawaPacific/WakePacific/WallisNZ-CHATPacific/ChathamEtc/GMT-13Pacific/EnderburyPacific/TongatapuEtc/GMT-14Pacific/Kiritimati

 

java时区TimeZone

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台