问题:
存储一个日期的序列,例如保存用户一年的登录时间序列,20140201,20130102这样两个日期,如果用INT那么需要八个字节,用STRING就更多了。
解决:
通过bit来存储一天,具体的组织形式是这样的
struct daybits {
Year[] before_years;
Year[] after_years;
}
struct Year {
Quarter q1;
Quarter q2;
Quarter q3;
Quarter q4;
}
struct Quarter {
byte[] bytes
}
日期压缩过程
daybits中有若干个年,以2013做为轴分别存储在before和after years数组里。每个年有四个季度,每个季度中有个byte数组,数组中的每个字节代表8天,bytes[i] 代表这个季度的第i*8 - (i+1) * 8天,其实就是Java BitSet不用INT存储,用BYTE存储。还有一点和JAVA的BitSet不同的是,Quarter中的byte数组,使用了延迟加载,当在某一个季度登录过,这个季度才分配存储空间,并且,分配的空间也不是每次把一个季度中的90天(假设一个月30天)全都分配了(最多也就是分配12个字节可以表示96天,够一个季度的天数了),而是最大需要多少天分配多少字节,如果这个季度之后的天又需要存储,那么重新分配空间再memcpy。通过这种分季度,节约了很大一部分的存储。如果一个季度登录过三天应该就比用INT存储登录时间要高效,如果是只登录了一天,而且是在季度的最后一天,那就亏了。
例子
存储20140105
2014年存储在after_years[1]中
1月存储year的q1中
计算2014年1月1日的时间戳,计算2014年1月5日的时间戳,相减除以3600*24秒得到是1月的第五天
存储在byte[0],且值为二进制的00010000,代表第五天
反解的时候通过月的第N天解出是几月几日有点麻烦,如果有Java Calendar处理这个还比较简单,不过这个东西可以提前计算好