YYMMDD转换成4位字符压缩表示算法java实现——应用各位不等进制的思想

</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来控制进制。



  最后说明下这个算法的利用场景:

      在大数据的年代,项目中生成流水号,可能会因为系统一轮分配结束,重新初始化流水号的时候,到底流水号冲突,会产生财务问题。所以需要在流水号之前加上了一个与年月日一一对应的字符表示,最后为了节省字符,就采取了这种算法。



猜你喜欢

转载自blog.csdn.net/u014112608/article/details/34536531