博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
时间戳 时区 java mysql
阅读量:5009 次
发布时间:2019-06-12

本文共 8907 字,大约阅读时间需要 29 分钟。

  • 当一个时间 比如2016年5月6日,生成时间戳。这个运算是与时区有关的。首先得确认这个时间是哪个时区的,然后转换成utc时区的时间。再减去1970,得到的秒数,就是时间戳。
  • 时间戳是个一定的值,他与时区没关。
  • 当想把时间戳还原成时间,必须指定时区,才能确认什么时间。
  • 总结:时间与时区有关。时间戳与时区无关,它是utc,也就是gmt时区的时间与1970年的差。在时间轴的某一点时刻,不管位于哪个时区(如北京 +8小时,或者格林威治 +0小时),它转换成的时间戳是相等的。
  • 首先澄清一个概念:

 

所有的linux系统文件系统底层存储的都是UTC时间,也就是说都是自1970年0时0分0秒以来的UTC标准时间的秒数。

无论系统配置是什么时区,显示如何不同,底层存储都是一致的。

 

  • 如何得到UTC系统时间?

 

在shell环境下 >date '+%s' 即可得到

在mysql环境下>select unix_timestamp();即可得到

 

  • timestamp是什么?
timestamp是mysql数据库中的一种字段类型,
不用说太多,
  • 内部存储是4个字节
  • 精度达到微妙
  • 回转换成UTC时间存储
  • 读取的时候再根据时区转换回来
mysql> select now()+0;
+-----------------------+
| now()+0               |
+-----------------------+
| 20130722184134.000000 |
+-----------------------+
1 row in set (0.00 sec)
mysql> select now();  
+---------------------+
| now()               |
+---------------------+
| 2013-07-22 18:41:37 |
+---------------------+
1 row in set (0.00 sec)
可以看到,我们看到的timestamp实际是已经根据当前时区转换过格式的字符形式
 
  • 如何在mysql中根据timestamp得到UTC系统时间戳呢呢?
很简单,mysql> select unix_timestamp( 20130722183356.000000);
+----------------------------------------+
| unix_timestamp( 20130722183356.000000) |
+----------------------------------------+
|                             1374489236 |
+----------------------------------------+
             
  • 如何在mysql中根据UTC 系统时间戳得到当前时区的timestamp呢?
mysql> select from_unixtime(1374489236);
+---------------------------+
| from_unixtime(1374489236) |
+---------------------------+
| 2013-07-22 18:33:56       |
+---------------------------+
1 row in set (0.00 sec)
 
  •  如何在mysql中根据当前时区的时区得到其他时区的timestamp呢?
mysql> SELECT CONVERT_TZ('2013-07-22 18:41:37','+08:00','+00:00') as UTC;         
+---------------------+
| UTC                 |
+---------------------+
| 2013-07-22 10:41:37 |
+---------------------+
1 row in set (0.00 sec)

 

 

  • 一个罕见的问题

 

数据库使用Amazon RDS 是无法修改时区的,统一使用UTC时区

应用程序使用Amazon 服务器 是UTC -7 美西时间

数据库部分时间字段使用了current_timestamp,使用了UTC时区

部分字段使用了unix_time,由应用程序插入,理论上也是UTC时间

部分字段使用了unix_time并根据app服务器的时区转成了时间的string格式,导致出现UTC-7的时间

导致了同一IDC的数据有了两种时间

===========================================

结论:

我们不需要被timestamp和时区弄糊涂,其实很简单,timestamp存储的时间是带时区偏移的。

所有的数据库的时间应该统一操作,要么使用DB的current_timestamp,要么使用应用程序插入。

在有多IDC且不同时区的情况下,

如果需要标准UNIX时间戳:我建议只需要每次取出UTC的时间戳进行处理

如果需要标准的timestamp,我建议全部统一convert到一个时区去处理

 
0

 

