java中转换不同时区的时间

一丶时区

  由于世界各国家与地区经度不同,地方时也有所不同,因此会划分为不同的时区。

 

  地球是自西向东自转,东边比西边先看到太阳,东边的时间也比西边的早。东边时刻与西边时刻的差值不仅要以时计,而且还要以分和秒来计算,这给人们带来不便。

  为了克服时间上的混乱,1884年在华盛顿召开的一次国际经度会议(又称国际子午线会议)上,规定将全球划分为24个时区(东、西各12个时区)。规定英国(格林尼治天文台旧址)为中时区(零时区)、东1—12区,西1—12区。每个时区横跨经度15度,时间正好是1小时。最后的东、西第12区各跨经度7.5度,以东、西经180度为界。每个时区的中央经线上的时间就是这个时区内统一采用的时间,称为区时,相邻两个时区的时间相差1小时。

 

  计算的区时=已知区时-(已知区时的时区-要计算区时的时区)。(注:东时区为正,西时区为负)

  例1:已知东京(东九区)时间为5月1日12:00,求北京(东八区)的区时。
  北京时间=12:00-(9-8)=11:00,即北京时间为5月1日11:00。
  例2:已知北京时间为5月1日12:00,求伦敦(中时区)的区时。
  伦敦时间=12:00-(8-0)=4:00,即伦敦时间为5月1日4:00。

 

 

二丶UTC时间 与 格林尼治时间

  协调世界时,又称世界统一时间、世界标准时间、国际协调时间。由于英文(CUT)和法文(TUC)的缩写不同,作为妥协,简称UTC。

  格林尼治标准时间(Greenwich Mean Time,GMT)是指位于伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。 理论上来说,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时的时间。由于地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能和实际的太阳时相差16分钟。 地球每天的自转是有些不规则的,而且正在缓慢减速。所以,格林尼治时间已经不再被作为标准时间使用。现在的标准时间——协调世界时(UTC)——由原子钟提供。 自1924年2月5日开始,格林尼治天文台每隔一小时会向全世界发放调时信息。而UTC是基于标准的GMT提供的准确时间。

  GMT(Greenwich Mean Time)——格林尼治标准时间,格林尼治标准时间是19 世纪中叶大英帝国的基准时间,同时也是事实上的世界基准时间。当时主要为了1840 年之后的铁路系统服务。它以格林尼治天文台的经线为0 度经线,将世界分为24 个时区。为了方便,在不需要精确到秒的情况下,通常将GMT 和UTC 视作等同。但UTC 更加科学更加精确,它是以原子时为基础,在时刻上尽量接近世界时的一种时间计量系统。它的出现是现代社会对于精确计时的需要。

  

四丶夏令时

 夏令时,表示为了节约能源,人为规定时间的意思。也叫夏时制,夏时令(Daylight Saving Time:DST),又称“日光节约时制”和“夏令时间”,在这一制度实行期间所采用的统一时间称为“夏令时间”。一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。目前全世界有近110个国家每年要实行夏令时。

  中国已不使用夏令时.

 

