最近处理反馈时,创造一个有趣的bug,即时区不一致导致数据缺点。

bug是这样的:

产品的接口流量报表中,查看当前一周的周报表时,创造未来几小时的报表数据已天生,这显然是不科学的。
那么,到底是什么缘故原由导致的呢?

php中datatime时区问题激发的Bug商量 Webpack

1. 首先,查看流量报表是如何获取数据的

流量报表是一张韶光轴折线图(如下图所示),x轴为韶光轴,从周一到周日,每天以小时为单位取24个点,y轴是流量值,每个小时时段内取最大值,无流量用0添补。
sql语句如下:

12select strftime('%H',time,'unixepoch')ashour,max(ibps)asibps,max(obps)asobps from traffic where time>?andtime<?group by hour order by hour;

接口流量统计

2. 其次,逐步排查问题

以周一的数据为例,进行排查。

第一步:确认传入的查询韶光参数是精确的,即从每天的0时0分0秒开始,截至到越日的0时0分0秒,用韶光戳表示,确认是精确的。

第二步:确认韶光段内的数据是否精确,下图分别为sql查询结果和php中韶光的输出结果片段。

输出片段

由上面两图可确认,sql语句中通过strftime转化后的小时比php strftime后的韶光整整慢了八个小时,从而导致数据缺点。

可是相差的八个小时到底是怎么回事呢?

敏感的八小时,难道是时区问题?

第三步:确认时区

查看php环境中时区 data_default_timezone_get();//输出 Etc/GMT-8 ,为东八区,精确!

那问题很可能出在数据库sql语句中,由于产品中采取的是sqlite无配置数据库,没有单独的时区配置,那会不会是系统的时区问题呢?

时区问题

由上可见,系统中的韶光和时区都是精确的,为GMT-8东八区。

可为什么数据库中解析出来的韶光会慢八个小时呢???

我们再回来看下sql语句:

12select strftime('%H',time,'unixepoch')ashour,max(ibps)asibps,max(obps)asobps from traffic where time>?andtime<?group by hour order by hour;

根据函数文档确认,strftime(%H,time,’unixepoch’)实行默认是显示为UTC韶光的,与系统时区无关,以是实行后与本地韶光(东八区)相差八个小时。

绕了一大圈终于找到了缘故原由,办理方案就很大略了,只要把韶光转化为本地韶光即可,如下所示:

12select strftime('%H',time,'unixepoch',’localtime’)ashour,max(ibps)asibps,max(obps)asobps from traffic where time>?andtime<?group by hour order by hour;

3. 涉及到的干系知识

(1) sqlite数据库韶光函数

包含下面五个,个中可以通过strftime表示其他四种函数。

详细利用方法可参考:

123456date(timestring,modifier,modifier,...)time(timestring,modifier,modifier,...)datetime(timestring,modifier,modifier,...)julianday(timestring,modifier,modifier,...)strftime(format,timestring,modifier,modifier,...)

(2) 与时区干系的观点

a. GMT(Greenwich Mean Time)/GST(Greenwich Sidereal Time)格林威治标准韶光,以地球自转为根本的韶光计量系统,但是地球每天的自转是不规则的,而且正在缓慢减速,以是存在偏差。

b. UTC(Coordinated Universal Time)折衷天下时,基于原子钟,更精确

c. NTP(Network Time Protocol)网络韶光协议,用来同步网络中各个打算机韶光的协议,将打算机韶光同步到UTC,韶光源可以是原子钟,天文台,卫星,也可以从Internet上获取

d. RTC(Real Time Clock) Linux实时的时钟驱动,常日被嵌在打算机的芯片中,也有一些是在主板上利用Motorola MC146818(或clone)实现的。
该硬件设备可映射到/dev/rtc,供root编程访问。

e. Epoch指的是一个特定的韶光:1970-01-01 00:00:00 UTC。
UNIX韶光戳(Unix time, POSIX time 或 Unix timestamp)是从Epoch(1970年1月1日00:00:00 UTC)开始所经由的秒数,不考虑闰秒。
一个小时表示为UNIX韶光戳格式为:3600秒;一天表示为UNIX韶光戳为86400秒,闰秒不打算。

f. Linux中关于韶光的知识

Linux机器里有两个时钟,一个是硬件时钟,一个是内核时钟。
硬件时钟是电池驱动的,通过专门的芯片事情,可以通过BIOS设置屏或一些系统命令(如hwclock)进行设置。
内核时钟是由内核掩护的,启动时从硬件读取韶光,之后独立运行。

hwclock -r 查看硬件韶光

/usr/share/zoneinfo 支持的时区文件

/etc/localtime 系统本地时区,可通过tzset或者ln –s /etc/localtime /usr/share/zoneinfo/Asia/Shanghai设置

/etc/sysconfig/clock 掌握如何解读硬体时钟的韶光,用来设置用户选择何种办法显示韶光,如果硬件时钟为本地韶光,则UTC设为0,并且不用设置环境变量TZ。

如果硬件时钟为UTC韶光,则要设置UTC为1,并设置环境变量TZ为时区信息,如“Asia/Shanghai”。

如果您须要理解更多内容,可以

加入QQ群:486207500