将日期打包成int变量(Java)

时间:2014-04-14 18:24:56

标签: java algorithm

我遇到一个问题,要求我在 int变量中打包并解压缩日历日期。例如, 2007年2月20日将表示为folows:

  • 第一个 5位将保留当天
  • 下一个 4位 将保留本月
  • 最后一位将保留为年度

不幸的是,这是我所拥有的所有信息。有什么建议吗?

2 个答案:

答案 0 :(得分:3)

假设您正在使用32位有符号整数而忽略了符号位,并且“Calendaristic”意味着它是Calendar类型,那么以下方法应该可以解决这个问题:

public static int calToInt(Calendar cal) {
    int date = cal.get(Calendar.DAY_OF_MONTH) << 26;
    date |= cal.get(Calendar.MONTH) << 22;
    date |= cal.get(Calendar.YEAR);
    return date;
}

请注意,在Calendar的实现中,1月为0,如果要将1月表示为1,则确保将1添加到月份。另请注意,根据我的假设,您的年份有22位可以使用,因此将工作到2^22年,即4194304年,这应该是足够的。

<强>解释

您可能对其余部分不感兴趣,但即使我只提供粗略概述,我也想解释一下如何运作:

这种方法的工作方式是获取日历对象,获取日期并将其向左移动26位(这就是<< 26所做的),这意味着每月的日期最多为5位,这一天实际上将从32位int的第二位开始。这是为了避免第一位表示int是负数。如果你想填写完整的int然后改变22到23和26到27这将给你一些额外的一年(实际上是双倍)。与一年中的月份相同,它向左移动22位,以便在月份之后到达,最大消耗为4位。

|=运算符是按位运算符或赋值运算符。这样做是做一个按位或左边的东西,右边的东西分配给左边的东西。您可以在一行中执行此操作,但在我看来这更清楚,并且在字节代码方面将导致相同的事情。 OR的含义是,如果左侧或右侧的任何一位为1,则输出将在该位置包含1。这就是各个部分组合在一起的方式。

如果这一年确实大于规定的最大值,那就会搞砸了。

反向:

为了将此int返回到Calendar对象,可以使用以下方法:

private static Calendar intToCal(int date) {
    int day = date >> 26;
    int month = (date & 0b00000011110000000000000000000000) >> 22;
    int year = date & 0b00000000001111111111111111111111;
    return new GregorianCalendar(year, month, day);
}

这可以使用位掩码和位移。所以第一个只是移位26位(右边的所有其他位丢失,我们留下了一天。 随着月和日使用位掩码。我用二进制格式编写了这些内容,以使其更清楚地了解它的作用。我正在使用逻辑并且只获取我想要的int中的位。在这个月中,只剩下位掩码中标记为1的位(这将删除我们移位前的月份)。我已经摆脱了本月右边的位,但这不是必需的,并且会像第一次执行正确的位移时一样被切断。这一年只需要掩码,因为最后22位只是二进制形式的年份。同样,我忽略了符号位,但是在第一个中并不明确,如果传递了一个负数,它就会搞砸了。要解决此问题,必须在当天应用遮罩来掩盖符号位。

答案 1 :(得分:0)

根据您的要求更改顺序。

简单使用String#substring()Integer#toBinaryString()

int date = 20;
int month = 2;
int year = 2007;
String d = String.format("%0$5s", Integer.toBinaryString(date));
String m = String.format("%0$4s", Integer.toBinaryString(month));
String y = String.format("%0$23s", Integer.toBinaryString(year));

String str = y + m + d;
str = str.replace(' ', '0');
System.out.println(str);
int number = 0;
for (int i = 0; i < str.length(); i++) {
    number = (number << 1) | ((str.charAt(i) != '0') ? 1 : 0);
}
System.out.println(number);
System.out.println(Integer.toBinaryString(number));

从返回的号码

获取日期
String str1=String.format("%0$32s", Integer.toBinaryString(number)).replace(' ', '0');
int originalYear= Integer.parseInt(str1.substring(0,23), 2);
int originalMonth= Integer.parseInt(str1.substring(23,27), 2);
int originalDate= Integer.parseInt(str1.substring(27,32), 2);