java-编码笔记-关于时间

本文介绍Java中处理时间的几种方法,包括java.util.Date、java.sql.Timestamp和java.sql.Date的使用,探讨DateFormat类的功能,并解析数据库中时间的存储方式及多数据库环境下时间字段的处理技巧。

1.几个时间类的构造

1.1 内容

1.1.1 java.util.Date

1.1.2 java.sql.Timestamp

1.1.3 java.sql.Date

1.2 概述

1.1.1 java.util.Date 是另外两类的基类

1.1.2 java.sql.Timestamp 内容是:日期+时间(2020-08-05 12:40:55)

1.1.3 java.sql.Date 内容是:日期(2020-08-05)

1.3 代码

package testJava;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TimestampTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		CreateTimestamp ctt = new CreateTimestamp();
		ctt.mian();
		CreateUtilDate ct = new CreateUtilDate();
		ct.mian();
		CreateSqlDate csd = new CreateSqlDate();
		csd.mian();
	}

	static class CreateTimestamp {
		void mian() {
			System.out.println("1 TimestampTest");
			createByString();
			createByLong();
		}

		// 通过字符串创建
		void createByString() {
			Timestamp time = new Timestamp(System.currentTimeMillis());// 获取系统当前时间
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String timeStr = df.format(time);
			System.out.println("使用的字符串:" + timeStr);
			time = Timestamp.valueOf(timeStr);
			System.out.println("生成的时间:" + time);
		}

		// 通过时间戳创建
		void createByLong() {
			Date date = new Date();
			System.out.println("使用的时间戳:" + date.getTime());
			Timestamp ts = new Timestamp(date.getTime());
			System.out.println("生成的时间:" + ts);
		}
	}

	static class CreateUtilDate {
		void mian() {
			System.out.println("\n2 ava.util.Date Test");
			create();
			createByLong();
		}

		// 通过字符串创建
		void create() {
			Date dt = new Date();
			System.out.println("生成的时间:" + dt);
		}

		// 通过时间戳创建
		void createByLong() {
			Long timeLong = System.currentTimeMillis();
			Date dt = new Date(timeLong);
			System.out.println("生成的时间:" + dt);
		}
	}

	static class CreateSqlDate {
		void mian() {
			System.out.println("\n3 java.sql.Date Test");
			createByString();
			createByLong();
		}

		// 通过字符串创建
		void createByString() {
			java.sql.Date time = new java.sql.Date(System.currentTimeMillis());// 获取系统当前时间
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			String timeStr = df.format(time);
			System.out.println("使用的字符串:" + timeStr);
			java.sql.Date time2 = java.sql.Date.valueOf(timeStr);
			System.out.println("生成的时间:" + time2);
		}

		// 通过时间戳创建
		void createByLong() {
			Long timeLong = System.currentTimeMillis();
			System.out.println("使用的时间戳:" + timeLong);
			java.sql.Date dt = new java.sql.Date(timeLong);
			System.out.println("生成的时间:" + dt);
		}
	}

}

2. 关于java.text.DateFormat

2.1

概述:关于时间,其实时间的本质无非就是时间戳(1970年到当前的毫秒数),而用户的使用通常都是格式的时间比如1999-10-10 13:00:00 等,所以时间就给了很多设置的方式,最终由时间类转变成时间戳。所以设计时间也可以通过格式设定,而DateFormat类就是一个很友好的家伙,你设置我就行了,其他的事情我来搞定。但是你得按照一定的规则来设计,规则很简单哦。

2.2 代码实验

(总结:DateFormat的价值在于可以创建util.Date,而util.Date可以转换为任何形式的 Date(sql.Date/sql.Timestamp))

package testJava;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;

