在Java开发中,时间的显示与处理是常见需求,无论是日志记录、业务逻辑处理还是用户界面展示,都离不开对时间的操作,Java提供了多种时间处理方式,从早期的Date、Calendar类到Java 8引入的java.time包,功能不断完善,使用体验也持续优化,本文将详细介绍Java中显示时间的多种方法,涵盖基础API、格式化技巧、时区处理及高级特性,帮助开发者根据实际场景选择合适的方案。

基础时间获取:System.currentTimeMillis()与Date类
Java中最基础的时间获取方式是通过System.currentTimeMillis()方法,该方法返回自1970年1月1日00:00:00 UTC(Unix纪元)以来的毫秒数,是一个long类型的时间戳,这种方式适合需要高精度时间戳的场景,例如性能监控、数据加密等。
long timestamp = System.currentTimeMillis();
System.out.println("当前时间戳:" + timestamp);
若需将时间戳转换为可读的时间格式,可结合Date类使用。Date类表示特定的瞬间,精确到毫秒,其无参构造方法会自动获取当前时间:
Date date = new Date();
System.out.println("默认格式时间:" + date); // 输出如:Wed Oct 05 10:20:30 CST 2023
Date类提供了toString()方法,默认输出符合本地语言环境的日期时间格式,但可定制性较差。Date类中的许多方法(如getYear()、getMonth())已标记为过时,官方推荐使用Java 8的新API替代。
格式化显示:SimpleDateFormat与DateTimeFormatter
为了将时间显示为自定义格式,Java提供了格式化工具,在Java 8之前,SimpleDateFormat是主要的格式化类,它通过模式字符串(如"yyyy-MM-dd HH:mm:ss")来定义日期时间的格式:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
String formattedTime = sdf.format(new Date());
System.out.println("自定义格式时间:" + formattedTime); // 输出如:2023年10月05日 10时20分30秒
SimpleDateFormat的模式字符中,yyyy代表4位年份,MM代表月份(区分大小写,mm代表分钟),dd代表日期,HH代表24小时制小时,hh代表12小时制小时。

但需注意,SimpleDateFormat是非线程安全的,在多线程环境下直接共享实例可能导致数据错乱,若需在多线程中使用,可通过ThreadLocal为每个线程创建独立实例,或每次调用时新建对象。
Java 8引入了DateTimeFormatter类,作为SimpleDateFormat的替代品,它不仅线程安全,还支持更丰富的格式化模式和国际化场景。DateTimeFormatter常与java.time包下的日期时间类配合使用,
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
String formattedTime = dtf.format(now);
System.out.println("Java 8格式化时间:" + formattedTime); // 输出如:2023-10-05 10:20:30
DateTimeFormatter还支持预定义格式(如ISO_LOCAL_DATE、ISO_LOCAL_TIME),可直接调用DateTimeFormatter.ISO_LOCAL_DATE.format(LocalDate.now())输出标准格式日期(如2023-10-05)。
时区处理:TimeZone与ZonedDateTime
跨时区应用中,时间显示需考虑时区问题,Java中通过TimeZone类表示时区,早期可通过TimeZone.setDefault()设置默认时区,但全局修改可能影响其他模块,推荐在具体操作时显式指定时区,使用SimpleDateFormat时:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String nyTime = sdf.format(new Date());
System.out.println("纽约时间:" + nyTime);
Java 8的java.time包提供了更完善的时区支持。ZoneId表示时区标识(如"Asia/Shanghai"、"UTC"),ZonedDateTime则带有时区的日期时间类,可直接获取不同时区的时间:

ZoneId shanghaiZone = ZoneId.of("Asia/Shanghai");
ZoneId newYorkZone = ZoneId.of("America/New_York");
ZonedDateTime shanghaiTime = ZonedDateTime.now(shanghaiZone);
ZonedDateTime newYorkTime = shanghaiTime.withZoneSameInstant(newYorkZone);
System.out.println("上海时间:" + shanghaiTime); // 输出如:2023-10-05T10:20:30+08:00[Asia/Shanghai]
System.out.println("纽约时间:" + newYorkTime); // 输出如:2023-10-04T22:20:30-04:00[America/New_York]
withZoneSameInstant()方法可在保持时间点不变的情况下转换时区,适合跨时区业务场景(如全球会议时间计算)。
高级时间API:Java 8的日期时间库
Java 8引入的java.time包重新设计了日期时间API,解决了早期类的线程安全性和易用性问题,核心类包括:
LocalDate:只包含日期(年月日),如LocalDate.now()获取当前日期,LocalDate.of(2023, 10, 5)指定日期。LocalTime:只包含时间(时分秒毫秒),如LocalTime.now()获取当前时间,LocalTime.of(10, 20, 30)指定时间。LocalDateTime:日期+时间(无时区),如LocalDateTime.now()获取当前日期时间,常用于本地业务逻辑。Instant:时间戳(秒+纳秒),如Instant.now()获取当前UTC时间戳,适合存储或传输。
这些类均为不可变对象,线程安全,且提供了丰富的计算方法(如plusDays()、minusHours()),计算未来3天的日期:
LocalDate today = LocalDate.now();
LocalDate futureDate = today.plusDays(3);
System.out.println("3天后日期:" + futureDate); // 输出如:2023-10-08
实用场景示例:常见时间显示需求实现
显示当前时间(带毫秒)
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
LocalDateTime now = LocalDateTime.now();
System.out.println("当前时间(毫秒):" + dtf.format(now)); // 输出如:2023-10-05 10:20:30.123
格式化时间戳(毫秒转日期)
long timestamp = 1696555230123L; // 示例时间戳
LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
System.out.println("时间戳转日期:" + dateTime); // 输出如:2023-10-05T10:20:30.123
计算时间差(如程序运行耗时)
Instant start = Instant.now();
// 模拟业务逻辑
Thread.sleep(1000);
Instant end = Instant.now();
Duration duration = Duration.between(start, end);
System.out.println("耗时:" + duration.getSeconds() + "秒"); // 输出:1秒
注意事项:线程安全与最佳实践
- 线程安全:
SimpleDateFormat非线程安全,多线程环境避免共享实例;DateTimeFormatter及java.time类均为线程安全,可放心使用。 - 避免过时API:
Date、Calendar的多数方法已过时,优先使用java.time包下的类。 - 时区规范:使用IANA时区ID(如
"Asia/Shanghai"),避免缩写(如"GMT+8"),因缩写可能存在歧义(如夏令时问题)。 - 精度选择:根据需求选择合适类型,如仅需日期用
LocalDate,需时间戳用Instant,需时区用ZonedDateTime。
Java中显示时间的方法从基础到高级,已形成完善的体系,开发者可根据项目需求(如Java版本、是否需要时区、线程安全要求等)选择合适的API,结合格式化工具和时区处理,灵活实现各种时间显示需求,掌握这些方法,不仅能提升代码的健壮性,还能避免因时间处理不当引发的潜在问题。

















