吸取教训:一段网上找的代码突然爆了,项目出现大BUG
本人是做游戏服务器开发的,碰到一个需求,给符某些要求的玩家的发送道具奖励,奖励的数量根据离线的天数计算。
这个需求实现起来很简单,只需要在玩家上线的时候计算上次离线时间和当前时间间隔的天数,然后根据策划的算法,计算出道具种类与数量,发一封邮件给玩家就可以了。
计算两个时间间隔天数的函数没有现成的,自己又懒得写,就上谷歌搜了下,选了第一条结果,代码如下
public static int differentDays(Date date1,Date date2)
{
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1); Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
int day1= cal1.get(Calendar.DAY_OF_YEAR);
int day2 = cal2.get(Calendar.DAY_OF_YEAR); int year1 = cal1.get(Calendar.YEAR);
int year2 = cal2.get(Calendar.YEAR);
if(year1 != year2) //同一年
{
int timeDistance = 0 ;
for(int i = year1 ; i < year2 ; i ++)
{
if(i%4==0 && i%100!=0 || i%400==0) //闰年
{
timeDistance += 366;
}
else //不是闰年
{
timeDistance += 365;
}
} return timeDistance + (day2-day1) ;
}
else //不同年
{
System.out.println("判断day2 - day1 : " + (day2-day1));
return day2-day1;
}
}
代码来源:https://www.cnblogs.com/0201zcr/p/5000977.html
把代码复制到项目里,调试下,发现没问题就直接用了,毕竟谷歌结果第一名,放心。
这段代码跑了几个月一直没问题,但是到了2020-1-1日那天,有玩家反馈收到了几百封奖励邮件,高兴坏了,但是出于对游戏的热爱,还是通知了运营人员。
运营把bug反馈到服务器这边后我开始排查,百思不得其解的是最近几天都没有更新服务器, 而前几天服务器都稳稳地,怎么突然就出BUG了呢。
接下来就是分析玩家数据,结合代码逻辑确定问题所在,最终根据BUG的表现排除了所有可能性后,发现唯一可能出问题的地方就是那个网上复制过来的计算天数差的函数。
根据调试发现,这个函数在两个日期参数是不同的年份并且第一个日期大于第二个日期的时候,会返回一个错误的结果
比如
differentDays("2020-1-1","2019-12-25")
理论上这么调用正确的结果是 -7,但是因为函数有bug,调用结果是 358
于是本来不用发奖励,因为这种特殊情况一下子发出去358份,严重影响了游戏某类道具的平衡性。
至于补救方式就是统计名单,把发出去但还没有用掉的道具回收,用掉的就当福利,然后再发公告道歉,再送些其他物品弥补。
也幸好补救的及时,要是这些道具收不回来,游戏运营的策略都要大变了,我特么肯定没好果子吃了。
所以千万别在网上复制来路不明的代码乱用,如果真的要用,必须反复测试,否则哪一天突然暴雷有你受的。
改用Java8的日期库修复了BUG
public static int differentDays(Date date1, Date date2) {
if (date1 == null || date2 == null) {
throw new RuntimeException("日期不能为空");
}
LocalDate localDate1 = date2LocalDate(date1);
LocalDate localDate2 = date2LocalDate(date2);
return Generic.long2int(localDate1.until(localDate2, ChronoUnit.DAYS));
}
public static LocalDate date2LocalDate(Date date) {
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
LocalDate localDate = instant.atZone(zoneId).toLocalDate();
return localDate;
}
吸取教训:一段网上找的代码突然爆了,项目出现大BUG的更多相关文章
- 完全图解scrollLeft,scrollWidth,clientWidth,offsetWidth 获取相对途径,滚动图片(网上找的,未经试验,但觉得比较好)
获取元素的位置属性可以通过 HTMLElement.offsetLeft HTMLElement.offsetTop 但是,这两个属性所储存的数值并不是该元素相对整个浏览器画布的绝对位置,而是相对于其 ...
- 分享一段Java搞笑的代码注释
今天在群里看到有人分享了一段搞笑的注释代码,觉得挺好玩的,在这里收藏一下 // _ooOoo_ // o8888888o // 88" . "88 // (| -_- |) // ...
- 从网上找的 visual studio 的各个版本下载地址,vs2010/vs2012/vs2013带注册码
从网上找的 visual studio 的各个版本下载地址,很全,从 6.0 一直 到 vs2013,要的拿去吧... Microsoft Visual Studio 6.0 下载:英文版360云盘下 ...
- PeopleSoft底层表,闪存查找历史代码(不小心改)
Oracle 闪存查找历史代码 select * from (SELECT * FROM PSPCMTXT AS OF TIMESTAMP to_timestamp('20180725 1 ...
- 内存布局:栈,堆,BSS段(静态区),代码段,数据段
简介 我们程序运行的时候都是放在内存里的.根据静态.成员函数.代码段.对象.等等.放在不同的内存分块里.大概分为5块 1 栈 2 堆 3 BSS段-全局区-(静态区) 4 代码段 5 数据段 栈 ...
- 数据段描述符和代码段描述符(二)——《x86汇编语言:从实模式到保护模式》读书笔记11
这篇博文,我们编写一个C语言的小程序,来解析数据段或者代码段描述符的各个字段.这样我们阅读原书的代码就会方便一点,只要运行这个小程序,就可以明白程序中定义的数据段或者代码段的描述符了. 这段代码,我用 ...
- 数据段描述符和代码段描述符(一)——《x86汇编语言:从实模式到保护模式》读书笔记10
一.段描述符的分类 在上一篇博文中已经说过,为了使用段,我们必须要创建段描述符.80X86中有各种各样的段描述符,下图展示了它们的分类. 看了上图,你也许会说:天啊,怎么这么多段描述符啊!我可怎么记住 ...
- 将这段美化的css代码
很多时候如果不是用了很多样式,很难把边框修饰得好看,看了一篇博文,觉得真的挺漂亮,也挺好看. 转载的博文地址 将这段美化的css代码 border:1px solid #96c2f1;backgrou ...
- C#代码反编译 得到项目可运行源码
C#代码反编译 得到项目可运行源码 摘自:http://www.cnblogs.com/know/archive/2011/03/15/1985026.html 谈到"C#代码反编译&quo ...
随机推荐
- Anagram——[枚举全排列]
预备知识: 1.求0—n个数全排列的算法: void print_permutation(int n,int *A,int cur){ if(cur==n){ ;i<cur;i++) cout& ...
- POJ 2253 Frogger(SPFA运用)
Description Freddy Frog is sitting on a stone in the middle of a lake. Suddenly he notices Fiona Fro ...
- java.lang.NoSuchMethodException: com.hgkj.controler.action.UserAction.newsLoginAction()
java.lang.NoSuchMethodException: com.hgkj.controler.action.UserAction.newsLoginAction() 不久前在学习struts ...
- CodeForces - 1189 E.Count Pairs (数学)
You are given a prime number pp, nn integers a1,a2,…,ana1,a2,…,an, and an integer kk. Find the numbe ...
- 两种常见的缓存淘汰算法LFU&LRU
1. LFU 1.1. 原理 LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”. 1.2. ...
- poj/OpenJ_Bailian - 2528 离散化+线段树
传送门:http://bailian.openjudge.cn/practice/2528?lang=en_US //http://poj.org/problem?id=2528 题意: 给你n长海报 ...
- .Net Core解除文件上传大小限制
一共要修改两处地方: \Startup.cs public void ConfigureServices(IServiceCollection services) { services.AddMvc( ...
- Hibernate映射文件详解(News***.hbm.xml)二
转自 http://blog.csdn.net/a9529lty/article/details/6454924 一.hibernate映射文件的作用: Hibernate映射文件是Hibernate ...
- python监控模块
pip install psutil 获取内存信息: >>> import psutil >>> mem = psutil.virtual_memory() #获取 ...
- Java面向对象程序设计第7章1-8
Java面向对象程序设计第7章1-8 1."程序中凡是可能出现异常的地方必须进行捕获或拋出",这句话对吗? 不对. 异常分两类,runtime异常和非runtime异常. runt ...