java对世界各个时区(TimeZone)的通用转换处理方法

在进行国际性软件项目开发的过程中,有时候会碰到一些比较特殊的要求。比如:比如说,你做的是个购物网站(假设服务器放在中国上海),当全世界客户在你的网站上下订单买东西后,往往希望看到客户所在地下单时间,比如说我是个美国纽约人,我在你的网站上下单后,你给我看到一个上海的下单时间,会觉得非常的奇怪。众所周知,纽约时间相对上海时间大约要晚13小时,如果让客户看到本地时区的时间,将变得更加符合客户的时间观念,使得客户理解比较方便。

其实,java中早已考虑过世界时区(TimeZone)这个问题,并给出了比较合理的解决方法,可以比较方便的进行世界时区时间的转化,将一个时区的时间转换成另一个时区的时间。可以看看下面的的实际例子(运行例子的main()方法)。

关于如何知道客户所在的时区,可以根据客户所在的ip或者用户注册提供的国家来计算出所在的时区。

/*
 * Created on 2005-6-10
 * Author stephen
 * Email zhoujianqiang AT gmail DOT com
 * CopyRight(C)2005-2008 , All rights reserved.
 */
package com.soft4j.utility;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.Vector;

import com.soft4j.log.Log;

/**
 * 与日期、时间相关的一些常用工具方法.
 * <p>
 * 日期(时间)的常用格式(formater)主要有: <br>
 * yyyy-MM-dd HH:mm:ss <br>
 *
 * @author stephen
 * @version 1.0.0
 */
public final class DateTool {

    /**
     * 对日期(时间)中的日进行加减计算. <br>
     * 例子: <br>
     * 如果Date类型的d为 2005年8月20日,那么 <br>
     * calculateByDate(d,-10)的值为2005年8月10日 <br>
     * 而calculateByDate(d,+10)的值为2005年8月30日 <br>
     *
     * @param d
     *            日期(时间).
     * @param amount
     *            加减计算的幅度.+n=加n天;-n=减n天.
     * @return 计算后的日期(时间).
     */
    public static Date calculateByDate(Date d, int amount) {
        return calculate(d, GregorianCalendar.DATE, amount);
    }

    public static Date calculateByMinute(Date d, int amount) {
        return calculate(d, GregorianCalendar.MINUTE, amount);
    }

    public static Date calculateByYear(Date d, int amount) {
        return calculate(d, GregorianCalendar.YEAR, amount);
    }

    /**
     * 对日期(时间)中由field参数指定的日期成员进行加减计算. <br>
     * 例子: <br>
     * 如果Date类型的d为 2005年8月20日,那么 <br>
     * calculate(d,GregorianCalendar.YEAR,-10)的值为1995年8月20日 <br>
     * 而calculate(d,GregorianCalendar.YEAR,+10)的值为2015年8月20日 <br>
     *
     * @param d
     *            日期(时间).
     * @param field
     *            日期成员. <br>
     *            日期成员主要有: <br>
     *            年:GregorianCalendar.YEAR <br>
     *            月:GregorianCalendar.MONTH <br>
     *            日:GregorianCalendar.DATE <br>
     *            时:GregorianCalendar.HOUR <br>
     *            分:GregorianCalendar.MINUTE <br>
     *            秒:GregorianCalendar.SECOND <br>
     *            毫秒:GregorianCalendar.MILLISECOND <br>
     * @param amount
     *            加减计算的幅度.+n=加n个由参数field指定的日期成员值;-n=减n个由参数field代表的日期成员值.
     * @return 计算后的日期(时间).
     */
    private static Date calculate(Date d, int field, int amount) {
        if (d == null)
            return null;
        GregorianCalendar g = new GregorianCalendar();
        g.setGregorianChange(d);
        g.add(field, amount);
        return g.getTime();
    }

    /**
     * 日期(时间)转化为字符串.
     *
     * @param formater
     *            日期或时间的格式.
     * @param aDate
     *            java.util.Date类的实例.
     * @return 日期转化后的字符串.
     */
    public static String date2String(String formater, Date aDate) {
        if (formater == null || "".equals(formater))
            return null;
        if (aDate == null)
            return null;
        return (new SimpleDateFormat(formater)).format(aDate);
    }

    /**
     * 当前日期(时间)转化为字符串.
     *
     * @param formater
     *            日期或时间的格式.
     * @return 日期转化后的字符串.
     */
    public static String date2String(String formater) {
        return date2String(formater, new Date());
    }

    /**
     * 获取当前日期对应的星期数.
     * <br>1=星期天,2=星期一,3=星期二,4=星期三,5=星期四,6=星期五,7=星期六
     * @return 当前日期对应的星期数
     */
    public static int dayOfWeek() {
        GregorianCalendar g = new GregorianCalendar();
        int ret = g.get(java.util.Calendar.DAY_OF_WEEK);
        g = null;
        return ret;
    }

