java+mysql 处理一天 24 小时时间问题

本贴最后更新于 2047 天前,其中的信息可能已经天翻地覆

问题描述

2 个广告在一天的 24 个时间段播放,我们将一天分为 24 个小时,播放用 1 表示,不播放用 0 表示。组成 24 位的 0 和 1 组成的字符串。数据库存储为一个整数,通过位运算判断新加广告与原有广告是否有时间冲突。

java 代码在整数和 24 位 0 和 1 的字符串转化


import org.apache.commons.lang3.StringUtils;

public class NumberUtil {
    /**
     * int整数转换为4字节的byte数组
     *
     * @param i  整数
     * @return byte数组
     */
    public static byte[] intToByte4(int i) {
        byte[] targets = new byte[4];
        targets[3] = (byte) (i & 0xFF);
        targets[2] = (byte) (i >> 8 & 0xFF);
        targets[1] = (byte) (i >> 16 & 0xFF);
        targets[0] = (byte) (i >> 24 & 0xFF);
        return targets;
    }

    /**
     * long整数转换为8字节的byte数组
     *
     * @param lo  long整数
     * @return byte数组
     */
    public static byte[] longToByte8(long lo) {
        byte[] targets = new byte[8];
        for (int i = 0; i < 8; i++) {
            int offset = (targets.length - 1 - i) * 8;
            targets[i] = (byte) ((lo >>> offset) & 0xFF);
        }
        return targets;
    }

    /**
     * short整数转换为2字节的byte数组
     *
     * @param s   short整数
     * @return byte数组
     */
    public static byte[] unsignedShortToByte2(int s) {
        byte[] targets = new byte[2];
        targets[0] = (byte) (s >> 8 & 0xFF);
        targets[1] = (byte) (s & 0xFF);
        return targets;
    }

    /**
     * byte数组转换为无符号short整数
     *
     * @param bytes   byte数组
     * @return short整数
     */
    public static int byte2ToUnsignedShort(byte[] bytes) {
        return byte2ToUnsignedShort(bytes, 0);
    }

    /**
     * byte数组转换为无符号short整数
     *
     * @param bytes
     *            byte数组
     * @param off
     *            开始位置
     * @return short整数
     */
    public static int byte2ToUnsignedShort(byte[] bytes, int off) {
        int high = bytes[off];
        int low = bytes[off + 1];
        return (high << 8 & 0xFF00) | (low & 0xFF);
    }

    /**
     * byte数组转换为int整数
     *
     * @param bytes
     *            byte数组
     * @param off
     *            开始位置
     * @return int整数
     */
    public static int byte4ToInt(byte[] bytes, int off) {
        int b0 = bytes[off] & 0xFF;
        int b1 = bytes[off + 1] & 0xFF;
        int b2 = bytes[off + 2] & 0xFF;
        int b3 = bytes[off + 3] & 0xFF;
        return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
    }
    public static byte[] getBooleanArray(byte b) {
        byte[] array = new byte[8];
        for (int i = 7; i >= 0; i--) {
            array[i] = (byte)(b & 1);
            b = (byte) (b >> 1);
        }
        return array;
    }
    public static String byteToBit(byte b) {
        return ""
                + (byte) ((b >> 7) & 0x1) + (byte) ((b >> 6) & 0x1)
                + (byte) ((b >> 5) & 0x1) + (byte) ((b >> 4) & 0x1)
                + (byte) ((b >> 3) & 0x1) + (byte) ((b >> 2) & 0x1)
                + (byte) ((b >> 1) & 0x1) + (byte) ((b >> 0) & 0x1);
    }

