time.c 的Java实现(从timestamp计算年月日时分秒等数值)

时间:2021-12-09 16:21:14

time.c的Java实现

public class GMT {
    public static final int EPOCH_YEAR = 1970;
    public static final int[][] MONTH_DAYS = {
            {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
            {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    };
    public static final long MSECS_DAY = 1000*3600*24L;

    private long timestamp;
    private int mil;
    private int sec;
    private int min;
    private int hour;
    private int wday;
    private int mday;
    private int yday;
    private int mon;
    private int year;

    public GMT(long timestamp, long shift) {
        this.timestamp = timestamp + shift;
        long dayclock = (this.timestamp % MSECS_DAY) / 1000L;
        long dayno = this.timestamp / MSECS_DAY;

        mil = (int) (this.timestamp % 1000L);
        sec = (int) (dayclock % 60);
        min = (int) ((dayclock % 3600) / 60);
        hour = (int) (dayclock / 3600);
        wday = (int) ((dayno + 4) % 7);
        while (dayno >= yearDays(EPOCH_YEAR + year)) {
            dayno -= yearDays(EPOCH_YEAR + year);
            year++;
        }
        year = EPOCH_YEAR + year;
        yday = (int)dayno;
        int[] monthDays = leapYear(year) ? MONTH_DAYS[1] : MONTH_DAYS[0];
        while (dayno >= monthDays[mon]) {
            dayno -= monthDays[mon];
            mon++;
        }
        mon++;
        mday = (int)dayno + 1;
    }

    public long toLongInteger() {
        return year     * 10000000000000L
                + mon   * 100000000000L
                + mday  * 1000000000L
                + hour  * 10000000L
                + min   * 100000L
                + sec   * 1000L
                + mil;
    }

    private static int yearDays(int year) {
        return leapYear(year) ? 366 : 365;
    }

    private static boolean leapYear(int year) {
        return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
    }

    public int getMil() { return mil; }
    public void setMil(int mil) { this.mil = mil; }
    public int getSec() { return sec; }
    public void setSec(int sec) { this.sec = sec; }
    public int getMin() { return min; }
    public void setMin(int min) { this.min = min; }
    public int getHour() { return hour; }
    public void setHour(int hour) { this.hour = hour; }
    public int getWday() { return wday; }
    public void setWday(int wday) { this.wday = wday; }
    public int getMday() { return mday; }
    public void setMday(int mday) { this.mday = mday; }
    public int getYday() { return yday; }
    public void setYday(int yday) { this.yday = yday; }
    public int getMon() { return mon; }
    public void setMon(int mon) { this.mon = mon; }
    public int getYear() { return year; }
    public void setYear(int year) { this.year = year; }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        int total = 500000;
        for (int i = 0; i < total; i ++) {
            GMT gmt = new GMT(System.currentTimeMillis(), 1000L*3600*8);
            System.out.println(gmt.toLongInteger());
        }
        long duration = System.currentTimeMillis() - start;
        System.out.println("Total: " + duration + "ms, " + total/duration + "/ms");
    }
}

可以作为Snowflake ID generator的前缀生成器, 好处是易于业务手工识别, 缺点是速度较慢, 与直接使用二进制的机制差一个数量级(sf默认实现是20k/ms, 这个只有2k/ms).

在带I/O的情况下, 能达到150/ms的生成速度, 比使用SimpleDateFormat的效率高很多, 还是可以使用的, 如果使用SimpleDateFormat的话, 只有30/ms的速度.

 

Update:

用这个改造出来的...TimeflakeId是类似于这样的

public class TimeflakeId {
    private final static int SEQUENCE_MASK = 999;
    private final RecyclableAtomicInteger atomic = new RecyclableAtomicInteger();
    private long lastTimestamp = -1L;
    private long lastTsFormatted = -1L;

    public long nextId() {
        long timestamp = millisecond();
        if (timestamp < lastTimestamp) {
            throw new IllegalArgumentException(
                    String.format("Wait for %d milliseconds", lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            int sequence = atomic.incrementAndRecycle(SEQUENCE_MASK);
            if (sequence == 0) {
                timestamp = waitTilNextMillis(lastTimestamp);
                lastTimestamp = timestamp;
                lastTsFormatted = getFormattedTimestamp();
            }
            return lastTsFormatted * 1000 + sequence;
        } else {
            atomic.set(0);
            lastTimestamp = timestamp;
            lastTsFormatted = getFormattedTimestamp();
            return lastTsFormatted * 1000;
        }
    }

    private long waitTilNextMillis(final long lastTimestamp) {
        long timestamp;
        for (;;) {
            timestamp = this.millisecond();
            if (timestamp > lastTimestamp) {
                return timestamp;
            }
        }
    }

    private long millisecond() {
        return System.currentTimeMillis();
    }

    public static final int EPOCH_YEAR = 1970;
    public static final long[][] MONTH_DAYS = {
            {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
            {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    };
    public static final long MSECS_DAY = 1000*3600*24L;

    private long getFormattedTimestamp() {
        long ts = lastTimestamp + 1000L*3600*8;
        long dayclock = (ts % MSECS_DAY) / 1000L;
        long dayno = ts / MSECS_DAY;

        long mil = ts % 1000L;
        long sec = dayclock % 60;
        long min = (dayclock % 3600) / 60;
        long hour = dayclock / 3600;
        long year = 0;
        while (dayno >= yearDays(EPOCH_YEAR + year)) {
            dayno -= yearDays(EPOCH_YEAR + year);
            year++;
        }
        long[] monthDays = leapYear(EPOCH_YEAR + year) ? MONTH_DAYS[1] : MONTH_DAYS[0];
        int mon = 0;
        while (dayno >= monthDays[mon]) {
            dayno -= monthDays[mon];
            mon++;
        }
        mon++;
        long mday = dayno + 1;

        return ((year > 30)? year - 30 : year + 70)     * 10000000000000L
                + mon   * 100000000000L
                + mday  * 1000000000L
                + hour  * 10000000L
                + min   * 100000L
                + sec   * 1000L
                + mil;
    }

    private static int yearDays(long year) {
        return leapYear(year) ? 366 : 365;
    }

    private static boolean leapYear(long year) {
        return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
    }

    public static void main(String[] args) {
        TimeflakeId worker = new TimeflakeId();
        long start = System.currentTimeMillis();
        int total = 50000;
        for (int i = 0; i < total; i ++) {
            //System.out.println(worker.nextId());
            worker.nextId();
        }
        long duration = System.currentTimeMillis() - start;
        System.out.println("Total: " + duration + "ms, " + total/duration + "/ms");
    }
}

RecyclableAtomicInteger 的实现

public class RecyclableAtomicInteger extends AtomicInteger
{
    /**
     * Atomically increments by one the current value, or return
     * to zero if the value exceeds threshold
     *
     * @return the updated value
     */
    public final int incrementAndRecycle(int threshold) {
        for (;;) {
            int current = get();
            int next = (current + 1) % threshold;
            if (compareAndSet(current, next))
                return next;
        }
    }
}