    /**
     * 获取所有的时区编号. <br>
     * 排序规则:按照ASCII字符的正序进行排序. <br>
     * 排序时候忽略字符大小写.
     *
     * @return 所有的时区编号(时区编号已经按照字符[忽略大小写]排序).
     */
    public static String[] fecthAllTimeZoneIds() {
        Vector v = new Vector();
        String[] ids = TimeZone.getAvailableIDs();
        for (int i = 0; i < ids.length; i++) {
            v.add(ids[i]);
        }
        java.util.Collections.sort(v, String.CASE_INSENSITIVE_ORDER);
        v.copyInto(ids);
        v = null;
        return ids;
    }

    /**
     * 测试的main方法.
     *
     * @param argc
     */
    public static void main(String[] argc) {

        String[] ids = fecthAllTimeZoneIds();
        String nowDateTime =date2String("yyyy-MM-dd HH:mm:ss");
        System.out.println("The time Asia/Shanhai is " + nowDateTime);//程序本地运行所在时区为[Asia/Shanhai]
        //显示世界每个时区当前的实际时间
        for(int i=0;i <ids.length;i++){
            System.out.println(" * " + ids[i] + "=" + string2TimezoneDefault(nowDateTime,ids[i]));
        }
        //显示程序运行所在地的时区
        System.out.println("TimeZone.getDefault().getID()=" +TimeZone.getDefault().getID());
    }

    /**
     * 将日期时间字符串根据转换为指定时区的日期时间.
     *
     * @param srcFormater
     *            待转化的日期时间的格式.
     * @param srcDateTime
     *            待转化的日期时间.
     * @param dstFormater
     *            目标的日期时间的格式.
     * @param dstTimeZoneId
     *            目标的时区编号.
     *
     * @return 转化后的日期时间.
     */
    public static String string2Timezone(String srcFormater,
            String srcDateTime, String dstFormater, String dstTimeZoneId) {
        if (srcFormater == null || "".equals(srcFormater))
            return null;
        if (srcDateTime == null || "".equals(srcDateTime))
            return null;
        if (dstFormater == null || "".equals(dstFormater))
            return null;
        if (dstTimeZoneId == null || "".equals(dstTimeZoneId))
            return null;
        SimpleDateFormat sdf = new SimpleDateFormat(srcFormater);
        try {
            int diffTime = getDiffTimeZoneRawOffset(dstTimeZoneId);
            Date d = sdf.parse(srcDateTime);
            long nowTime = d.getTime();
            long newNowTime = nowTime - diffTime;
            d = new Date(newNowTime);
            return date2String(dstFormater, d);
        } catch (ParseException e) {
            Log.output(e.toString(), Log.STD_ERR);
            return null;
        } finally {
            sdf = null;
        }
    }

    /**
     * 获取系统当前默认时区与UTC的时间差.(单位:毫秒)
     *
     * @return 系统当前默认时区与UTC的时间差.(单位:毫秒)
     */
    private static int getDefaultTimeZoneRawOffset() {
        return TimeZone.getDefault().getRawOffset();
    }

    /**
     * 获取指定时区与UTC的时间差.(单位:毫秒)
     *
     * @param timeZoneId
     *            时区Id
     * @return 指定时区与UTC的时间差.(单位:毫秒)
     */
    private static int getTimeZoneRawOffset(String timeZoneId) {
        return TimeZone.getTimeZone(timeZoneId).getRawOffset();
    }

    /**
     * 获取系统当前默认时区与指定时区的时间差.(单位:毫秒)
     *
     * @param timeZoneId
     *            时区Id
     * @return 系统当前默认时区与指定时区的时间差.(单位:毫秒)
     */
    private static int getDiffTimeZoneRawOffset(String timeZoneId) {
        return TimeZone.getDefault().getRawOffset()
                - TimeZone.getTimeZone(timeZoneId).getRawOffset();
    }

    /**
     * 将日期时间字符串根据转换为指定时区的日期时间.
     *
     * @param srcDateTime
     *            待转化的日期时间.
     * @param dstTimeZoneId
     *            目标的时区编号.
     *
     * @return 转化后的日期时间.
     * @see #string2Timezone(String, String, String, String)
     */
    public static String string2TimezoneDefault(String srcDateTime,
            String dstTimeZoneId) {
        return string2Timezone("yyyy-MM-dd HH:mm:ss", srcDateTime,
                "yyyy-MM-dd HH:mm:ss", dstTimeZoneId);
    }

}

本文转自:http://stephen830.iteye.com/blog/260343

时间: 2024-12-23 13:43:03

java对世界各个时区(TimeZone)的通用转换处理方法的相关文章

Java -- JDBC_利用反射及 JDBC 元数据编写通用的查询方法

先利用 SQL 进行查询,得到结果集: 利用反射创建实体类的对象:创建对象: 获取结果集的列的别名: 再获取结果集的每一列的值, 结合 3 得到一个 Map,键:列的别名,值:列的值: 再利用反射为 2 的对应的属性赋值:属性即为 Map 的键,值即为 Map 的值. 使用 JDBC 驱动程序处理元数据 Java 通过JDBC获得连接以后,得到一个Connection 对象,可以从这个对象获得有关数据库管理系统的各种信息,包括数据库中的各个表,表中的各个列,数据类型,触发器,存储过程等各方面的信