(摘自http://www.cnblogs.com/flying5/archive/2011/12/05/2276578.html)

最近在编程中遇到了时间与时区相关的问题,整理在这里

  我的程序是一个在上运行的分布式程序,从中取数据,经过处理之后输出

一. 基本概念

  时区 :time zone 1884年国际经线会议规定,全球按经度分为24个时区,每区各占经度15°。

      以本初子午线为中央经线的时区为零时区,由零时区向东、西各分12区,东、西12区都是半时区,共同使用180°经线的地方时。

  CST :China Standard Time UTC+8:00 中国标准时间(北京时间),在东八区

  UTC :Universal Time Coordinated,世界协调时间,又称世界标准时间、世界统一时间。UTC 提供了一种与时区无关(或非特定于时区)的时间。

      世界上的所有时区都可以表示为 UTC 加上或减去一个偏移量。

      因此,UTC是0时区的时间,如北京为早上八点(东八区),UTC时间就为零点,时间比北京时晚八小时

  GMT :Greenwich Mean Time格林威治标准时间,指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。

  Unix timestamp :Unix时间戳,或称Unix时间(Unix time)、POSIX时间(POSIX time),是一种时间表示方式,

      定义为从格林威治时间(UTC/GMT的午夜)1970年01月01日00时00分00秒起至现在的总秒数。

  可以这么说:

  UTC和GMT几乎是同一概念,两者的区别是GMT是一个天文上的概念,UTC是基于原子钟。

  GMT=UTC

  GMT + 8 = UTC + 8 = CST

  UTC+时间差=本地时间 (时间差东为正,西为负,东八区记为 +0800)

 

二. 从数据库取数据的过程

  
mysql>
select 
auction_id,starts
from 
auctions 
where 
auction_id=88888;
+
-------------+---------------------+
| auction_id  | starts |
+
-------------+---------------------+
| 88888       | 2011-10-24 20:32:58 |
+
-------------+---------------------+
1 row
in 
set 
(0.00 sec)
 
mysql> show columns
from 
auctions;
+
--------------------------------+---------------+------+-----+---------+-------+
| Field | Type |
Null 
Key
Default 
| Extra |
+
--------------------------------+---------------+------+-----+---------+-------+
|starts | datetime | YES | MUL |
NULL 
| |

  可见:数据库的时间字段starts存的是datetime类型,它是一个和时区相关的string(显然:string都是和时区相关的)

  而且数据库是按照CST时区存的时间

     程序中从数据库取数据用的sql语句:

mysql>
select 
auction_id,DATE_FORMAT(starts,
'%Y%m%d%H%i%S'
)
from 
auctions 
where 
auction_id=88888;
+
-------------+------------------------------------+
| auction_id  | DATE_FORMAT(starts,
'%Y%m%d%H%i%S'
) |
+
-------------+------------------------------------+
| 88888       | 20111024203258 |
+
-------------+------------------------------------+
1 row
in 
set 
(0.00 sec)

  这里只是简单的用DATE_FORMAT函数把datetime类型的starts字段转换为我们需要的格式 %Y%m%d%H%i%S 而已

 

三、代码

  看这样一段转换时间的java代码:

// 将字符串时间转化为秒数(yyyyMMddHHmmss)
static
public 
long 
getUnixTimestamp(String srcTime)
{        
          
SimpleDateFormat sdf =
new 
SimpleDateFormat(
"yyyyMMddHHmmss"
);
          
Date result_date;
          
long
result_time = 
0
;
          
try
                   
result_date = sdf.parse(srcTime);
                   
//返回的是毫秒数故除以1000
                   
result_time = result_date.getTime()/
1000
;
          
}
catch 
(Exception e) { 
                   
//出现异常时间赋值为20000101000000
                   
result_time =
946684800
;
          
}
          
return
result_time;
 
}

  计算结果:

getUnixTimestamp(
"20111204212224"
) =
1323004944

  说明:java.util.Date中的getTime函数定义如下:

     java.util.Date代表一个时间点,其值为距公元1970年1月1日 00:00:00的毫秒数。所以它是没有时区和Locale概念的。

     public long getTime() 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数

  java中通过如下形式取得当前时间点: 

Date now =
new 
Date(); 
//这个时间点与本地系统的时区无关

  而正因为其与时区的无关性,才使得我们的存储数据(时间)是一致的(时区一致性)。

  一般的我们将now存储于数据库中,当我们需要展现数据时,将now格式化成想要的格式,如:2011-12-04 21:22:24
  而这个功能一般交由java.text.DateFormat来实现。例如:

SimpleDateFormat sdf =
new 
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
);
String snow = sdf.format(now);

  我们发现snow是带时间(如2011-12-04 21:22:24)的字符串,那么 2011-12-04 21:22:24 这个时间是哪个时区的时间呢?

  默认情况下,SimpleDateFormat 取得本地系统的时区(我的时区为GMT+8北京),然后按照 pattern("yyyy-MM-dd HH:mm:ss")格式化now,

  此时输出的就是 GMT+8 区的时间了。如果想支持国际化时间,则先指定时区,然后再格式化date数据。例如:

SimpleDateFormat sdf =
new 
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
);
sdf.setTimeZone(TimeZone.getTimeZone(
"GMT+8"
));
String snow = sdf.format(now);
// snow = 2011-12-04 21:22:24
sdf.setTimeZone(TimeZone.getTimeZone(
"GMT+7"
));
String snow2 = sdf.format(now);
// snow2 = 2011-12-04 20:22:24 (可见:东八区比东七区早一个小时)

  另外,你可以通过如下代码修改本地时区信息:

TimeZone.setDefault(TimeZone.getTimeZone(
"GMT+8"
));

  在windows操作系统中,是通过桌面右下角,也可以指定操作系统的时区。

  在linux系统中,通过如下命令可以得到当前时区

[admin
@localhost
]$ date -R
Sun,
04 
Dec 
2011
22
:
49
:
00
+
0800

 

四、结论:

  getTime()返回的已经是一个UTC的unix timestamp秒数了,与时区无关;而转换为字符串后,就和时区相关了

  对于这个秒数,不同时区的人,按照自己所在的时区去解析,就可以得到正确的时间了

[admin
@localhost
]$ date -d
@1323004944
2011
12
月 
04
日 星期日
21
:
22
:
24
CST
[admin
@localhost
]$ date -d
@1323004944 
-u
2011
12
月 
04
日 星期日
13
:
22
:
24
UTC

  对于涉及到时间转换的程序来说,如果代码里面没有强行指定时区,那就会依赖于操作系统的时区。

  特别是对于分布式程序,如果不同机器上系统时区不一样,那就会出现不一致的数据了!

 

五、对unix timestamp和时区概念的曲解和误用

  由于历史原因,发现程序中有这样一段代码:

// 将字符串时间转化为秒数(yyyyMMddHHmmss),有8个小时的时差
  
static
public 
long 
getLongTime(String srcTime)
  
{        
            
SimpleDateFormat sdf =
new 
SimpleDateFormat(
"yyyyMMddHHmmss"
);
            
Date result_date;
            
long
result_time = 
0
;
            
try
                     
result_date = sdf.parse(srcTime);
                     
//返回的是毫秒数故除以1000
                     
result_time = result_date.getTime()/
1000
8 
3600
;  
// 这里加了八个小时
            
}
catch 
(Exception e) { 
                     
//出现异常时间赋值为20000101000000
                     
result_time =
946684800
;
            
}
             
            
return
result_time;
   
}

  计算结果:

getUnixTimestamp(
"20111204212224"
) =
1323033744

  显然,这个时间比上面通过 getUnixTimestamp("20111204212224") = 1323004944 得到的时间多了8个小时

       1323033744 - 1323004944 = 28800 = 8 * 3600 = 8h

  如果用户将得到的 1323033744 按照自己所在的时区解析后得到的结果是:

[admin
@localhost
]$ date -d
@1323033744
2011
12
月 
05
日 星期一
05
:
22
:
24
CST

  得到了一个完全错误的结果!

  但如果用户将这个 1323033744 按照UTC时区来解析后得到的结果是:

[admin
@localhost
]$ date -d
@1323033744 
-u
2011
12
月 
04
日 星期日
21
:
22
:
24
UTC

  为了方便对比,把 1323004944 的解析结果也拿来对比

