点击周活
![changlishe](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/002/04/22/88_avatar_mid.jpg?v=1656319081)
- 发布:2022-12-03 16:49
- 更新:2022-12-09 01:52
- 阅读:299
产品分类: uniCloud/App
操作步骤:
预期结果:
获取周活跃设备
获取周活跃设备
实际结果:
获取到昨天的活跃设备
获取到昨天的活跃设备
bug描述:
以今天时间 2022-12-03 16:19 星期六为例,如果获取本周活跃设备,获取到的设备是昨天 2022-12-02 00:00:00 到现在的活跃设备,而不是本周的活跃设备。
下面是 uni-stat 的 mod/activeDevices.js 的代码
const dateDimension = dateTime.getTimeDimensionByType('day', -1, date)
this.startTime = dateDimension.startTime
// 是否在本周内已存在
const datetime = new DateTime()
const dateDimension = datetime.getTimeDimensionByType('week', 0, this.startTime)
// 取出本周已经存储的device_id
const weekHaveDeviceList = []
const haveWeekList = await this.selectAll(this.tableName, {
appid: data.appid,
version_id: versionInfo._id,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
device_id: {
$in: data.device_ids
},
dimension: 'week',
create_time: {
$gte: dateDimension.startTime,
$lte: dateDimension.endTime
}
}, {
device_id: 1
})
if (haveWeekList.data.length > 0) {
for (const hui in haveWeekList.data) {
weekHaveDeviceList.push(haveWeekList.data[hui].device_id)
}
}
其中 this.startTime 是昨天的时间
而在 lib/date.js 可以看到 getTimeDimensionByType 函数
/**
* 根据指定的时间类型获取时间范围
* @param {String} type 时间类型 hour:小时 day:天 week:周 month:月
* @param {Number} offset 时间的偏移量
* @param {Date|Time} thistime 指定的日期或时间戳
* @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定日期初始时间戳(当天00:00:00的时间戳)
*/
getTimeDimensionByType(type, offset = 0, thistime, getAll = false) {
let startTime = 0
let endTime = 0
switch (type) {
case 'hour': {
startTime = this.getTimeBySetHours(offset, thistime, getAll)
endTime = getAll ? startTime : startTime + 3599999
break
}
case 'day': {
startTime = this.getTimeBySetDays(offset, thistime, getAll)
endTime = getAll ? startTime : startTime + 86399999
break
}
case 'week': {
startTime = this.getTimeBySetWeek(offset, thistime, getAll)
endTime = getAll ? startTime + 86400000 * 6 : startTime + 86400000 * 6 + 86399999
break
}
case 'month': {
startTime = this.getTimeBySetMonth(offset, thistime, getAll)
const date = this.getDateObj(this.getDate('Y-m-d H:i:s', startTime))
const nextMonthFirstDayTime = new Date(date.getFullYear(), date.getMonth() + 1, 1).getTime()
endTime = getAll ? nextMonthFirstDayTime - 86400000 : this.getTimeByDateAndTimezone(
nextMonthFirstDayTime) - 1
break
}
}
return {
startTime,
endTime
}
}
而这个问题,应该是出在 getTimeBySetWeek 上
/**
/**
* 根据设置的周数获取指定日期N周后(前)的时间戳
* @param {Number} weeks 周数
* @param {Date|Time} time 指定的日期或时间戳
* @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定日期初始时间戳(当天00:00:00的时间戳)
*/
getTimeBySetWeek(weeks, time, getAll = false) {
const date = this.getDateObj(time)
const dateInfo = this.getTimeInfo(time)
const day = dateInfo.nWeek
const offsetDays = 1 - day
if (weeks) {
weeks = weeks * 7 + offsetDays
}
date.setDate(date.getDate() + weeks)
let startTime = date.getTime()
if (!getAll) {
const realdate = this.getDate('Y-m-d 00:00:00', startTime)
startTime = this.getTimeByDateAndTimezone(realdate)
}
return startTime
}
如果 weeks 传入为 0,其中 time 是昨天的时间,最终计算的 startTime 其实是昨天的时间,也就是 2022-12-02 00:00:00。也就是本周统计的时间会从昨天凌晨时间算起,而不是由当前周的周一算起,这样在获取本周活跃设备时,只是获取到昨天的活跃设备。
作为比较我也查看了关于获取本月的活跃设备数的代码
// 取出本月已经存储的device_id
const dateMonthDimension = datetime.getTimeDimensionByType('month', 0, this.startTime)
const monthHaveDeviceList = []
const haveMonthList = await this.selectAll(this.tableName, {
appid: data.appid,
version_id: versionInfo._id,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
device_id: {
$in: data.device_ids
},
dimension: 'month',
create_time: {
$gte: dateMonthDimension.startTime,
$lte: dateMonthDimension.endTime
}
}, {
device_id: 1
})
if (haveMonthList.data.length > 0) {
for (const hui in haveMonthList.data) {
monthHaveDeviceList.push(haveMonthList.data[hui].device_id)
}
}
/**
* 根据设置的月数获取指定日期N月后(前)的时间戳
* @param {Number} monthes 月数
* @param {Date|Time} time 指定的日期或时间戳
* @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定日期初始时间戳(当天00:00:00的时间戳)
*/
getTimeBySetMonth(monthes, time, getAll = false) {
const date = this.getDateObj(time)
date.setMonth(date.getMonth() + monthes)
let startTime = date.getTime()
if (!getAll) {
const realdate = this.getDate('Y-m-01 00:00:00', startTime)
startTime = this.getTimeByDateAndTimezone(realdate)
}
return startTime
}
如果是本月的话,那么 startTime 是 2022-12-01 00: 00: 00,这个月活跃设备数的获取是没有问题的。
目前问题就出现在周统计上,统计上只统计了从昨天开始的活跃设备,而不是从周一起的活跃设备
![changlishe](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/002/04/22/88_avatar_mid.jpg?v=1656319081)
changlishe (作者)
如果抛去掉关于统计的问题,getTimeBySetWeek 这个函数本身可能是有问题的
/**
* 根据设置的周数获取指定日期N周后(前)的时间戳
* @param {Number} weeks 周数
* @param {Date|Time} time 指定的日期或时间戳
* @param {Boolean} getAll 是否获取完整时间戳,为 false 时返回指定日期初始时间戳(当天00:00:00的时间戳)
*/
getTimeBySetWeek(weeks, time, getAll = false) {
const date = this.getDateObj(time)
const dateInfo = this.getTimeInfo(time)
const day = dateInfo.nWeek
const offsetDays = 1 - day
if (weeks) {
weeks = weeks * 7 + offsetDays
}
date.setDate(date.getDate() + weeks)
let startTime = date.getTime()
if (!getAll) {
const realdate = this.getDate('Y-m-d 00:00:00', startTime)
startTime = this.getTimeByDateAndTimezone(realdate)
}
return startTime
}
如果是 getTimeBySetWeek(0, new Date('2022-12-09')) 获取的结果是 2022/12/9 00:00:00 (不是本周一,而是当天凌晨)
如果是 getTimeBySetWeek(1, new Date('2022-12-09')) 获取的结果是 2022/12/12 00:00:00 (下周一)
如果是 getTimeBySetWeek(-1, new Date('2022-12-09')) 获取的结果是 2022/11/28 00:00:00 (上周一)
作为对比可以看一下 getTimeBySetMonth 函数
如果是 getTimeBySetMonth(0, new Date('2022-12-09')) 获取的结果是 2022/12/1 00:00:00 (本月)
如果是 getTimeBySetMonth(1, new Date('2022-12-09')) 获取的结果是 2023/1/1 00:00:00 (下一个月)
如果是 getTimeBySetMonth(-1, new Date('2022-12-09')) 获取的结果是 2022/11/1 00:00:00 (上一个月)
当然不清楚这个是否是故而设计的,但是同一个文件下还有一个问题代码
/**
* 时间格式转换
* @param {String} format 展示格式如:Y-m-d H:i:s
* @param {Time} time 时间戳
*/
dateFormat(format, time) {
const timeInfo = this.getTimeInfo(time)
format = format || this.defaultDateFormat
let date = format
if (format) {
date = date.replace(/Y/, timeInfo.nYear)
}
if (format.indexOf('m') !== false) {
date = date.replace(/m/, timeInfo.nMonth)
}
if (format.indexOf('d') !== false) {
date = date.replace(/d/, timeInfo.nDay)
}
if (format.indexOf('H') !== false) {
date = date.replace(/H/, timeInfo.nHour)
}
if (format.indexOf('i') !== false) {
date = date.replace(/i/, timeInfo.nMinutes)
}
if (format.indexOf('s') !== false) {
date = date.replace(/s/, timeInfo.nSeconds)
}
return date
}
这种代码肯定是过不了审查的
[代码链接]https://github.com/dcloudio/uni-admin/blob/master/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/lib/date.js
changlishe (作者)
代码注释写了[仅添加本周/本月首次访问的设备],我贴的这两段代码是为了获得 haveWeekList 和 haveMonthList,根据后续的代码目的应该是用来筛选掉当天非本周/本月首次访问的设备,然后对当天的活跃设备归档。在筛选月统计时,我看确实是从月初开始筛选起的,作为对照周的筛选我以为也是从周一开始筛选起的,但是我发现是从昨天筛选起的,可能会出现本周早些天登录的设备也归档了。
2022-12-09 00:15