五丶区时转换

  计算区时(时间) – 已知区时(时间) = 计算时区 – 已知区时的时区.

  所以, 计算区时(时间)= 已知区时(时间) + 计算时区 – 已知区时的时区.

  需要注意的是, 有的地区在夏季使用夏令时, 即时钟会拨快一个小时.

 

  DateUtils.java

  1. /**
  2. * 将本地时间, 转换成目标时区的时间
  3. * @param sourceDate
  4. * @param targetZoneId {@link ZoneIds}
  5. * @return
  6. */
  7. public static Date convertTimezone(Date sourceDate, String targetZoneId){
  8. return convertTimezone(sourceDate, TimeZone.getTimeZone(targetZoneId));
  9. }
  10. public static Date convertTimezone(Date sourceDate, String sourceZoneId, String targetZoneId){
  11. TimeZone sourceTimeZone=TimeZone.getTimeZone(sourceZoneId);
  12. TimeZone targetTimeZone=TimeZone.getTimeZone(targetZoneId);
  13. return convertTimezone(sourceDate, sourceTimeZone, targetTimeZone);
  14. }
  15. /**
  16. * 将本地时间,转换成对应时区的时间
  17. * @param localDate
  18. * @param targetTimezone 转换成目标时区所在的时间
  19. * @return
  20. */
  21. public static Date convertTimezone(Date localDate, TimeZone targetTimezone){
  22. return convertTimezone(localDate, TimeZone.getDefault(), targetTimezone);
  23. }
  24. /**
  25. * 将sourceDate转换成指定时区的时间
  26. * @param sourceDate
  27. * @param sourceTimezone sourceDate所在的时区
  28. * @param targetTimezone 转化成目标时间所在的时区
  29. * @return
  30. */
  31. public static Date convertTimezone(Date sourceDate, TimeZone sourceTimezone, TimeZone targetTimezone){
  32. // targetDate - sourceDate=targetTimezone-sourceTimezone
  33. // --->
  34. // targetDate=sourceDate + (targetTimezone-sourceTimezone)
  35. Calendar calendar=Calendar.getInstance();
    // date.getTime() 为时间戳, 为格林尼治到系统现在的时间差,世界各个地方获取的时间戳是一样的,
    // 格式化输出时,因为设置了不同的时区,所以输出不一样
  36. long sourceTime=sourceDate.getTime();
  37. calendar.setTimeZone(sourceTimezone);
  38. calendar.setTimeInMillis(sourceTime);// 设置之后,calendar会计算各种filed对应的值,并保存
  39. //获取源时区的到UTC的时区差
  40. int sourceZoneOffset=calendar.get(Calendar.ZONE_OFFSET);
  41. calendar.setTimeZone(targetTimezone);
  42. calendar.setTimeInMillis(sourceTime);
  43. int targetZoneOffset=calendar.get(Calendar.ZONE_OFFSET);
  44. int targetDaylightOffset=calendar.get(Calendar.DST_OFFSET); // 夏令时
  45.  
  46.  
  47. long targetTime=sourceTime+ (targetZoneOffset+targetDaylightOffset) -sourceZoneOffset;
  48. return new Date(targetTime);
  49. }

 

  ZoneIds.java

  1. /**
  2. *
  3. * @see java.time.ZoneId#SHORT_IDS
  4. * @author TimFruit
  5. * @date 19-11-2 下午6:02
  6. */
  7. public class ZoneIds {
  8. /*
  9. EST - -05:00
  10. HST - -10:00
  11. MST - -07:00
  12. ACT - Australia/Darwin
  13. AET - Australia/Sydney
  14. AGT - America/Argentina/Buenos_Aires
  15. ART - Africa/Cairo
  16. AST - America/Anchorage
  17. BET - America/Sao_Paulo
  18. BST - Asia/Dhaka
  19. CAT - Africa/Harare
  20. CNT - America/St_Johns
  21. CST - America/Chicago
  22. CTT - Asia/Shanghai
  23. EAT - Africa/Addis_Ababa
  24. ECT - Europe/Paris
  25. IET - America/Indiana/Indianapolis
  26. IST - Asia/Kolkata
  27. JST - Asia/Tokyo
  28. MIT - Pacific/Apia
  29. NET - Asia/Yerevan
  30. NST - Pacific/Auckland
  31. PLT - Asia/Karachi
  32. PNT - America/Phoenix
  33. PRT - America/Puerto_Rico
  34. PST - America/Los_Angeles
  35. SST - Pacific/Guadalcanal
  36. VST - Asia/Ho_Chi_Min
  37. */
  38.  
  39. public static final String UTC="Z";// utc国际时间
  40.  
  41. public static final String DEFAULT=TimeZone.getDefault().toZoneId().getId();
  42. public static final String BEIJING="Asia/Shanghai"; //也可以使用"+8" 北京在东8区
  43. //
  44. // UTC+10 夏莫罗标准时区
  45. // UTC-11 美属萨摩亚标准时区
  46. // UTC-10HST夏威夷-阿留申标准时区
  47. // UTC-9AKST阿拉斯加标准时区
  48. // UTC-8PST太平洋标准时区
  49. // UTC-7MST山地标准时区
  50. // UTC-6CST中部标准时区
  51. // UTC-5EST东部标准时区
  52. // UTC-4AST大西洋标准时区
  53. //https://baike.baidu.com/item/%E7%BE%8E%E5%9B%BD%E6%97%B6%E9%97%B4/3163209?fr=aladdin
  54. /*
  55. 太平洋时区:代表城市洛杉矶,与北京相差16小时;
  56. 山地时区:代表城市盐湖城,与北京相差15小时;
  57. 中部时区:代表城市芝加哥,与北京相差14小时;
  58. 东部时区:代表城市纽约、华盛顿,与北京相差13小时;
  59. 夏威夷时区:代表城市:火奴鲁鲁,与北京相差18小时;
  60. 阿拉斯加时区:代表城市:费尔班克斯,与北京相差17小时。
  61. */
  62. public static final String US_EST="-5"; //东部标准时区
  63. public static final String US_CST="-6";// 中部标准时区
  64. public static final String US_MST="-7";// 山地标准时区
  65. public static final String US_PST="America/Los_Angeles"; //也可以使用"-8" 太平洋标准时区
  66.  
  67.  
  68. public static final String JST="Asia/Tokyo";//日本东京
  69. }

 

  测试:

  1. @Test
  2. public void convertTimezonePstNowTest(){
  3. // 太平洋时区:代表城市洛杉矶,与北京相差16小时;
  4. // 但由于实行夏令时, 夏季会快一个小时
  5. Date now=new Date();
  6. convertTimeZonePstTest(now);
  7. }
  8. @Test
  9. public void convertTimezonePstTest1(){
  10. // 太平洋时区:代表城市洛杉矶,与北京相差16小时;
  11. // 但由于实行夏令时, 夏季会快一个小时
  12. Date now=DateUtils.parse("2019-11-03 03:00:00");
  13. convertTimeZonePstTest(now);
  14. now=DateUtils.parse("2019-11-03 06:00:00");
  15. convertTimeZonePstTest(now);
  16. now=DateUtils.parse("2019-11-03 09:00:00");
  17. convertTimeZonePstTest(now);
  18. now=DateUtils.parse("2019-11-03 11:00:00");
  19. convertTimeZonePstTest(now);
  20. now=DateUtils.parse("2019-11-03 14:00:00");
  21. convertTimeZonePstTest(now);
  22. now=DateUtils.parse("2019-11-03 16:00:00");
  23. convertTimeZonePstTest(now);
  24. now=DateUtils.parse("2019-11-03 18:00:00");
  25. convertTimeZonePstTest(now);
  26. now=DateUtils.parse("2019-11-03 19:00:00");
  27. convertTimeZonePstTest(now);
  28. now=DateUtils.parse("2019-11-03 20:00:00");
  29. convertTimeZonePstTest(now);
  30. now=DateUtils.parse("2019-11-03 23:00:00");
  31. convertTimeZonePstTest(now);
  32. }
  33. private void convertTimeZonePstTest(Date sourceDate){
  34. Date target=DateUtils.convertTimezone(sourceDate, ZoneIds.US_PST);
  35. long sub=sourceDate.getTime()-target.getTime();
  36. System.out.println("北京时间与洛杉矶时间相差时间: "+sub/(60*60*1000) +" 小时");
  37. //由于有夏令时, 使用jdk提供的方法验证
  38. SimpleDateFormat pstSdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  39. pstSdf.setTimeZone(TimeZone.getTimeZone(ZoneIds.US_PST));
  40. String expectFormat=pstSdf.format(sourceDate);
  41. String targetFormat=DateUtils.format(target);
  42. System.out.println("洛杉矶时间: "+targetFormat);
  43. Assert.assertEquals(expectFormat,targetFormat);
  44. }

 

 

 

 

 

完整源码

 

版权声明:本文为timfruit原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/timfruit/p/11788366.html