[admin
@localhost
]$ date -d
@1323004944
2011
12
月 
04
日 星期日
21
:
22
:
24
CST
[admin
@localhost
]$ date -d
@1323004944 
-u
2011
12
月 
04
日 星期日
13
:
22
:
24
UTC

  可以看到,这个代码中得到的秒数时间是比UTC的unix timestamp秒数多了八个小时

    这个时间 1323033744 可以理解为北京时区得到的秒数,但是不是unix timstamp时间!

    unix timestamp秒数是与时区无关的,不管是在哪个时区得到的unix timestamp都是一样的

  我们可以验证一下,用北京时间“20111204212224”减去“19700000000000”得到的秒数,就是 1323033744

SimpleDateFormat df =
new 
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
);
java.util.Date end = df.parse(
"2011-12-04 21:22:24"
);
java.util.Date start = df.parse(
"1970-01-01 00:00:00"
);
long
delta = (end.getTime() - start.getTime())/
1000
;
System.out.println(
"delta="
+ delta); 
// delta=1323033744

  或者用shell命令来求时间差

[admin
@localhost
]$ date -d
"2011-12-04 21:22:24" 
+%s
1323004944
[admin
@localhost
]$ date -d
"1970-01-01 0:0:0" 
+%s
-
28800
[admin
@localhost
]$ date -d
"2011-12-04 21:22:24" 
+%s -u
1323033744
[admin
@localhost
]$ date -d
"1970-01-01 0:0:0" 
+%s -u
0

    1323004944 + 28800 = 1323033744

  对于东八区的人来说,1323033744 这个时间按照UTC时间可以解析正确。不能按照自己所在的时区去解析,不然就是错的

  但是如果是东七区的人呢?需要按照UTC时间解析后,自己去减1个小时的时差,so ugly!

  所以,用户在解析1323033744 这个数据的时候:

    (1) 按照UTC时间来解析得到北京时间,然后根据时间差换算成自己所在时区的时间

        (当然,一般都是在北京时区了,所以不用换算,按UTC时间来解析就能得到正确的时间)

    (2) 将这个时间减去8小时得到unix timestamp,然后按照自己所在的时区去解析就可以了

  总结:这段代码是对unix timestamp和时区的曲解和误用。

 

六、从数据库获取unix timestamp时间

    其实从数据库是可以直接获取到unix timestamp时间的

mysql> select auction_id,unix_timestamp(starts)  from auctions where auction_id=
88888
;                                                   
 
+-------------+------------------------+
 
| auction_id  | unix_timestamp(starts) |
 
+-------------+------------------------+
 
|
88888       
|            
1319459578 
|
 
+-------------+------------------------+
 
1
row in set (
0.02 
sec)

 

七、参考

  java.util.Date  

  关于java Date和时区的问题  

八、unix时间戳转换工具

http://code.aosoo.com/unixtime

 
 

转载于:https://www.cnblogs.com/bigben0123/p/6042985.html

你可能感兴趣的文章
翻译的一篇关于VBO的文章
查看>>
数据结构之表(C语言实现)
查看>>
php单例模式
查看>>
安卓开发第一天小结
查看>>
android GUI 流程记录
查看>>
C# 修饰符
查看>>
负载均衡介绍
查看>>
海贼王之——梦想音乐
查看>>
Windows Azure Cloud Service (18) 基于Input Endpoint通过Worker Role发布WCF服务
查看>>
如何解决最后一个尾注引用显示与致谢混为一谈的问题-下
查看>>
Java Socket编程 - 基于TCP方式的二进制文件传输【转】http://blog.csdn.net/jia20003/article/details/8248221...
查看>>
阅读之https及加密原理
查看>>
HDOJ4550 卡片游戏 随便销毁内存的代价就是wa//string类的一些用法
查看>>
bzoj3875 [Ahoi2014&Jsoi2014]骑士游戏
查看>>
转载-稳定排序和不稳定排序
查看>>
as3 资料链接
查看>>
css文本样式text、字体样式font
查看>>
洛谷 P1020 导弹拦截(LIS)
查看>>
python判断图片是否损坏
查看>>
MySQL服务启动:某些服务在未由其他服务或程序使用时将自动停止
查看>>