java转换时区时间过程详解

这篇文章主要介绍了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

/**
   * 将本地时间, 转换成目标时区的时间
   * @param sourceDate
   * @param targetZoneId {@link ZoneIds}
   * @return
   */
  public static Date convertTimezone(Date sourceDate, String targetZoneId){
    return convertTimezone(sourceDate, TimeZone.getTimeZone(targetZoneId));
  }

  public static Date convertTimezone(Date sourceDate, String sourceZoneId, String targetZoneId){
    TimeZone sourceTimeZone=TimeZone.getTimeZone(sourceZoneId);
    TimeZone targetTimeZone=TimeZone.getTimeZone(targetZoneId);

    return convertTimezone(sourceDate, sourceTimeZone, targetTimeZone);
  }

  /**
   * 将本地时间,转换成对应时区的时间
   * @param localDate
   * @param targetTimezone 转换成目标时区所在的时间
   * @return
   */
  public static Date convertTimezone(Date localDate, TimeZone targetTimezone){
    return convertTimezone(localDate, TimeZone.getDefault(), targetTimezone);
  }

  /**
   * 将sourceDate转换成指定时区的时间
   * @param sourceDate
   * @param sourceTimezone sourceDate所在的时区
   * @param targetTimezone 转化成目标时间所在的时区
   * @return
   */
  public static Date convertTimezone(Date sourceDate, TimeZone sourceTimezone, TimeZone targetTimezone){

    // targetDate - sourceDate=targetTimezone-sourceTimezone
    // --->
    // targetDate=sourceDate + (targetTimezone-sourceTimezone)

    Calendar calendar=Calendar.getInstance();    // date.getTime() 为时间戳, 为格林尼治到系统现在的时间差,世界各个地方获取的时间戳是一样的,    // 格式化输出时,因为设置了不同的时区,所以输出不一样
    long sourceTime=sourceDate.getTime(); 

    calendar.setTimeZone(sourceTimezone);
    calendar.setTimeInMillis(sourceTime);// 设置之后,calendar会计算各种filed对应的值,并保存

    //获取源时区的到UTC的时区差
    int sourceZoneOffset=calendar.get(Calendar.ZONE_OFFSET);

    calendar.setTimeZone(targetTimezone);
    calendar.setTimeInMillis(sourceTime);

    int targetZoneOffset=calendar.get(Calendar.ZONE_OFFSET);
    int targetDaylightOffset=calendar.get(Calendar.DST_OFFSET); // 夏令时

    long targetTime=sourceTime+ (targetZoneOffset+targetDaylightOffset) -sourceZoneOffset;

    return new Date(targetTime); 

  }

ZoneIds.java

/**
 *
 * @see java.time.ZoneId#SHORT_IDS
 * @author TimFruit
 * @date 19-11-2 下午6:02
 */
public class ZoneIds {

  /*
  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_Min
   */

  public static final String UTC="Z";// utc国际时间

  public static final String DEFAULT=TimeZone.getDefault().toZoneId().getId();

  public static final String BEIJING="Asia/Shanghai"; //也可以使用"+8" 北京在东8区

  //
//  UTC+10 夏莫罗标准时区
//  UTC-11 美属萨摩亚标准时区
//  UTC-10HST夏威夷-阿留申标准时区
//  UTC-9AKST阿拉斯加标准时区
//  UTC-8PST太平洋标准时区
//  UTC-7MST山地标准时区
//  UTC-6CST中部标准时区
//  UTC-5EST东部标准时区
//  UTC-4AST大西洋标准时区

  //https://baike.baidu.com/item/%E7%BE%8E%E5%9B%BD%E6%97%B6%E9%97%B4/3163209?fr=aladdin
  /*
  太平洋时区:代表城市洛杉矶,与北京相差16小时;
山地时区:代表城市盐湖城,与北京相差15小时;
中部时区:代表城市芝加哥,与北京相差14小时;
东部时区:代表城市纽约、华盛顿,与北京相差13小时;
夏威夷时区:代表城市:火奴鲁鲁,与北京相差18小时;
阿拉斯加时区:代表城市:费尔班克斯,与北京相差17小时。
   */
  public static final String US_EST="-5"; //东部标准时区
  public static final String US_CST="-6";// 中部标准时区
  public static final String US_MST="-7";// 山地标准时区
  public static final String US_PST="America/Los_Angeles"; //也可以使用"-8" 太平洋标准时区

  public static final String JST="Asia/Tokyo";//日本东京
}

测试:

@Test
  public void convertTimezonePstNowTest(){
    // 太平洋时区:代表城市洛杉矶,与北京相差16小时;
    // 但由于实行夏令时, 夏季会快一个小时
    Date now=new Date();

    convertTimeZonePstTest(now);

  }

  @Test
  public void convertTimezonePstTest1(){
    // 太平洋时区:代表城市洛杉矶,与北京相差16小时;
    // 但由于实行夏令时, 夏季会快一个小时
    Date now=DateUtils.parse("2019-11-03 03:00:00");
    convertTimeZonePstTest(now);

    now=DateUtils.parse("2019-11-03 06:00:00");
    convertTimeZonePstTest(now);

    now=DateUtils.parse("2019-11-03 09:00:00");
    convertTimeZonePstTest(now);

    now=DateUtils.parse("2019-11-03 11:00:00");
    convertTimeZonePstTest(now);

    now=DateUtils.parse("2019-11-03 14:00:00");
    convertTimeZonePstTest(now);

    now=DateUtils.parse("2019-11-03 16:00:00");
    convertTimeZonePstTest(now);

    now=DateUtils.parse("2019-11-03 18:00:00");
    convertTimeZonePstTest(now);

    now=DateUtils.parse("2019-11-03 19:00:00");
    convertTimeZonePstTest(now);

    now=DateUtils.parse("2019-11-03 20:00:00");
    convertTimeZonePstTest(now);

    now=DateUtils.parse("2019-11-03 23:00:00");
    convertTimeZonePstTest(now);
  }

  private void convertTimeZonePstTest(Date sourceDate){
    Date target=DateUtils.convertTimezone(sourceDate, ZoneIds.US_PST);
    long sub=sourceDate.getTime()-target.getTime();
    System.out.println("北京时间与洛杉矶时间相差时间: "+sub/(60*60*1000) +" 小时");

    //由于有夏令时, 使用jdk提供的方法验证
    SimpleDateFormat pstSdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    pstSdf.setTimeZone(TimeZone.getTimeZone(ZoneIds.US_PST));
    String expectFormat=pstSdf.format(sourceDate);

    String targetFormat=DateUtils.format(target);
    System.out.println("洛杉矶时间: "+targetFormat);
    Assert.assertEquals(expectFormat,targetFormat);
  }

