三種時間表達形式
| 形式 | 類別/方法 | 特點 | 適用場景 |
| 長整數毫秒數 | System.currentTimeMillis() | UTC 1970-01-01 00:00:00 至今毫秒數、唯一可直接比較大小、運算差值、跨平台傳輸標準 | 時間差計算、排序、網路傳輸、RMS 儲存 |
| Date 物件 | new Date(), new Date(millis) | 不可變、封裝毫秒數、提供 toString() 固定格式、無格式化能力 | API 介面傳遞、DateField 互操作 |
| Calendar 物件 | Calendar.getInstance() | 可變、提供年/月/日/時/分/秒/星期欄位存取與運算、支援時區 | 日期運算、格式化、解析、UI 顯示邏輯 |
核心互轉操作
1. 長整數 → Date
long now = System.currentTimeMillis();
Date date = new Date(now); // 最常用
2. Date → Calendar
Date date = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date); // 關鍵步驟
3. Calendar → Date → 長整數
Calendar cal = Calendar.getInstance();
// ... 修改欄位 ...
Date date = cal.getTime();
long millis = date.getTime(); // 或 cal.getTimeInMillis() (MIDP 2.0)
Calendar 日期運算實戰
取得當前日期時間欄位
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1; // +1 修正 0-based
int day = cal.get(Calendar.DATE);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 1=Sun
日期加減運算 (add/roll)
// 加 7 天
cal.add(Calendar.DATE, 7);
// 減 1 個月 (roll 不進位年份,add 會進位)
cal.roll(Calendar.MONTH, -1); // 1月 roll -1 → 12月,年份不變
cal.add(Calendar.MONTH, -1); // 1月 add -1 → 去年12月
// 設定具體日期
cal.set(2024, 11, 25); // 2024-12-25 (月份 0-based)
cal.set(2024, 11, 25, 18, 30, 0); // 含時間
比較兩個日期
Calendar cal1 = Calendar.getInstance();
cal1.set(2024, 0, 1); // 2024-01-01
Calendar cal2 = Calendar.getInstance();
cal2.set(2024, 11, 31); // 2024-12-31
// 方式一:比較毫秒數 (最簡單)
long diffMs = cal2.getTimeInMillis() - cal1.getTimeInMillis();
long diffDays = diffMs / (24*60*60*1000);
// 方式二:Calendar.before/after/equals
if (cal1.before(cal2)) { /* cal1 較早 */ }
實用工具類整合
public class TimeUtil {
private TimeUtil() {}
// 當前毫秒數
public static long now() {
return System.currentTimeMillis();
}
// 毫秒數 → "yyyy-MM-dd HH:mm:ss"
public static String format(long ms) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(ms));
StringBuffer sb = new StringBuffer();
sb.append(cal.get(Calendar.YEAR)).append('-');
append2(sb, cal.get(Calendar.MONTH)+1).append('-');
append2(sb, cal.get(Calendar.DATE)).append(' ');
append2(sb, cal.get(Calendar.HOUR_OF_DAY)).append(':');
append2(sb, cal.get(Calendar.MINUTE)).append(':');
append2(sb, cal.get(Calendar.SECOND));
return sb.toString();
}
// "yyyy-MM-dd HH:mm:ss" → 毫秒數
public static long parse(String s) {
try {
int y = Integer.parseInt(s.substring(0,4));
int m = Integer.parseInt(s.substring(5,7))-1;
int d = Integer.parseInt(s.substring(8,10));
int h = Integer.parseInt(s.substring(11,13));
int mi = Integer.parseInt(s.substring(14,16));
int se = Integer.parseInt(s.substring(17,19));
Calendar cal = Calendar.getInstance();
cal.set(y, m, d, h, mi, se);
return cal.getTime().getTime();
} catch (Exception e) {
return 0;
}
}
// 相對時間描述: "剛剛", "5分鐘前", "3小時前", "昨天", "5天前", "更早"
public static String relative(long pastMs) {
long diff = now() - pastMs;
if (diff < 60_000) return "剛剛";
if (diff < 3_600_000) return (diff/60_000) + "分鐘前";
if (diff < 86_400_000) return (diff/3_600_000) + "小時前";
if (diff < 172_800_000) return "昨天";
if (diff < 604_800_000) return (diff/86_400_000) + "天前";
return "更早";
}
private static StringBuffer append2(StringBuffer sb, int v) {
if (v < 10) sb.append('0');
sb.append(v);
return sb;
}
}
效能與記憶體優化建議
- 儲存/傳輸用長整數:8 位元組,無解析開銷,
RMS 直接 DataOutputStream.writeLong()。
- 避免頻繁建立 Calendar:
Calendar.getInstance() 較重,熱路徑改用長整數運算。
- Date 物件不可變:可安全共享,但無運算能力。
- 時區統一用 UTC 儲存:顯示時再轉本地時區 (
Calendar.getInstance() 自動用裝置時區)。
常見錯誤避雷
- ❌
Calendar.MONTH 0-based 忘記 +1/-1 → 月份錯誤。
- ❌ 用
Date.toString() 做顯示 → 格式固定 (如 "Jan 1 2024 12:00:00 GMT+08:00") 無法本地化。
- ❌
cal.getTimeInMillis() 在 MIDP 1.0 不存在 → 用 cal.getTime().getTime()。
- ❌ 跨時區傳輸
Date 物件而非毫秒數 → 接收端解析時區不一致。