日期的压缩存储daybits

问题:

存储一个日期的序列,例如保存用户一年的登录时间序列,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处理这个还比较简单,不过这个东西可以提前计算好

daybits的ToString

用"#",区分了上半区和下半区,用";"区分了每年,用","区分了每个季度,每个季度的bytes数组用base64编码。

原文地址:https://www.cnblogs.com/23lalala/p/4201153.html