完整源码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java时区转换及Date类实现原理解析

    这篇文章主要介绍了Java时区转换及Date类实现原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.时区的说明 地球表面按经线从东到西,被划成一个个区域,规定相邻区域的时间相差1小时.在同一区域内的东端和西端的人看到太阳升起的时间最多相差不过1小时.当人们跨过一个区域,就将自己的时钟校正1小时(向西减1小时,向东加1小时),跨过几个区域就加或减几小时 ,所以同一时刻在不同时区表示的时间是不一样的. 二.时间的表示 我们平时表示时间时通

  • 基于java时区转换夏令时的问题及解决方法

    一.准备知识 1.America/New_York的夏令时时间如下: 包左不包右 2016-3-13, 02:00:00到2016-11-6, 02:00:00 2017-3-12, 02:00:00到2017-11-5, 02:00:00 2.三字母时区 ID 为了与 JDK 1.1.x 兼容,一些三字母时区 ID(比如 "PST"."CTT"."AST")也受支持. 但是,它们的使用被废弃,这是因为相同的缩写经常用于多个时区 例如 CST:有

  • Java时区转换实例代码解析

    一.时区的说明 地球表面按经线从东到西,被划成一个个区域,规定相邻区域的时间相差1小时.在同一区域内的东端和西端的人看到太阳升起的时间最多相差不过1小时.当人们跨过一个区域,就将自己的时钟校正1小时(向西减1小时,向东加1小时),跨过几个区域就加或减几小时 ,所以同一时刻在不同时区表示的时间是不一样的. 二.时间的表示 我们平时表示时间时通常是以一个格式化的字符串来表示一个时间,例如"2019-11-5 20:05"这个字符串表示的是2019年11月5日20点05分.但这里有一个隐含的

  • 详解Java中的时区类TimeZone的用法

    一.TimeZone 简介 TimeZone 表示时区偏移量,也可以计算夏令时. 在操作 Date, Calendar等表示日期/时间的对象时,经常会用到TimeZone:因为不同的时区,时间不同. 下面说说TimeZone对象的 2种常用创建方式. 1.获取默认的TimeZone对象 使用方法: TimeZone tz = TimeZone.getDefault() 2.使用 getTimeZone(String id) 方法获取TimeZone对象 使用方法: // 获取 "GMT+08:0

  • Java中指定时区的3种方法

    这两天在做与某知名一卡通公司的单点登录集成(我们的产品使用Java编写,对方的程序使用.Net编写)其中有一项参数是时间戳.即当前时间相对于公元1970-1-1 00:00:00的秒数.按照他们给出的文档我完成了Java部分的编写,时间戳部分很简单,一句话: 复制代码 代码如下: private String createTimestamp() //timestamp     {         return System.currentTimeMillis() / 1000 + ""

  • java转换时区时间过程详解

    这篇文章主要介绍了java转换时区时间过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一丶时区 由于世界各国家与地区经度不同,地方时也有所不同,因此会划分为不同的时区. 地球是自西向东自转,东边比西边先看到太阳,东边的时间也比西边的早.东边时刻与西边时刻的差值不仅要以时计,而且还要以分和秒来计算,这给人们带来不便. 为了克服时间上的混乱,1884年在华盛顿召开的一次国际经度会议(又称国际子午线会议)上,规定将全球划分为24个时区(东.西

  • Java搭建RabbitMq消息中间件过程详解

    这篇文章主要介绍了Java搭建RabbitMq消息中间件过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前言 当系统中出现"生产"和"消费"的速度或稳定性等因素不一致的时候,就需要消息队列. 名词 exchange: 交换机 routingkey: 路由key queue:队列 控制台端口:15672 exchange和queue是需要绑定在一起的,然后消息发送到exchange再由exchange通过ro

  • Java Servlet响应httpServletResponse过程详解

    目录 一.核心方法 1.setStatus 2.setHeader(Stringname,Stringvalue) 3.addHeader(Stringname,Stringvalue) 4.setContentType(Stringtype) 二.响应一个网页 三.返回一个文件 四.返回json数据 一.核心方法 1.setStatus 设置响应状态码 如果没有调用这个方法,默认返回200状态码(前提:正常执行,没有异常) 如果出现异常,返回500 前端代码: <body> <h3&g

  • JAVA如何调用wsdl过程详解

    前提:① 已经提供了一个wsdl接口② 该接口能正常调用 总体分为两种方式: 1.使用cxf的wsdl2java工具生成本地类(使用方式就是本地类的使用). 2.调用远程的web service方法:创建client来远程调用接口. 因为第二种方式,需要熟悉wsdl,没深入了解不太好操作,主要说下第一种方式. 使用cxf的wsdl2java工具生成本地类主要步骤如下: 1.安装JDK环境(jdk版本是1.6的话,后续会报错jdk6最高只支持ws2.1规范版本) 2.下载apache-cxf发布包

  • java虚拟机原理:类加载过程详解

    目录 一.Java 类加载过程 1.字节码编译 2.加载 3.连接 4.初始化 总结 一.Java 类加载过程 1.字节码编译 编写好 Java 源码 Student.java , 使用 javac 将上述 Java 源码编译成 Class 字节码文件 Student.class , 2.加载 加载 : 通过 " 类加载子系统 " 将该字节码文件 , 加载到 Java 虚拟机内存中 的 方法区 , 然后开始执行 " 连接 " 操作 , 类加载时机 : Java 程序

  • Java通过BCrypt加密过程详解

    一.概述 在用户模块,对于用户密码的保护,通常都会进行加密.我们通常对密码进行加密,然后存放在数据库中,在用户进行登录的时候,将其输入的密码进行加密然后与数据库中存放的密文进行比较,以验证用户密码是否正确. 目前,MD5和BCrypt比较流行.相对来说,BCrypt比MD5更安全,但加密更慢. 二.使用BCrypt 首先,可以在官网中取得源代码 然后通过Ant进行编译.编译之后得到jbcrypt.jar.也可以不需要进行编译,而直接使用源码中的java文件(本身仅一个文件). 下面是官网的一个D

  • Java emoji持久化mysql过程详解

    前言 好久没有更新博客了,今天和大家分享一个关于emoji表情持久化问题,相信做web开发的都遇到过这样的问题,因为我们知道mysql的utf-8字符集保存不了保存不了表情字符,这是为什么呢?因为普通的字符串或者表情都是占位3个字节,所以utf8足够用了,但是移动端的表情符号占位是4个字节,普通的utf8就不够用了,为了应对无线互联网的机遇和挑战.避免 emoji 表情符号带来的问题.涉及无线相关的 MySQL 数据库建议都提前采用 utf8mb4 字符集,这必须要作为移动互联网行业的一个技术选

  • 使用Java Api操作HDFS过程详解

    如题 我就是一个标题党 就是使用JavaApi操作HDFS,使用的是MAVEN,操作的环境是Linux 首先要配置好Maven环境,我使用的是已经有的仓库,如果你下载的jar包 速度慢,可以改变Maven 下载jar包的镜像站改为 阿里云. 贴一下 pom.xml 使用到的jar包 <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifact

  • 基于Java代码操作Redis过程详解

    Jedis简介 实际开发中,我们需要用Redis的连接工具连接Redis然后操作Redis, 对于主流语言,Redis都提供了对应的客户端: 提供了很多客户端 官方推荐的是Jedis 托管地址:https://github.com/xetorthio/jedis 要使用redis首先得下载pom依赖 <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId&g

  • Java HttpServletResponse响应实现过程详解

    用户在客户端输入网址(虚拟路径)时,开始发送一个HTTP请求(请求行.请求头.请求体)至服务器.服务器内的Tomcat引擎会解析请求的地址,去找XML文件,然后根据虚拟路径找Servlet的真实路径,真实的Servlet会将请求的信息封装成request(请求)对象,然后再创建一个response(响应)对象,(此时的response内是空的)同时创建servlet对象,并调用service方法(或doGet和doPost方法). 这样就是把两个对象传给了服务器内的某个servlet的servi

随机推荐