    /**
     * 将24位01字符串转化为整数
     * @param timeSeq 24位01字符串
     * @return 整数
     */
    public static  int str2Int(String timeSeq){
        timeSeq = "00000000"+timeSeq;
        int ret = -1;
        if(StringUtils.isEmpty(timeSeq)){
            return ret;
        }
        int length = timeSeq.length();
        if (length!=32){
            return ret;
        }
        byte[] intByteArray = new byte[4];
        for(int i=0;i<4;i++){
            String tmp = timeSeq.substring(i*8,i*8+8);
            intByteArray[i] =(byte)Integer.parseInt(tmp,2);
        }
        ret = byte4ToInt(intByteArray,0);
        return ret;
    }

    /**
     * 将整数转化为01字符串
     * @param timeCout
     * @return
     */
    public static String int2Str(int timeCout){
        byte[] c = intToByte4(timeCout);
        return byteToBit(c[1])+byteToBit(c[2])+byteToBit(c[3]);
    }
    public  static void main(String[] args){
        String a = "000000010000000000010000";
        System.out.println("Output: "+a);
        System.out.println("Output: "+str2Int(a));
        int  b = str2Int(a);
        System.out.println("Output: "+int2Str(b));
    }
}

mysql 位运算

在 mysql 中,如果某条数据与其它数据存在一对多的关系,一般我们很自然的就会想到建立一个关系表。例如有一个景点信息的数据表,其结构如下:

字段名 说明
id int(主键)
name varchar(景点名)
province int(省份)
city int(城市)

每个景点包含很多属性,例如适合旅游的月份,我们一般的做法可能有两种:一种是增加一个 varchar 字段,每个月份之间用一个特殊符号分隔保存,例如“1,2,3,11,12”;另一种方法是建立一个关系表,如下:

字段名 描述
spots_id int(景点 ID)
month int(适合月份,取值 1-12)

第一种方法,查询极不方便,例如想查出适合 2 月份旅行的景点,就要使用 like 语句,效率极其低下。第二种方法,只适合景点属性较少的场合。如果景点还包含其它属性,例如“高山”、“草原”之类的分类属性,还有“美食”、“购物”等的主题属性,就要根据每个属性去建立一个关系表,扩展极其不便,查询的时候可能需要联表查询,也影响效率。

我们知道,PHP 当中的错误级别常量,是根据二进制位特性而确定的一个个整数,可以简单的通过位运算定制 PHP 的错误报告。我们也可以将其应用到 mysql 当中,还是以上面的景点表为例,我们增加一个字段,其结构如下:

字段名 描述
id int(主键)
name varchar(景点名)
province int(省份)
city int(城市)
month int(适合旅行月份)

其建表语句为:

CREATE TABLE `spots` (

  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '景点ID',
  `name` varchar(50) NOT NULL COMMENT '景点名称',
  `province` int(5) unsigned NOT NULL COMMENT '景点所在省份',
  `city` int(11) unsigned NOT NULL COMMENT '景点所属城市',
  `month` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '适合旅行的月份',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`),
  KEY `location` (`province`,`city`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='景点信息表'

注意:在这里不能使用 1-12 的数字来表示月份,而是使用 1,2,4,8,16,32,64,128,512,1024,2048,4096 来表示。

以下为使用技巧:

  • 当我们需要查询某个月份的景点时,例如查询 3 月份的景点,可使用以下语句:
SELECT * FROM `spots` WHERE `month` & 4 = 4
  • 当设置某个景点适合某个月份时,例如设置 4325 的景点适合 2 月份,可使用下面的语句:
UPDATE `spots` SET `month` = `month` | 2 WHERE `id` = 4325
  • 当取消设置某个景点的月份时,可使用下面的语句:
UPDATE `spots` SET `month` = `month` ^ 2 WHERE `id` = 4325
  • 查询同时适合多个月份的数据,例如需要查询设置了 11,12,1 月份的景点,将其三个月份对应的数值加起来,结果为 6146,然后使用这个数值进行查询:
SELECT * FROM `spots` WHERE `month` & 6146 = 6146
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3167 引用 • 8207 回帖
  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    675 引用 • 535 回帖
  • 24hours
    1 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...