时间戳 时区 java mysql
- 当一个时间 比如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是什么?
- 内部存储是4个字节
- 精度达到微妙
- 回转换成UTC时间存储
- 读取的时候再根据时区转换回来
+-----------------------+
| 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)
- 如何在mysql中根据timestamp得到UTC系统时间戳呢呢?
+----------------------------------------+
| unix_timestamp( 20130722183356.000000) |
+----------------------------------------+
| 1374489236 |
+----------------------------------------+
- 如何在mysql中根据UTC 系统时间戳得到当前时区的timestamp呢?
+---------------------------+
| from_unixtime(1374489236) |
+---------------------------+
| 2013-07-22 18:33:56 |
+---------------------------+
1 row in set (0.00 sec)
- 如何在mysql中根据当前时区的时区得到其他时区的timestamp呢?
+---------------------+
| 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)
最近在编程中遇到了时间与时区相关的问题,整理在这里
我的程序是一个在Hadoop上运行的分布式程序,从MySQL数据库中取数据,经过处理之后输出
一. 基本概念
时区 :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代码
看这样一段转换时间的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 http://www.jar114.com/jdk6/zh_CN/api/java/util/Date.html
关于java Date和时区的问题 http://blog.163.com/haizai219@126/blog/static/444125552009101924912981/
八、unix时间戳转换工具
http://code.aosoo.com/unixtime
时间戳 时区 java mysql的更多相关文章
- Mysql时间戳转Java时间戳
MySQL 时间戳和Java返回的时间戳是不一样的 例如: 当前时间是 2014-08-04 10:42:55.204000 使用mysql时间戳函数UNIX_TIMESTAMP 返回的结果为: 14 ...
- Java Mysql连接池配置和案例分析--超时异常和处理
前言: 最近在开发服务的时候, 发现服务只要一段时间不用, 下次首次访问总是失败. 该问题影响虽不大, 但终究影响用户体验. 观察日志后发现, mysql连接因长时间空闲而被关闭, 使用时没有死链检测 ...
- java mysql 日期类型
mysql(版本:5.1.50)的时间日期类型如下: datetime 8bytes xxxx-xx-xx xx:xx:xx 1000-01-01 00:00:00到9999-12-31 23:59: ...
- 阿里云上安装mysql步骤/ 阿里云ECS搭建Java+mysql+tomcat环境
使用阿里云ECS挺长一段时间了.这两天碰巧朋友小白让我一步一步教他在ECS上搭建Java+mysql+tomcat环境,所以把在这里把步骤在这简单整理了一下,以便需要的人查阅. 我购买的阿里云服务器系 ...
- Java mysql 日期相关
获取当前系统时间和日期并格式化输出: import java.util.Date;import java.text.SimpleDateFormat; public class NowString { ...
- java mysql模板
Java mysql的模版,很优雅.同时也兼顾了性能PreparedStatement和安全性(防SQL注入)两方面.对于比较简单的数据库操作基本满足要求. package dao; import j ...
- C# 制作Java +Mysql+Tomcat 环境安装程序,一键式安装
原文:C# 制作Java +Mysql+Tomcat 环境安装程序,一键式安装 要求: JDK.Mysql.Tomcat三者制作成一个安装包, 不能单独安装,安装过程不显示三者的界面, 安装完成要配置 ...
- java mysql 数据类型对照
java mysql 数据类型对照 类型名称 显示长度 数据库类型 JAVA类型 JDBC类型索引(int) 描述 VARCHAR L+N VARCHAR java.lang. ...
- 在linux环境下搭建JDK+JAVA+Mysql,并完成jforum的安装
参考链接: YUM安装MySQL和JDK和Tomcat:http://cmdschool.blog.51cto.com/2420395/1696206/ http://www.cnblogs.com/ ...
随机推荐
- SQL周、日、月、年数据统计
本文只是记录在项目中用到的统计的SQL语句,记一笔以防忘了 /// <summary> /// 获取统计数据 /// </summary> /// <param name ...
- SQL数据库修改默认备份和恢复路径
每次都做数据恢复和备份的时候,点Add文件,系统会自动指定到一个默认路径,是SQL的安装目录,但是我的数据库不是备份在这里,每次都要更改有点麻烦. 如上图,更改这个有三个方法. 方法一:找到注册表,手 ...
- win10磁盘100%解决办法
控制面板-管理工具-服务 找到“HomeGroupListener”服务,双击打开或右键单击“属性”命令. 在弹出属性界面窗口,在常规选项卡单击启动类型的下拉框,出来的列表选择“禁用”.然后在服务状态 ...
- android 尽量不要使用static静态变量
使用静态static静态变量潜在性问题: 1.占用内存,并且内存一般不会释放: 2.在系统不够内存情况下会自动回收静态内存,这样就会引起访问全局静态错误. 3.不能将activity作为static静 ...
- nginx 301 永久重定向
nginx301跳转设置很简单,配置如下. (配置文件默认为nginx.conf,如果制定了新的配置文件,在新的文件配置即可.) server{ server_name xxx.com www.xxx ...
- 如何读取Access里的OLE类型的图片
身份证一类读卡器读取的照片信息,保存在Access数据库中一般为OLE型字段,图片为BMP格式,因为是用其读卡器写入的,其数据类型为常二进制数据. 再用报表或EXCEL读取这些图片时,如果将该图片字段 ...
- spark1.4.1 启动过程
今天稍微没那么忙了,趁着这个时间,准备把spark的启动过程总结一下(),分享给大家.现在使用的spark1.4.1版本 当然前提是你已经把spark环境搭建好了. 1.我们启动spark的时候一般会 ...
- NopCommerce 增加 Customer Settings
预期: 仿照Customer 的 Phone number enabled 和 required 增加MemberType 相关步骤如下: 1.运行站点 Admin -> Settings -& ...
- uva 140 bandwidth (好题) ——yhx
Bandwidth Given a graph (V,E) where V is a set of nodes and E is a set of arcs in VxV, and an orde ...
- Unity Shader入门
Unity Shader入门 http://www.cnblogs.com/lixiang-share/p/5025662.html http://www.manew.com/blog-30559-1 ...