我有一个包含下一项的集合,其属性之一是日期:
id: xxxxxx
name: xxxx
date: August 21, 2018 at 1:00:00 AM UTC+8 (timestamp)
在firebase云功能中,我试图查询某个时间段内的所有对象,该时间段可以是日,周,年等。
我想在当前服务器日期之前查询项目,因此我在Firebase Cloud Function中进行了此操作:
let auxDate = moment();
dateStart = auxDate.startOf('day').toDate();
dateEnd = auxDate.endOf('day').toDate();
await admin.firestore().collection('items')
.where("date", ">=", dateStart)
.where('date', '<=', dateEnd).get();
控制台中打印的dateStart和dateEnd的值为:
Date start: Tue Aug 21 2018 00:00:00 GMT+0000 (UTC)
Date end: Tue Aug 21 2018 23:59:59 GMT+0000 (UTC)
查询返回0个项目。但是当我将商品的日期更改为
时id: xxxxxx
name: xxxx
date: August 21, 2018 at 8:00:00 AM UTC+8 (timestamp)
查询正确返回该项目。
所以现在我知道了问题与偏移有关,但是我该如何解决?为什么Firebase将所有日期保存在UTC + 8中?
答案 0 :(得分:2)
我找到了自己问题的答案。我将详细解释。
了解问题所在:
首先要记住,我们是在Cloud Function中进行此查询的,因此我们不知道客户端时区。在Firestore中,所有日期都保存在UTC + 00中。所以,如果我有类似的物品:
id: xxxxxx
name: xxxx
date: August 22, 2018 at 12:00:00 AM UTC+8 (timestamp)
这意味着该日期等于August 21, 2018 at 04:00:00 PM UTC+0
。
因此,如果我要查询之间的所有日期:
Date start: August 22, 2018 at 12:00:00 AM UTC+8 (timestamp)
Date end: August 22, 2018 at 11:59:59 PM UTC+8 (timestamp)
这意味着查询必须类似于:
Date start: August 21, 2018 at 04:00:00 AM UTC+0 (timestamp)
Date end: August 22, 2018 at 03:59:59 PM UTC+0 (timestamp)
问题是当我执行let auxDate = moment()
时,该日期创建的服务器时间没有偏移,因此auxDate的值例如是:August 21, 2018 at 11:23:43 PM UTC+0
。
因此auxDate的开始日期变为:
auxDate start: August 21, 2018 at 12:00:00 AM UTC+0 (timestamp)
auxDate end: August 21, 2018 at 11:59:59 PM UTC+0 (timestamp)
正如我们看到的那样,该查询未满足我们必须查询的范围,并且许多项目将被淘汰。
问题结论:
如果我们不知道客户端的时区,我们将无法正确查询。
解决方案:
现在,我将客户端的当前时间传递给此云函数,并计算开始日期和结束日期:
const clientCurrentDateTime = "2018-08-22T11:23:15+08:00";
let startDate = moment(clientCurrentDateTime).utcOffset(clientCurrentDateTime).startOf('day').toDate();
let endDate = moment(clientCurrentDateTime).utcOffset(clientCurrentDateTime).endOf('day').toDate();
这会为不同的偏移量/时区创建正确的开始和结束日期时间