Java和Mongo中的Date比较(数据库默认是UTC标准时间)
由于中国处于东八区(GMT+08:00)是比世界协调时间/格林尼治时间(GMT)快8小时的时区,当格林尼治标准时间为0:00时,东八区的标准时间为08:00。
时间戳是一个数字,定义为格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。注意,同一时刻,不同时区获得的时间戳是相同的。以前很多用来记录时间的字段,在数据库中往往不会存储为Datetime类型,而是直接存储为无符号整形,存放时间戳的值。
Java中的东八区Date:"updateTime" : ("2023-12-06T10:13:49.427")
MongoDB中的UTC标准时间Date: "updateTime" : ISODate("2023-12-06T02:13:49.427Z")
MongoDB中的日期格式 是 UTC 通用标准,以z来标识,格式为yyyy-MM-dd HH:mm:ss.000Z
。
该时间比中国北京时间晚了8
个小时,即ISODate("2023-12-06T02:13:49.427Z")
相当于北京时间2023-12-06T10:13:49.427
因为mongo中的Date类型以UTC(Coordinated Universal Time)存储,就等于GMT(格林尼治标准时)时间。而系统时间使用的是GMT+0800时间,两者正好相差8
个小时。
包含日期字段实体类的封装
Book book= mongoTemplate.findOne(new Query(Criteria.where("_id").is("656fd8dde0c34e57defdc8d2")), Book.class);
System.out.println(book);
mongoTemplate查询时将MongoDB中的UTC Date类型自动转为东八区时间。
如果MongoDB配置的是LocalTinezone,也就是当前时区即东八区,则java不会再转换。
日期范围查找(查找更新时间在昨天零时至今天零时的图书)
即在2023-12-06零点
-2023-12-07零点
即2023-12-06T00:00:00.000
-2023-12-07T00:00:00.000
的图书
Mongodb数据库查询:
因为MongoDB中的Date类型比中国北京时间晚了8
个小时,所以24-8=16
查找内容为小于ISODate("2023-12-06T16:00:00.000Z")
大于ISODate("2023-12-05T16:00:00.000Z")
db.book.find({
updateTime: {$lte: ISODate("2023-12-06T16:00:00.000Z"),$gte: ISODate("2023-12-05T16:00:00.000Z")}
})
或者使用东八区时间来查,虽然配置的是UTC但是会自动将东八区转为UTC时间来查。
db.book.find({
updateTime: {$lte: ISODate("2023-12-07T00:00:00.000+08:00"),$gte: ISODate("2023-12-06T00:00:00.000+08:00")}
})
以下为错误示范,这相当于查的是北京时间2023-12-06T08:00:00.000
-2023-12-07T08:00:00.000
的图书
db.book.find({
updateTime: {$lte: ISODate("2023-12-07T00:00:00.000Z"),$gte: ISODate("2023-12-06T00:00:00.000Z")}
})
Java
第一种:
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
Query query = new Query();
Criteria criteria = Criteria.where("updateTime").lte(c.getTime());
c.add(Calendar.DAY_OF_MONTH, -1);
criteria.gte(c.getTime());
query.addCriteria(criteria);
List<Book> books = mongoTemplate.find(query, Book.class);
books.stream().forEach(book -> System.out.println(book));
原理:
java会将北京时间自动转为MongoDB中的Date类型。
将北京时间2023-12-06T00:00:00.000
-2023-12-07T00:00:00.000
转换为2023-12-05T16:00.00Z
-2023-12-06T16:00.00Z
mongoTemplate以UTC生成的Query语句去数据库中查询。
第二种:
LocalDateTime startTime = LocalDateTime.now().minusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
LocalDateTime EndTime = startTime.plusDays(1);
Query query = new Query(Criteria.where("updateTime").lte(EndTime).gte(startTime));
List<Book> books = mongoTemplate.find(query, Book.class);
books.stream().forEach(book -> System.out.println(book));
原理:
mongoTemplate以东八区生成的Query语句去数据库中查询,此时会自动将东八区转为UTC时间来查。
MongoDB条件表达式
表达式 | 含义 |
---|---|
$gt | > |
$gte | >= |
$eq | = |
$ne | != |
$lt | < |
$lte | <= |
$in | in(后面的值为bson对象数组) |
$nin | not in(后面的值为bson对象数组) |
实现方式1:
Query query = new Query(Criteria.where("updateTime").lte(LocalDateTime.now()).gte(LocalDateTime.now().minusMonths(5)));
Book book = mongoTemplate.findOne(query, Book.class);
实现方式2:
BasicDBObject query = new BasicDBObject();
BasicDBObject basicDbObject = new BasicDBObject();
LocalDateTime startTime = LocalDateTime.now();
basicDbObject.append("$lte", startTime);
basicDbObject.append("$gte", startTime.minusMonths(5));
query.put("updateTime", basicDbObject);
long countDocuments = mongoTemplate.getCollection("book").countDocuments(query);
System.out.println(countDocuments);
实现方式3:
BasicDBObject gt = new BasicDBObject("$gt",24);
BasicDBObject queryObject = new BasicDBObject("age",gt);
这个BasicDBObject 类就是bson jar包的类,这里的条件拼接出来就是下面这个格式
{"age":{"$gt":24}}
如果转换为MongoDB指令 也就是db.java.find({"age":{"$gt":24}})
。
int startYear=2011;
int startMonth=11;
int startDay=1;
BasicDBObject ageObj = new BasicDBObject("insertTime",new BasicDBObject("$gte",new Date(startYear - 1900, startMonth - 1, startDay)));
因为BasicDBObject()这个构造函数会自动帮你把Date格式数据转换为UTC通用标准时
注意:因为java.util.Date(year,month,day)这个构造函数中year是超出1900的年数,所以需要减去1900;month从0开始,所以需要减去1。
然后测试上面的代码,发现成功,日期可以筛选出来,如果我们需要是 日期大于2011-1-1 并且 小于 2012-12-12呢?
我们只需要做如下操作即可,参数自己替换
BasicDBObject ageObjStart = new BasicDBObject("updateTime",new BasicDBObject("$gte",new Date(startYear - 1900, startMonth - 1, startDay)));
BasicDBObject ageObjEnd = new BasicDBObject("updateTime",new BasicDBObject("$lte",new Date(endYear - 1900, endMonth - 1, endDay)));
BasicDBObject andObj = new BasicDBObject("$and",Arrays.asList(ageObjStart ,ageObjEnd ));
然后就可以实现筛选介于两个时间点内的数据了!