精华内容
下载资源
问答
  • TimeZone.getDefault()规范很清楚它如何获得时区:Gets the default TimeZone of the Java virtual machine. If the cacheddefault TimeZone is available, its clone is returned. Otherwise, themethod takes the ...

    TimeZone.getDefault()规范很清楚它如何获得时区:

    Gets the default TimeZone of the Java virtual machine. If the cached

    default TimeZone is available, its clone is returned. Otherwise, the

    method takes the following steps to determine the default time zone.

    Use the user.timezone property value as the default time zone ID if it’s available.

    Detect the platform time zone ID. The source of the platform time zone and ID mapping may vary with implementation.

    Use GMT as the last resort if the given or detected time zone ID is unknown.

    The default TimeZone created from the ID is cached, and its clone is

    returned. The user.timezone property value is set to the ID upon

    return.

    文档说明该区域被缓存;此方法受到user.timezone系统属性的影响,反之亦然.

    If zone is null, the cached default TimeZone is cleared.

    也就是说,为了重新读取系统时区,你必须

    >通过调用TimeZone.setDefault(null)清除TimeZone缓存;

    >通过调用System.clearProperty(“user.timezone”)清除user.timezone系统属性;

    尝试以下测试:

    while (true) {

    TimeZone.setDefault(null);

    System.clearProperty("user.timezone");

    System.out.println("Offset = " + TimeZone.getDefault().getRawOffset() / 3600);

    System.out.println("Zone ID = " + System.getProperty("user.timezone"));

    Thread.sleep(1000);

    }

    展开全文
  • 本文中,我们将展示如何在不同时区之间转换时间,我们分别使用Date、Calendar、Joda Time。本例从新加坡时区(GMT+8:00) Asia/Singapore - Singapore TimeDate : 22-1-2015 10:15:55 AM转换到美国纽约时区(GMT-5:00) ...

    本文中,我们将展示如何在不同时区之间转换时间,我们分别使用Date、Calendar、Joda Time。

    本例从新加坡时区

    (GMT+8:00) Asia/Singapore - Singapore Time

    Date : 22-1-2015 10:15:55 AM

    转换到美国纽约时区

    (GMT-5:00) America/NewYork - Eastern Standard Time

    Date : 21-1-2015 09:15:55 PM

    注意,在JDK1.7版本之前,java.util.Date没有时区的概念,Date对象只显示系统的时间和系统的默认时区。

    1.使用Date

    使用DateFormat格式化时间(需要设置时区)

    SimpleDateFormat sdfAmerica = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");

    sdfAmerica.setTimeZone(TimeZone.getTimeZone("America/NewYork"));

    String sDateInAmerica = sdfAmerica.format(date);

    完整的代码如下:

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

    import java.util.TimeZone;

    public class TimeZoneTest {

    public static void main(String[] argv) throws

    ParseException {

    SimpleDateFormat formatter = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");

    String dateInString = "22-01-2015 10:15:55 AM";

    Date date = formatter.parse(dateInString);

    TimeZone tz = TimeZone.getDefault();

    // From TimeZone Asia/Singapore

    System.out.println("TimeZone : " + tz.getID() + " - " + tz.getDisplayName());

    System.out.println("TimeZone : " + tz);

    System.out.println("Date : " + formatter.format(date));

    // To TimeZone America/NewYork

    SimpleDateFormat sdfAmerica = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");

    TimeZone tzInAmerica = TimeZone.getTimeZone("America/NewYork");

    sdfAmerica.setTimeZone(tzInAmerica);

    String sDateInAmerica = sdfAmerica.format(date); // Convert to String first

    Date dateInAmerica = formatter.parse(sDateInAmerica);

    System.out.println("\nTimeZone : " + tzInAmerica.getID() +

    " - " + tzInAmerica.getDisplayName());

    System.out.println("TimeZone : " + tzInAmerica);

    System.out.println("Date (String) : " + sDateInAmerica);

    System.out.println("Date (Object) : " + formatter.format(dateInAmerica));

    }

    }

    输出结果为:

    TimeZone : Asia/Singapore - Singapore Time

    TimeZone : sun.util.calendar.ZoneInfo[id="Asia/Singapore",offset=28800000,dstSavings=0,useDaylight=false,transitions=9,lastRule=null]

    Date : 22-1-2015 10:15:55 AM

    TimeZone : America/NewYork - Eastern Standard Time

    TimeZone : sun.util.calendar.ZoneInfo[id="America/NewYork",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/NewYork,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]

    Date (String) : 21-1-2015 09:15:55 PM

    Date (Object) : 21-1-2015 09:15:55 PM

    2.使用Calendar

    Calendar设置时区

    Calendar calendar = new GregorianCalendar();

    calendar.setTime(date);

    calendar.setTimeZone(tzInAmerica);

    我们经常犯的错误是这样获取java.util.Date.

    Date dateInAmerican = calendar.getTime();

    在以上得例子,不管Calendar的时区如何设置,Date总是显示的时本地的系统时间22-1-2015 10:15:55 AM.

    正确得方式是需要使用DateFormat来格式化。

    SimpleDateFormat sdfAmerica = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");

    TimeZone tzInAmerica = TimeZone.getTimeZone("America/NewYork");

    sdfAmerica.format(calendar.getTime())

    或者是使用一种calendar.get()的方法获取。

    int year = calendar.get(Calendar.YEAR);

    int month = calendar.get(Calendar.MONTH); // Jan = 0, dec = 11

    int dayOfMonth = calendar.get(Calendar.DAYOFMONTH);

    int hour = calendar.get(Calendar.HOUR); // 12 hour clock

    int hourOfDay = calendar.get(Calendar.HOUROFDAY); // 24 hour clock

    int minute = calendar.get(Calendar.MINUTE);

    int second = calendar.get(Calendar.SECOND);

    int ampm = calendar.get(Calendar.AMPM); //0 = AM , 1 = PM

    3.使用Joda Time

    JodaTime设置时区

    DateTime dt = new DateTime(date);

    DateTimeZone dtZone = DateTimeZone.forID("America/NewYork");

    DateTime dtus = dt.withZone(dtZone);

    也是容易饭的错误是,直接转换为java.util.Date,时区的信息将丢失。

    //Output : 22-1-2015 10:15:55 AM

    Date dateInAmerica = dtus.toDate();

    正确得方式是转换为Joda得LocalDateTime

    //Output : 21-1-2015 09:15:55 PM

    Date dateInAmerica = dtus.toLocalDateTime().toDate();

    参考:

    Date and Time Manipulation in Java Using JodaTime

    SimpledateFormat JavaDoc

    World Time Server

    展开全文
  • 时区机制导致的程序中的问题java时区设置java程序的Date日期序列化方法JVM时区参数tomcat与时区设置mysql与时区设置临时修改MySql时区MySql数据库时区连接参数Linux查看系统时区后端到前端的时间序列化因为时区...

    在这里插入图片描述

    时区(Time Zone)

    地球是自西向东自转,东边比西边先看到太阳,东边的时间也比西边的早。东边时刻与西边时刻的差值不仅要以时计,而且还要以分和秒来计算,这给人们带来不便。
    为了克服时间上的混乱,1884年在华盛顿召开的一次国际经度会议(又称国际子午线会议)上,规定将全球划分为24个时区(东、西各12个时区)。规定英国(格林尼治天文台旧址)为中时区(零时区)、东1—12区,西1—12区。每个时区横跨经度15度,时间正好是1小时。最后的东、西第12区各跨经度7.5度,以东、西经180度为界。每个时区的中央经线上的时间就是这个时区内统一采用的时间,称为区时,相邻两个时区的时间相差1小时。
    例如,中国东8区的时间总比泰国东7区的时间早1小时,而比日本东9区的时间晚1小时。因此,出国旅行的人,必须随时调整自己的手表,才能和当地时间相一致。凡向西走,每过一个时区,就要把表拨慢1小时(比如2点拨到1点);凡向东走,每过一个时区,就要把表拨快1小时(比如1点拨到2点)。并且规定英国(格林尼治天文台旧址)为本初子午线,即零度经线。

    在这里插入图片描述

    GMT(格林尼治标准时间/世界时)

    以本初子午线的平子夜起算的平太阳时

    英文:UT(Universal Time)

    GMT:Greenwich Mean Time

    格林尼治标准时间。这是以英国格林尼治天文台观测结果得出的时间,这是英国格林尼治当地时间,这个地方的当地时间过去被当成世界标准的时间。

    也就是说它是世界计算时间和经度的起点。


    1960年以前曾作为基本时间计量系统被广泛应用。由于地球自转速度变化的影响,它不是一种均匀的时间系统。后来世界时被原子时所取代,但在日常生活、天文导航、大地测量和宇宙飞行等方面仍属必需;同时,世界时反映地球自转速率的变化,是地球自转参数之一,仍为天文学和地球物理学的基本资料。

    UTC(协调世界时)

    协调世界时是以原子时秒长为基础,在时刻上尽量接近于世界时的一种时间计量系统。

    这套时间系统被应用于许多互联网和万维网的标准中,例如,网络时间协议就是协调世界时在互联网中使用的一种方式。
    在军事中,协调世界时区会使用“Z”来表示。又由于Z在无线电联络中使用“Zulu”作代称,协调世界时也会被称为"Zulu time"。

    中国大陆、中国香港、中国澳门、中国台湾、蒙古国、新加坡、马来西亚、菲律宾、西澳大利亚州的时间与UTC的时差均为+8,也就是UTC+8。

    如今的标准时间——协调世界时(UTC)——由原子钟提供。 自1924年2月5日开始,格林尼治天文台每隔一小时会向全世界发放调时信息。而UTC是基于标准的GMT提供的准确时间。

    国际原子时的准确度为每日数纳秒,而世界时的准确度为每日数毫秒。许多应用部门要求时间系统接近世界时UT,对于这种情况,一种称为协调世界时的折中时标于1972年面世。为确保协调世界时与世界时相差不会超过0.9秒,在有需要的情况下会在协调世界时内加上正或负闰秒。因此协调世界时与国际原子时之间会出现若干整数秒的差别,两者之差逐年积累,便采用跳秒(闰秒)的方法使协调时与世界时的时刻相接近,其差不超过1s。它既保持时间尺度的均匀性,又能近似地反映地球自转的变化。

    GMT与UTC

    为了方便,在不需要精确到秒的情况下,通常将GMT 和UTC 视作等同。但UTC
    更加科学更加精确,它是以原子时为基础,在时刻上尽量接近世界时的一种时间计量系统。它的出现是现代社会对于精确计时的需要。

    UT:Universal Time 世界时。根据原子钟计算出来的时间。

    UTC:Coordinated Universal Time 协调世界时。因为地球自转越来越慢,每年都会比前一年多出零点几秒,每隔几年协调世界时组织都会给世界时+1秒,让基于原子钟的世界时和基于天文学(人类感知)的格林尼治标准时间相差不至于太大。并将得到的时间称为UTC,这是现在使用的世界标准时间。

    协调世界时不与任何地区位置相关,也不代表此刻某地的时间,所以在说明某地时间时要加上时区也就是说GMT并不等于UTC,而是等于UTC+0,只是格林尼治刚好在0时区上。

    GMT = UTC+0

    关于北京时间

    地区:中国 北京 Beijing

    时区:UTC/GMT +8.00 (东八区)

    北京时间又称中国标准时间。

    比格林威治时间(Greenwich Mean Time简称GMT)早8小时。

    北京时间是由位于陕西西安的中国国家授时中心计算得出。

    在这里插入图片描述

    时区时差时间换算/世界时区划分时差查询

    CST(时区缩写)

    CST可以为如下4个不同的时区的缩写:

    • 美国中部时间:Central Standard Time (USA) UT-6:00
    • 澳大利亚中部时间:Central Standard Time (Australia) UT+9:30
    • 中国标准时间:China Standard Time UT+8:00
    • 古巴标准时间:Cuba Standard Time UT-4:00

    DST(夏时制)

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

    unix时间戳(Unix timestamp)

    unix时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。

    Unix时间戳(英文为Unix epoch, Unix time, POSIX time 或 Unix timestamp)

    是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。 UNIX时间戳的0按照ISO 8601规范为 :1970-01-01T00:00:00Z.

    一个小时表示为UNIX时间戳格式为:3600秒;一天表示为UNIX时间戳为86400秒,闰秒不计算。

    在大多数的UNIX系统中UNIX时间戳存储为32位,这样会引发2038年问题或Y2038。

    中文名unix时间戳外文名Unix epoch, Unix time, POSIX time又 称 Unix timestamp时
    间1970年1月1日系 统UNIX内核系统

    在这里插入图片描述

    时间戳与北京时间

    在这里插入图片描述

    时区与时间戳单位计算公式(!!!)

    在这里插入图片描述

    时区机制导致的程序中的问题

    对于操作DB在两个不同时区的程序去存取同一个Datetime字段的话会出现大问题:
    在同一时刻存入的“当前时间”会不一样。

    另外一个情况是:在中国存到数据表里的 2020-12-12 13:39:00 在美国的服务器取出来为2020-12-12 13:39:00 看起来没什么问题;可是实际上美国中部现在时间为 2020-12-11 23:39:00 整整差了14个小时。

    如果是一个国际秒杀活动的话在中国你可能已经拿到买的东西了而美国那边还在显示活动开始倒计时!

    分布在不同时区的两个程序在传递Date类型数据时也可能会有意外的反应,因为同一个时间在传递另一个时区的Date对象中时会根据接收方的时区做相应的转换。


    当前mysql默认的连接会话时区为美国中部
    UTC-06:00

    在这里插入图片描述

    同时使用
    一个JDBC连接加了东八区时区参数的客户端和
    一个没有加JDBC时区参数的客户端查看同一条记录

    其中一个客户端连接加了为上海(东八区)的连接参数
    在这里插入图片描述

    另一个客户端使用默认时区

    得到的结果为:

    在这里插入图片描述

    可以看出来create_time时差了8个小时

    这就是时区不同所造成的影响

    但这并不是错误,而是数据在时区机制的序列化的正常反应。

    如果再有一个客户端设置为美国中部
    在这里插入图片描述
    在这里插入图片描述
    那就会相差13个小时

    java与时区设置

    默认取系统的时区
    我这里为东八区 CST 也就是 GMT+08:00

    Date now = new Date();
    
    System.out.println(now.toString())
    Sat Dec 12 16:08:48 CST 2020
    
    System.out.println(now.toGMTString())
    12 Dec 2020 08:08:48 GMT
    

    修改java程序全局默认的时区

    这个会影响到Date类型序列化的日期偏移

    TimeZone.setDefault(TimeZone.getTimeZone("CST"));
    
    # 美国中部时区
    TimeZone.setDefault(TimeZone.getTimeZone("GMT-06:00"));
    

    java程序的Date日期序列化方法

    Date类型的toString()不只是把自身属性打印出来这么简单

        public String toString() {
            // "EEE MMM dd HH:mm:ss zzz yyyy";
            BaseCalendar.Date date = normalize();
            StringBuilder sb = new StringBuilder(28);
            int index = date.getDayOfWeek();
            if (index == BaseCalendar.SUNDAY) {
                index = 8;
            }
            convertToAbbr(sb, wtb[index]).append(' ');                        // EEE
            convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
            CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
    
            CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
            CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
            CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
            TimeZone zi = date.getZone();
            if (zi != null) {
                sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
            } else {
                sb.append("GMT");
            }
            sb.append(' ').append(date.getYear());  // yyyy
            return sb.toString();
        }
    
        @Deprecated
        public String toGMTString() {
            // d MMM yyyy HH:mm:ss 'GMT'
            long t = getTime();
            BaseCalendar cal = getCalendarSystem(t);
            BaseCalendar.Date date =
                (BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
            StringBuilder sb = new StringBuilder(32);
            CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
            convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
            sb.append(date.getYear()).append(' ');                            // yyyy
            CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');      // HH
            CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':');    // mm
            CalendarUtils.sprintf0d(sb, date.getSeconds(), 2);                // ss
            sb.append(" GMT");                                                // ' GMT'
            return sb.toString();
        }
    

    我们阅读源代码得知Date类型的序列话是经过时区计算之后的结果。

    JVM时区参数

    -Duser.timezone=CST
    

    tomcat与时区设置

    tomcat可以将时区配置写到setenv.sh或者catalina.sh的JAVA_OPTS

    -Duser.timezone=CST
    

    mysql与时区设置

    mysql的datetime字段并不存储时区信息

    我们的程序在mysql里存取Datetime的时候时间值取决于连接指定的时区

    查看数据库会话时区命令

    show VARIABLES like '%time_zone%'
    

    在这里插入图片描述
    在这里插入图片描述

    全局参数system_time_zone

    系统时区,在MySQL启动时会检查当前系统的时区并根据系统时区设置全局参数system_time_zone的值。

    全局参数time_zone

    用来设置每个连接会话的时区,默认为system时,使用全局参数system_time_zone的值。

    上面两个配置并不是影响MySql自身的时区,它们指定的是程序连接到mysql的时候用的默认时区。

    临时修改MySql时区

    改为东八区

    set time_zone=+8:00;
    set global time_zone =+8:00;
    flush privileges;
    

    MySql数据库时区连接参数

    mysql驱动5.1版本要同时配置下面3个配置项连接服务器时区才会生效

    useLegacyDatetimeCode=true
    useTimezone=true
    serverTimezone=Asia/Shanghai
    

    修改jdbc连接设置,直接把连接的时区固定死,绕开mysql本身的时区。

    就是在jdbc连接配置上添加以下3个配置即可:

    useLegacyDatetimeCode=true&useTimezone=true&serverTimezone=GMT%2B8

    分别为启用时区设置和设置连接服务的时区。

    此时,jdbc操作都会使用自定义时区去进行时间处理。

    8.0驱动没有useLegacyDatetimeCode=true,useTimezone=true 这两个配置项了。

    Linux查看系统时区

    # date -R
    Sat, 12 Dec 2020 14:15:06 +0800
    # date
    Sat Dec 12 14:15:20 CST 2020
    

    表明服务器的时区是东八区同时认为CST中国标准时间

    后端到前端的时间序列化因为时区导致的时间偏移

    springboot 默认的 jackson 序列化到 前端

    spring:
      jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8
    

    (全局) 固定将日期时间按照东八区时区序列化

    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    @JsonProperty("start_time")
    private Date startTime;
    

    设置单个字段的时区序列化

    http调用传递Date类型的时区问题

    在java程序调用另一个java程序的接口时(或者叫后端接口)

    此接口接收的参数有Date类型再序列化过程中会产生时区问题:即参数出现时差。

    我们在条件不允许改变JVM的时区设置的时候也可以选择改变接口入参Date类型形参的序列化方案改纠正时区导致的时差问题。

    接收入参的字段

    	// spring mvc 接口注解:指定入参的反序列化方式
    	@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    	// 字段的序列化格式
    	@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
    	private Date beginTime;
    

    传参使用SimpleDataFormat将Date字段序列化为指定格式的字符串。

    结尾

    建议在数据库连接参数上都加上时区参数
    建议在后端到前端的接口序列化指定时区

    不建议使用CST来做时区,容易造成系统混淆

    展开全文
  • 所有编程语言都提供了方法来生成这个时间戳,Java和JavaScript输出以毫秒计算的Long型整数,Python等输出标准的Unix时间戳,以秒计算的Float型浮点数,这两者转换只存在1000倍的关系。 实际上,操作系统内部的...

    将时间转换为时间戳:

    /* 
         * 将时间转换为时间戳
         */    
        public static String dateToStamp(String s) throws ParseException{
            String res;
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = simpleDateFormat.parse(s);
            long ts = date.getTime();
            res = String.valueOf(ts);
            return res;
        }

    日期和时间在程序中应用广泛,每种程序开发语言都自带处理日期和时间的相关函数,很多开发者把日期和时间存入数据库中,但是,一旦涉及到跨时区的日期和时间的处理时,大多数开发者根本就不明白如何正确地处理日期和时间。

    首先,我们来看大部分的程序都是这么创建当前时间并存入数据库的:

    Date date = new Date();
    store2db(date);
    

    这么做的问题在于,数据库的DateTime类型没有时区(time zone)信息,因此,存入的是本地时间,并且丢掉了时区信息。如果你把数据库服务器的时区改了,或者把应用服务器的时区改了,读出来的日期和时间就是错误的。如果以Timestamp类型存储,各数据库的实现也不相同,有的进行了内部时区自动转换,而且,存储的时间不超过2037年。

    如果应用服务器的时区和数据库服务器的时区不一致,你无法确定数据库驱动程序会不会自动帮你转换。

    大多数开发者遇到这个问题不是去探索正确的解决方法,而是自作聪明地在存入数据库之前先来个“调整”,比如把当前时间减掉8小时,在显示的时候遇到不正确的时间时,又来个“调整”,以“负负得正”的方式来掩盖错误。在遇到夏令时的时区时,还需要写更复杂的代码来调整小时。

    正确的做法是先理解时间和时区的概念。

    时区的概念

    之所以有时区的概念是因为住在地球上不同地方的人看到太阳升起的时间是不一样的。我们假设北京人民在早上8:00看到了太阳刚刚升起,而此刻欧洲人民还在夜里,他们还需要再过7个小时才能看到太阳升起,所以,此刻欧洲人民的手表上显示的是凌晨1:00。如果你强迫他们用北京时间那他们每天看到日出的时间就是下午3点。

    也就是说,东8区的北京人民的手表显示的8:00和东1区欧洲人民手表显示的1:00是相同的时刻:

    "2014-10-14 08:00 +8:00" = "2014-10-14 01:00 +1:00"
    

    这就是本地时间的概念。

    但是,在计算机中,如果用本地时间来存储日期和时间,在遇到时区转换的问题上,即便你非常清楚地知道如何转换,也非常麻烦,尤其是矫情的美国人还在采用夏令时。

    所以我们需要引入“绝对时间”的概念。绝对时间不需要年月日,而是以秒来计时。当前时间是指从一个基准时间(1970-1-1 00:00:00 +0:00),到现在的秒数,用一个整数表示。

    当我们用绝对时间表示日期和时间时,无论服务器在哪个时区,任意时刻,他们生成的时间值都是相等的。所有编程语言都提供了方法来生成这个时间戳,Java和JavaScript输出以毫秒计算的Long型整数,Python等输出标准的Unix时间戳,以秒计算的Float型浮点数,这两者转换只存在1000倍的关系。

    实际上,操作系统内部的计时器也是这个标准的时间戳,只有在显示给用户的时候,才转换为字符串格式的本地时间。

    正确的存储方式

    基于“数据的存储和显示相分离”的设计原则,我们只要把表示绝对时间的时间戳(无论是Long型还是Float)存入数据库,在显示的时候根据用户设置的时区格式化为正确的字符串。

    数据的存储和显示相分离是非常基本的设计原则,却常常被大多数开发人员忽略。举个例子,在Excel中编写一个表格,表格的数据可视为数据的存储格式,你可以把表格的数据以柱状图或饼图表示出来,这些不同的图表是数据的不同显示格式,存储数据的时候,我们应该存储表格数据,绝不应该存储柱状图等图片信息。

    HTML和CSS也是数据的存储和显示相分离的设计思想。

    所以,数据库存储时间和日期时,只需要把Long或者Float表示的时间戳存到BIGINTREAL类型的列中,完全不用管数据库自己提供的DATETIMETIMESTAMP,也不用担心应用服务器和数据库服务器的时区设置问题,遇到Oracle数据库你不必去理会with timezonewith local timezone到底有啥区别。

    读取时间时,读到的是一个Long或Float,只需要按照用户的时区格式化为字符串就能正确地显示出来:

    // Java:
    long t = System.currentTimeMillis();
    System.out.println("long = " + t);
     
    // current time zone:
    SimpleDateFormat sdf_default = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    System.out.println(sdf_default.format(t));
     
    // +8:00 time zone:
    SimpleDateFormat sdf_8 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    sdf_8.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
    System.out.println("GMT+8:00 = " + sdf_8.format(t));
     
    // +7:00 time zone:
    SimpleDateFormat sdf_7 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    sdf_7.setTimeZone(TimeZone.getTimeZone("GMT+7:00"));
    System.out.println("GMT+7:00 = " + sdf_7.format(t));
     
    // -9:00 time zone:
    SimpleDateFormat sdf_la = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    sdf_la.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
    System.out.println("America/Los_Angeles = " + sdf_la.format(t));
    

    输出:

    long = 1413230086802
    2014-10-14 03:54
    GMT+8:00 = 2014-10-14 03:54
    GMT+7:00 = 2014-10-14 02:54
    America/Los_Angeles = 2014-10-13 12:54
    

    基于绝对时间戳的时间存储,从根本上就没有时区的问题。时区只是一个显示问题。额外获得的好处还包括:

    • 两个时间的比较就是数值的比较,根本不涉及时区问题,极其简单;

    • 时间的筛选也是两个数值之间筛选,写出SQL就是between(?, ?)

    • 显示时间时,把Long或Float传到页面,无论用服务端脚本还是用JavaScript都能简单而正确地显示时间。

    你唯一需要编写的两个辅助函数就是String->LongLong->StringString->Long的作用是把用户输入的时间字符串按照用户指定时区转换成Long存进数据库。

    唯一的缺点是数据库查询你看到的不是时间字符串,而是类似1413266801750之类的数字。

    Date对象会和本地时区保持一致,当得到固定时区的时间之后:string类型的字符串,转换成date之后就会变为系统的时区。

    展开全文
  • 时间戳 时区 java mysql

    2021-01-19 00:06:01
    首先得确认这个时间是哪个时区的,然后转换成utc时区的时间。再减去1970,得到的秒数,就是时间戳。时间戳是个一定的值,他与时区没关。当想把时间戳还原成时间,必须指定时区,才能确认什么时间。总结:时间与时区...
  • 了好多中文资料都没彻底解决,这台服务器曾经是“Mon Mar 17 15:18:24 EST 2008 ”,西方时间,后来改为CST 上海时间,在程序中输出的时间就和系统时间相差了13个小时,java虚拟机读取的时区不是系统设置的时区吗...
  • java&postgresql时区总结

    2021-02-28 07:37:16
    2、DateTimeZone对象给我们的是原始的偏移量,也就是与GMT相差的微秒数,Java的Date对象里面存储着当前时刻到1970年1月1日0:00所经过的毫秒数,它与时区和地域没有关系(其实可以认为是GMT时间)计算机内...
  • 前言ZoneOffset,LocalDateTime,LocalTime, YearMonth, Year, MonthDay,它们代表与上下文相...这些类主要用于不需要在上下文中明确指定时区的情况,他们是线程安全的类 信息类别 输出案例ZoneOffset 时区偏移量 +01:...
  • 根据经纬度计算时区

    千次阅读 2019-01-16 20:09:14
    给定经纬度,返回时区编号: /** * 根据经度获取时区 * @param currentLon * @return */ public static int caculateTimeZone(double currentLon) { int timeZone ; int shangValue = (int)(curr...
  • 日期和时间在程序中应用广泛,每种程序开发语言都自带处理日期和时间的相关函数,很多开发者把日期和时间存入数据库中,但是,一旦涉及到跨时区的日期和时间的处理时,大多数开发者根本就不明白如何正确地处理日期和...
  • 一、概述1、问题描述使用Java处理时间时,我们可能会经常发现时间不对,比如相差8个小时等等,其真实原因便是TimeZone。只有正确合理的运用TimeZone,才能保证系统时间无论何时都是准确的。由于我在外企工作,服务器...
  • java项目多时区问题解决方式

    千次阅读 2019-02-20 20:34:12
    前言:近期项目中由于以前的设计缺陷出现了多时区问题,一开始解决思路还错了导致折腾了好一会,特记录下来。主要现象: 部署项目的服务器时区为UTC(协调世界时),客户端是CST(可理解为中国的标准时间),两者...
  • Java时区转换及时间格式

    千次阅读 2021-01-13 16:17:30
    本文介绍Java API 中 Date, Calendar, TimeZone和DateFormat的使用,以及不同时区时间相互转化的方法和原理。问题描述:向处于不同时区的服务器发请求时需要考虑时区转换的问题。譬如,服务器位于东八区(北京时间,...
  • Java服务端时区的几点思考

    千次阅读 2017-06-15 21:29:33
    时区概念时区(Time Zone)是地球上的区域使用同一个时间定义。1884年在华盛顿召开国际经度会议时,为了克服时间上的混乱,规定将全球划分为24个时区。 GMT,UTC,UNIX时间戳GMT,格林尼治时间。理论上来说,格林尼治...
  • 红鲱鱼由于处理两个独立的服务器(数据库服务器,Web应用服务器),每个服务器都有不同的时区设置,因此您应该更清楚地分离问题.事实上,MySQL服务器似乎只是一个红色的鲱鱼,分散注意力.您应该测试并报告实际时间,而不是...
  • 设置calendar时区

    2021-02-27 18:22:01
    iOS - Swift NSTimeZone时区前言public class NSTimeZone : NSObject, NSCopying, NSSecureCodingNSTimeZone 表示时区信息。1、NSTimeZone 时区的创建// 根据时区名称创建let zone1:NSTimeZon...文章QianChia2016-08...
  • Java 计算两个日期的差值

    千次阅读 2020-06-23 14:15:21
    在这篇快速的文章中,我们将探讨Java计算两个日期之间差值的一些方法。 解决方案 使用 java.util.Date 让我们首先使用Java SE API计算两个日期之间的天数: @Test public void test_TwoDatesDiffBeforeJava8...
  • 在我们的Web应用程序中,我们需要显示并输入不同国家/地区在不同时区的日期时间信息。目前,我们正在为每个国家/地区维护单独的Web服务器和单独的数据库(oracle 11g)。我们计划将所有数据库合并为一个数据库(Oracle ...
  • Oracle服务器数据库时区设置为GMT + 2 JVM时区设置为GMT + 2(即使对于我而言这无关紧要)。我有一个执行某些日期操作的存储过程。问题是,即使我未在代码/配置中明确设置会话时区,会话时区也不同于数据库时区(GMT)。...
  • 2、日期时间的时区问题处理,这两个问题要区分开,不要弄混了。 日期时间国际化化格式处理 对应的关键词:Locale 日期时间的国际化格式指的是在不同的国家和地区对日期时间的显示方式...
  • 我输入的日期时间是"20121225 10:00:00 Z",时区是"亚洲/加尔各答"我的服务器/DB(Oracle)运行在同一时区(IST)"亚洲/加尔各答"获取此特定时区中的日期对象String date ="20121225 10:00:00 Z";String timeZoneId ...
  • MongoDB将日期存储为UTC,这通常也是通常存储日期的最佳实践,因为它允许在不计算原始起点的情况下往返于各个时区进行转换。 因此,可以肯定的是,这里的实际日期确实是UTC,但是您传入的是从其他时区构造的值。...
  • java 时间格式转换带有时区+08:00

    千次阅读 2020-09-15 19:12:28
    最近在使用es发现通过时间范围进行查询数据,怎么都查询不出来,后来查阅了一些资料发现是传入es的时间参数需要添加时区,于是乎查阅了很多资料,把我整的很晕,下面的方法是我测试过没问题的代码。 ...
  • 4、使用Java访问Mysql数据库时出现时区异常的解决方案 原文链接: https://my.oschina.net/u/2608182/blog/1940809 问题来源:将Mysql5.6版本升级到8.0.12版本后,Java在访问Mysql数据库时出现如下异常: ...
  • linux下为java设置正确的时区

    万次阅读 2016-08-18 20:13:53
     后来想到因为系统中使用的时间类型是timestamp类型,所以会有时区的问题,当时区设置有问题的时候就会发生查看当前时间设置正确,但是时间怎么也对不上的情况;  于是到网上查询如何设置时区,走了一些弯路,在此...
  • 0、引言Druid中时区的问题一直困扰着我们,所以我专门去研究了一下世界时区Java中的时区,对使用Druid很用帮助.1、UTC时间&GMT时间UTC时间是时间标准时间(Universal Time Coordinated),UTC是根据原子钟来计算...
  • java driver保存Date时会把他自动转换为标准时间GMT。如中国在GMT+8时区,保存2012-01-20 00:00:00到库中,查询后结果竟然是2012-01-19 16:00:00跟想要结果不一致。 可以在com.mongodb.util.JSON找到问题根源:if (o...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,766
精华内容 4,306
关键字:

java计算时区查

java 订阅