原理:设置一个时间戳,默认1640995200L。设置序列号32位为默认值。将时间戳和序列号拼接。

注意:该id生成器需要配合redis使用,基于redis自增长插入记录实现该功能。

public class RedisIdWorker {
    /**
     * 开始时间戳
     */
    private static  long BEGIN_TIMESTAMP = 1640995200L;//2022.1.1.0.0.0
    /**
     * 序列号的位数
     */
    private static  int COUNT_BITS = 32;

    public static long getBeginTimestamp() {return BEGIN_TIMESTAMP; }

    public static void setBeginTimestamp(long beginTimestamp) {BEGIN_TIMESTAMP = beginTimestamp;}

    public static int getCountBits() { return COUNT_BITS; }

    public static void setCountBits(int countBits) {COUNT_BITS = countBits;}

    private StringRedisTemplate stringRedisTemplate;

    public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    public long nextId(String keyPrefix) {
        // 1.生成时间戳
        LocalDateTime now = LocalDateTime.now();
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
        long timestamp = nowSecond - BEGIN_TIMESTAMP;

        // 2.生成序列号
        // 2.1.获取当前日期,精确到天
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        // 2.2.自增长
        long count = stringRedisTemplate.opsForValue().increment("id:" + keyPrefix + ":" + date);

        // 3.拼接并返回(二进制将31位时间戳向左移32位,序列号或运算。)
        return timestamp << COUNT_BITS | count;
    }

    //计算某年某月某日某时的时间戳。
    public long timeStamp(Integer year,Integer month,Integer day, Integer hour,Integer minute){
        LocalDateTime time = LocalDateTime.of(year,month,day,hour,minute,0);
        return time.toEpochSecond(ZoneOffset.UTC);
    }