time.c 的Java实现(从timestamp计算年月日时分秒等数值)
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; } } }