</pre><pre name="code" class="java">先上代码。
package com.yundaex.open.basic;
public final class YYMMDDDUtil {
public static void main(String[] args) {
System.out.println(new YYMMDDDUtil().dateDecode("NJJJ"));
System.out.println(new YYMMDDDUtil().dateEncode("001231"));
}
private String MAX_YYMMDD = null;
public YYMMDDDUtil() {
MAX_YYMMDD = dateEncode("001231");
}
/**
* 压缩年月日
*
* @param yymmdd
* 日期
* @return 压缩后年月日
*/
public String dateEncode(String yymmdd) {
if (yymmdd == null || yymmdd.length() != 6) {
throw new IllegalArgumentException(yymmdd + " is not [yymmdd] formated");
}
int y1 = Integer.parseInt(yymmdd.substring(0, 1));
int y2 = Integer.parseInt(yymmdd.substring(1, 2));
if (y1 == 0 && y2 == 0) {
y1 = 10;
}
int mm = Integer.parseInt(yymmdd.substring(2, 4));
if (mm > 12 || mm < 1) {
throw new IllegalArgumentException(yymmdd.substring(2, 4) + " is not [mm] formated");
}
int dd = Integer.parseInt(yymmdd.substring(4, 6));
if (dd > 31 || dd < 1) {
throw new IllegalArgumentException(yymmdd.substring(4, 6) + " is not [dd] formated");
}
// 转换成10进制
int total = y1 * (10 * 12 * 31) + y2 * (12 * 31) + (mm - 1) * (31) + (dd - 1);
return int2str(total);
}
/**
* 10进制转换成压缩后形式
*
* @param num
* @return
*/
private String int2str(int num) {
int ext = 0;
ext = num % (factor * factor * factor);
int n1 = (num - ext) / (factor * factor * factor);
num = ext;
ext = num % (factor * factor);
int n2 = (num - ext) / (factor * factor);
num = ext;
ext = num % (factor);
int n3 = (num - ext) / factor;
int n4 = ext;
return "" + chars[n1] + chars[n2] + chars[n3] + chars[n4];
}
private int factor = 14;
private char[] chars = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N' };
/**
* 解压年月日
*
* @param ssss
* 四位压缩的年月日
* @return 解压压后年月日
*/
public String dateDecode(String ssss) {
if (ssss == null || ssss.length() != 4) {
throw new IllegalArgumentException("\"" + ssss + "\" is not [ssss] formated");
}
if (ssss.compareTo(MAX_YYMMDD) > 0) {
throw new IllegalArgumentException("\"" + ssss + "\" has exceed MAX_YYMMDD: " + MAX_YYMMDD);
}
int total = 0;
int f = factor * factor * factor;
// 转换到10进制
for (char c : ssss.toCharArray()) {
for (int j = 0; j < chars.length; j++) {
if (c == chars[j]) {
total += j * f;
f = f / factor;
break;
}
if (j == chars.length - 1) {
throw new IllegalArgumentException(c + " in \"" + ssss + "\" is not illeagle");
}
}
}
return int2date(total);
}
/**
* 10进制转换成年月日
*
* @param num
* @return
*/
private String int2date(int num) {
int ext = 0;
ext = num % (10 * 12 * 31);
int n1 = (num - ext) / (10 * 12 * 31);
num = ext;
ext = num % (12 * 31);
int n2 = (num - ext) / (12 * 31);
num = ext;
ext = num % (31);
int n3 = (num - ext) / 31 + 1;
int n4 = ext + 1;
if (n1 == 10 && n2 == 0) {
n1 = 0;
}
return "" + n1 + n2 + formatInt(n3) + formatInt(n4);
}
private String formatInt(int num) {
if (num < 10) {
return "0" + num;
}
return "" + num;
}
}
我的思路是根据以前学过的10进制和2进制的互转,只不过不同的是,这里的YYMMDD中,Y表示0-9,这一位就相当于1个10进制位,而MM这两位相当于12进制位,DD相当于32进制位。
因为加减乘除算法都是建立在10进制的基础上,所以中间都要变换成为10进制,这时候,YYMMDD能够表示的最大的10进制数字也就是10*12*31-1了,再将它转换成诸如16进制,15进制,14进制都可以,(经过测试,用4位字符表示的话,至少需要有14个元字符)。
这里的chars是可以自由定义的,而且还有一个factor来控制进制。
最后说明下这个算法的利用场景:
在大数据的年代,项目中生成流水号,可能会因为系统一轮分配结束,重新初始化流水号的时候,到底流水号冲突,会产生财务问题。所以需要在流水号之前加上了一个与年月日一一对应的字符表示,最后为了节省字符,就采取了这种算法。