public class DateFormatTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("DateFormatTest");
		Create c = new Create();
		c.main();
	}
	static class Create{
		void main() {
			createUtilDate();
			createSqlTimestamp();
		}
		private void createUtilDate() {
			System.out.println("转换为util.Date");
			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.SSS", Locale.ENGLISH);//设定格式
		    dateFormat.setLenient(false);
		    String sToTimestamp = "2005-8-18 14:21:12.123";
		    try {
		    	java.util.Date timeDate = dateFormat.parse(sToTimestamp);
		    	System.out.println("格式时间:"+timeDate);
		    	System.out.println("时间戳:"+timeDate.getTime());
		    }catch(Exception e) {
		    	System.out.println(e.toString());
		    }
		}
		private void createSqlTimestamp() {
			System.out.println("转换为sql.Timestamp");
			System.out.println("DateFormatTest");
			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.SSS", Locale.ENGLISH);//设定格式
		    dateFormat.setLenient(false);
		    String sToTimestamp = "2005-8-18 14:21:12.123";
		    try {
		    	java.util.Date timeDate = dateFormat.parse(sToTimestamp);
		    	java.sql.Timestamp dateTime = new java.sql.Timestamp(timeDate.getTime());
		    	System.out.println("格式时间:"+dateTime);
		    	System.out.println("时间戳:"+dateTime.getTime());
		    }catch(Exception e) {
		    	System.out.println(e.toString());
		    }
		}
	}
}

2.3 图解时间相关类的关系

3 数据库时间的存储

3.1 关于数据库的时间问题

3.1.1 问题

3.1.1.1 数据库里保存的时间字符还是是时间戳?

3.1.1.2 数据库对输入的时间如何处理,比如时间戳怎么保存,其他格式怎么处理?

3.1.2 问题调查

 问:数据库保存时间是用时间戳还是日期格式?

 答:应该说有两种方案供用户选择,比如:Mysql 内置了 timestamp 和 datetime 两个类型供开发者选择,timestamp 保存的是时间戳,而datetime 则不同。时间戳的优势是性能,而datetime的表示能力更丰富,比如1970年之前的时间,用时间戳就没有办法表示。

问:数据库对输入的时间如何处理

答:数据库一般提供相对丰富的处理方式

3.2 PreparedStatement设置时间

3.2.1 ps.setTimestamp(2, new Timestamp(new Date().getTime()));//数据库中显示的是当前系统日期+时间

3.2.2 ps.setTime(2, new Time(new Date().getTime()));//数据库中显示的是1970-1-1+当前系统时间

3.2.3 ps.setDate(2, new java.sql.Date(new Date().getTime()));//数据库中显示的是当前系统日期+0:00:00

这里有个问题。setTimestamp设置后的数据在保存给dataTime类型的数据库字段时会怎么处理呢。时做了些自动的转换吗?(java.sql.Timestamp类型的输出都是字符类型,形如2020-10-10 20:20:20.001,而数据库的接收都是支付类型,差别在于保存的处理,比如要保存成时间戳,数据库会自动将字符型的数据转换成时间戳)

还有 datetime类型的数据对应的PreparedStatement 应该设置成什么样的类型呢?

3.3 多数据库数据插入实验

例如有表table,table 中有两个字段:name 、makedate

1.oracle:

插入系统时间应为sysdate:

insert into table (name,makedate) values('测试',sysdate);

2.Db2:

插入系统时间应为current timestamp并且makedate数据类型为timestamp

insert into table (name,makedate) values('测试',current timestamp);

3.SqlServer:

插入系统时间应为GETDATE()

insert into table (name,makedate) values('测试',GETDATE());

4.MySQL:

插入系统时间应:

now():以'yyyy-mm-dd hh:mm:ss'返回当前的日期时间,可以直接存到datetime字段中。

curdate():’yyyy-mm-dd’的格式返回今天的日期,可以直接存到date字段中。

insert into table (name,makedate) values('测试',now());

3.4 mysql dateTime使用问题记录

3.4.1 数据库自动对毫秒精度进行了四舍五入

具体情况看例子:

mysql> create table t(id int,dt datetime);
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values(1,'2019-03-05 01:53:55.63');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t;
+------+---------------------+
| id | dt |
+------+---------------------+
| 1 | 2019-03-05 01:53:56 |
+------+---------------------+
1 row in set (0.00 sec)

问题好理解,数据库自动对毫秒精度进行了四舍五入,取了个近似值。
解决问题:

问题也好解决:
1.修改字段类型,给datetime加上精度,改成datetime(2),这样就把后面的毫秒精度存进数据库了,也不会出现查询时数值错误;
2.如果毫秒精度实际意义不大,可以在程序中截断毫秒值,存入数据库的值直接精确到秒,这样数据库层面不需要修改。

mysql> create table t_m(id int,dt datetime(2));
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t_m values(1,'2019-03-05 01:53:55.63');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t_m;
+------+------------------------+
| id | dt |
+------+------------------------+
| 1 | 2019-03-05 01:53:55.63 |
+------+------------------------+
1 row in set (0.00 sec)

个人赞成第二种方法,因为架构定好后,不建议随便修改底层数据库,尽量从代码层满足需求,除非迫不得已。

3.4.2.自动识别时间字符串

查看数据库默认日期类型格式:

mysql> show variables like 'datetime_format';
+-----------------+-------------------+
| Variable_name | Value |
+-----------------+-------------------+
| datetime_format | %Y-%m-%d %H:%i:%s |
+-----------------+-------------------+
1 row in set (0.00 sec)

默认格式是‘%Y-%m-%d %H:%i:%s’这样的,一般写入数据也是这种格式。

当写入其他时间字符串时,只有数据库能识别都会写入成功,且是想要的数据;如果识别不了的时间值,会显示成‘0000-00-00 00:00:00’。

mysql> insert into t values(3,'20191221010203');

mysql> select * from t;
+------+---------------------+
| id | dt |
+------+---------------------+
| 3 | 2019-12-21 01:02:03 |
+------+---------------------+

mysql> insert into t values(4,'2019/12/21/1/21/3');

mysql> select * from t;
+------+---------------------+
| id | dt |
+------+---------------------+
| 4 | 2019-12-21 01:21:03 |
+------+---------------------+

插入一个不存在的时间,会显示出‘0000-00-00 00:00:00’,比如63秒

mysql> insert into t values(4,'2019/12/21/1/21/63');

mysql> select * from t;
+------+---------------------+
| id | dt |
+------+---------------------+
| 4 | 0000-00-00 00:00:00 |
+------+---------------------+

3.4.3.查询时智能的补全模式

经常接到研发反馈,查一天的数据,查不出来,比如查询‘2019-12-21’日期的全部数据,很多人在where条件中写where dt = '2019-12-21',妄图查出一天的数据。如果dt类型是date,会如常所愿;如果是datetime或其他类型,恐怕要大失所望了,因为MySQL会对datetime值自动补零。

例子:

表中有3条数据:

mysql> select * from t;
+------+---------------------+
| id | dt |
+------+---------------------+
| 3 | 2019-12-21 01:02:03 |
| 4 | 2019-12-21 01:21:03 |
| 4 | 0000-00-00 00:00:00 |
+------+---------------------+

查询‘2019-12-21’的数据:

mysql> select * from t where dt='2019-12-21';
Empty set (0.00 sec)

期望查到两条数据,实际啥都没查到,因为数据库自动根据类型补全了0,实际查询语句成了:select * from t where dt='2019-12-21 00:00:00';

对于datetime类型的值,想要查询一天的数据,可以通过范围查询:between and(between and是左右闭合区间,两边数值都能查到) 。

mysql> select * from t where dt between '2019-12-21 00:00:00' and '2019-12-21 23:59:59';
+------+---------------------+
| id | dt |
+------+---------------------+
| 3 | 2019-12-21 01:02:03 |
| 4 | 2019-12-21 01:21:03 |
+------+---------------------+

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值