Java连接MySQL数据库增删改查通用方法

Java连接MySQL数据库增删改查通用方法 运行环境:eclipse+MySQL 以前我们Java连接MySQL数据库都是一个数据库写一个类,类下面写好多方法,要是多个数据库,就要写多个类多个方法,导致代码编写太过于繁琐,所以为了改变这样的繁琐,我将连接数据库的方法进行了一系列的封装,使用户传入一个对象值Object就可以得到想要的. 我在之前写过一篇普通的Java连接MySQL数据库,大家可以看看,以便对比参考之后就知道差距了  数据库--MySQL-->Java篇 接下来我给大家讲讲如何将

新霸哥带你进入java的世界

新霸哥从近期大家的留言中注意到了大家对基础知识比较重视,很多的朋友希望多讲一些入门的知识,为了满足广大开发爱好者的需求,新霸哥决定从最基础的做起,一点一点的帮助大家一起走进云计算的世界.下面新霸哥首先带领大家入门,今天入门的第一站就是进入java的世界. 喜欢编程的朋友,可能会知道java一种以来很受开发者热爱,因为Java可运行于多个平台,如Windows, Mac OS,及其他多种UNIX版本的系统.java有跨平台的特性. Java之父 热爱java的朋友对java之父应该比较熟悉了吧,J

Docker时区timezone问题

原文:Docker时区timezone问题 文章目录 Linux时间类型 docker时间.时区问题 docker-compose启动时的设置: dockerfile进行镜像设置生成 容器启动时直接设置 Linux时间类型 在Unix类的机器下的/usr/share/zoneinfo/文件内为所有代码调用的ZONEINFO的数据位置,想查看设置哪个时区时,直接去里边看名字即可. docker时间.时区问题 docker容器内默认为utc时间 docker-compose启动时的设置: 设置容器内

Android应用程序通用自动脱壳方法研究

Author: @爱博才会赢 本文为乌云峰会上<Android应用程序通用自动脱壳方法研究>的扩展延伸版. 0x00 背景及意义 Android应用程序相比传统PC应用程序更容易被逆向,因为被逆向后能够完整的还原出Java代码或者smali中间语言,两者都具有很丰富的高层语义信息,理解起来更为容易,让程序逻辑轻易暴露给技术能力甚至并不需要很高门槛的攻击者面前.因此Android应用程序加固保护服务随之应运而生.从一开始只有甲方公司提供服务到现在大型互联网公司都有自己的加固保护服务,同时与金钱相

深入剖析Java编程中的中文问题及建议最优解决方法

摘录自:http://fafeng.blogbus.com/logs/3062998.html http://www.blogbus.com/fafeng-logs/3063006.html 深入剖析Java编程中的中文问题及建议最优解决方法 说明:本文为作者原创,作者联系地址为:[email protected].由于Java编程中的中文问题是一个老生常谈的问题,在阅读了许多关于Java中文问题解决方法之后,结合作者的编程实践,我发现过去谈的许多方法都不能清晰地说明问题及解决问题,尤其是跨平台

[转载]Android应用程序通用自动脱壳方法研究

本文转载自: http://drops.wooyun.org/tips/9214 Author: @爱博才会赢 本文为乌云峰会上<Android应用程序通用自动脱壳方法研究>的扩展延伸版. 0x00 背景及意义 Android应用程序相比传统PC应用程序更容易被逆向,因为被逆向后能够完整的还原出Java代码或者smali中间语言,两者都具有很丰富的高层语义信息,理解起来更为容易,让程序逻辑轻易暴露给技术能力甚至并不需要很高门槛的攻击者面前.因此Android应用程序加固保护服务随之应运而生.从

JDBC课程1-实现Driver接口连接mysql数据库、通用的数据库连接方法(使用文件jdbc.properties)

package day_18; import jdk.internal.util.xml.impl.Input; import org.junit.Test; import java.io.InputStream; import java.net.URL; import java.sql.*; import java.util.Properties; import java.util.logging.Logger; /** * Driver 只是一个接口,数据库厂商必须提供的接口,能从中获取数据

javaWeb_JDBC_利用反射以及JDBC元数据编写通用的查询方法

JDBC利用反射以及元数据编写通用的查询方法[*****] 1.如何获取元数据 Java 通过JDBC获得连接以后,得到一个Connection 对象,可以从这个对象获得有关数据库管理系统的各种信息,包括数据库中的各个表, 表中的各个列,数据类型,触发器,存储过程等各方面的信息.根据这些信息,JDBC可以访问一个实现事先并不了解的数据库. 获取这些信息的方法都是在DatabaseMetaData类的对象上实现的,而DataBaseMetaData对象是在Connection对象上获得的. 2.元