Java初学笔记(七):日期与时间

本文详细介绍了Java中处理时间和日期的API,包括旧API(如Date、Calendar、TimeZone)和新API(如java.time包下的LocalDateTime、ZonedDateTime、Instant等)。文章对比了新旧API的优缺点,并提供了实例代码,帮助开发者更好地理解和使用Java时间日期处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

时间和日期

Java程序中, 时间戳(Epoch Time)通常是用long(64位)表示的毫秒数, 获取方法是System.currentTimeMillis()
标准库API: Java有新旧两套处理时间和日期的API

  • 旧API在java.util包里, 主要包括Date, Calendar, TimeZone
  • 新API在java.time包里, 主要包括LocalDateTime, ZonedDateTime, ZoneId
    由于遗留代码问题, 旧API也要了解

旧API

Date
    Date d = new Date();    // 获取当前时间(Date内部使用long来存储)
    d.getYear();            // 获取1900年开始年数, 实际年份要+1900
    d.getMonth();           // 获取月份(0-11), 实际月份要+1
    d.getDate();            // 获取日份(1-31), 正常使用, 注意不是getDay
    d.toString();           // 转换成标准时间字符串
    d.toGMTString();        // 转换成GMT时区
    d.toLocaleString();     // 转换成本地时间, 注意不是local是locale

自定义显示格式:

  • yyyy:年
  • MM:月
  • EE: 周
  • dd: 日
  • HH: 小时
  • mm: 分钟
  • ss: 秒
  • zz: 时区
    字母越多, 显示越多/越复杂
import java.text.SimpleDateFormat;
Date d = new Date();
var sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(d));

Date不能任意转换时区, 也不能进行时间加减

Calendar
  1. Calendar可以用于获取并设置年、月、日、时、分、秒,它和Date比,主要多了一个可以做简单的日期和时间运算的功能
    get(int field)

    Calendar c = Calendar.getInstance();    // 获取当前时间, 唯一Calendar的获取方式
    int y = c.get(Calendar.YEAR);           // 获取年份, 正常使用
    int m = 1 + c.get(Calendar.MONTH);      // 获取月份(0-11), 实际月份需要+1
    int d = c.get(Calendar.DAY_OF_MONTH);   // 获取日份, 正常使用
    int w = c.get(Calendar.DAY_OF_WEEK);    // 获取星期(1-7), 注意从周日开始算
    int hh = c.get(Calendar.HOUR_OF_DAY);   // 获取时
    int mm = c.get(Calendar.MINUTE);        // 获取分
    int ss = c.get(Calendar.SECOND);        // 获取秒
    int ms = c.get(Calendar.MILLISECOND);   // 获取毫秒
    
  2. 可以设置特定的时间, 设置前可以使用c.clear()清除所有字段, 设置时日期格式同获取时一样, 对某字段设置set(int field, int value),也可以直接设置完整时间setTime(Data d)

  3. c.getTime()Calendar转换成Date类型

TimeZone
    TimeZone tzDefault = TimeZone.getDefault();                 // 当前时区
    TimeZone tzGMT9 = TimeZone.getTimeZone("GMT+09:00");        // GMT+9:00时区
    TimeZone tzNY = TimeZone.getTimeZone("America/New_York");   // 纽约时区
    System.out.println(tzDefault.getID());                      // Asia/Shanghai
    System.out.println(tzGMT9.getID());                         // GMT+09:00
    System.out.println(tzNY.getID());                           // America/New_York
  1. 时区的唯一标识是以字符串表示的ID

  2. 获取指定TimeZone也是以ID参数获取

  3. TimeZone.getAvailableIDs()可以列出所有有效的时区ID

  4. 时区转换:

    // 当前时间:
    Calendar c = Calendar.getInstance();
    // 清除所有:
    c.clear();
    // 设置为北京时区:
    c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
    // 设置年月日时分秒:
    c.set(2019, 10, 20, 8, 15, 0);  // 注意11月
    // 显示时间:
    var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));  // 指定时区
    System.out.println(sdf.format(c.getTime()));
    
  5. 利用Calendar进行时区转换步骤:

    1. 清除所有字段
    2. 设定指定时区
    3. 设定日期和时间
    4. 创建SimpleDateFormat并设定目标时区
    5. 格式化获取的Date对象(注意Date对象无时区信息, 时区信息存储在SimpleDateFormat中)
  6. 时间加减:

     c.add(Calendar.DAY_OF_MONTH, 5);    // 加5天
     c.add(Calendar.HOUR_OF_DAY, -2);    // 减2小时
    

java.time

java.time.*修复了年月和周的数字对应

  • 本地日期和时间: LocalDateTime, LocalDate, LocalTime
  • 带时区的日期和时间: ZonedDateTime
  • 时刻: Instant
  • 时区: ZoneId, ZoneOffset
  • 时间间隔: Duration
  • 格式化: DateTimeFormatter
  • 时间类型属于不变类
LocalDateTime
  1. 本地时间, 默认格式按ISO 8601规定输出:

    • LocalDateTime.now() -> 2020-03-10T10:03:12.500267
    • LocalDate.now() -> 2020-03-10
    • LocalTime.now() -> 10:03:12.500267
  2. 时间日期转换LocalDateTime dt = LocalDateTime.now():

    • LocalDate d = dt.toLocalDate()
    • LocalTime t = dt.toLocalTime()
    • LocalDate ld = LocalDate.of(2020, 3, 10)
    • LocalTime lt = LocalTime.of(10, 22[, 33])
    • LocalDateTime ldt = ld.atStartOfDay()
    • LocalDateTime ldt = LocalDateTime.of(2020, 3, 10, 10, 37, 59)
    • LocalDateTime ldt = LocalDateTime.of(ld, lt)
    • LocalDateTime sdt = LocalDateTime.parse("2020-3-10T15:16:17")
    • LocalDate sd = LocalDate.parse("2020-3-10")
    • LocalTime st = LocalTime.parse("15:16:17")
    • DateTimeFormatter.ofPattern(String)时间格式化, 解析时间字符串时可以传入指定的格式进行解析
  3. ISO 8601标准规定日期和时间的分隔符为T, 标准格式:

    • 日期:yyyy-MM-dd
    • 时间:HH:mm:ss
    • 带毫秒的时间:HH:mm:ss.SSS
    • 日期和时间:yyyy-MM-dd’T’HH:mm:ss
    • 带毫秒的日期和时间:yyyy-MM-dd’T’HH:mm:ss.SSS
  4. 时间运算(三个时间类都可以用):

    • plusDays(int): 天数加
    • minusMonths(int): 月份减
    • minusHours(int)
    • withYear()
    • withMonth()
    • withDayOfMonth()
    • withHour()
    • withMinute()
    • withSecond()
    • 运算结果会自动调整
    • 通用的with()可以进行更复杂的运算:
      • import java.time.temporal.*;
      • LocalDate.now().with(TemporalAdjusters.lastDayOfMonth())
      • LocalDate.now().with(TemporalAdjusters.firstDayOfNextMonth())
      • LocalDate.now().with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY))
    • 判断时间的先后(同类型比较):
      • isBefore()
      • isAfter()
    • 因为LocalDateTime没有时区, 所以不能与时间戳进行转换
Duration和Period
  1. Duration表示时间(LocalDateTime/LocalTime)的间隔, 常用格式为P...H...M...S, 表示间隔时分秒(可正可负):

    • Duration d = Duration.between(LocalTime.of(12, 13, 14), LocalTime.of(11, 12, 13));`
      
    
    
  2. Period表示日期(LocalDate)间隔, 常用格式为P...M...D, 表示间隔月日:

    • Period p = LocalDate.of(2019, 11, 19).until(LocalDate.of(2020, 1, 9));
      
    
    
  3. 创建时间间隔:

     Duration d1 = Duration.ofHours(10);         // P10H
     Duration d2 = Duration.parse("P1DT2H3M");   // 可以添加D表示天数, 自动换算成H
    
ZonedDateTime
  1. ZonedDateTime可以可以看成是LocalDateTimeZoneId的结合
  2. 创建:
    • ZonedDateTime.now(): 默认时区
    • ZonedDateTime.now(ZoneId.of("America/New_York"))
    • LocalDateTime.now().atZone(ZoneId.systemDefault())
    • LocalDateTime.now().atZone(ZoneId.of("America/New_York"))
  3. 时区转换:
    • ZonedDateTime.now().withZoneSameInstant(ZoneId.of("America/New_York"))
    • 时区转换涉及夏令时, 转换后的日期和时间会相应调整
    • LocalDateTime ldt = ZonedDateTime.now().toLocalDateTime()直接丢弃时区信息, 变成本地时间
  4. ZonedDateTime也提供了时间的加减操作
DateTimeFormatter
  1. DateTimeFormatter可以对LocalDateTimeZonedDateTime进行时间格式化
  2. DateTimeFormatter是不可变类, 而且是线程安全的, 可以一次获取到处引用
  3. 创建:
    • var f = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    • var f = DateTimeFormatter.ofPattern("E, yyyy-MM-dd HH:mm", Locale.US);
  4. f.format(ZonedDateTime.now())
Instant
  1. java.time中用Instant表示时间戳, 效果与System.currentTimeMillis()类似, 但是多了一个纳秒级的精度
  2. Instant.now()获取当前时间戳
  3. Instant.now().getEpochSecond(): 秒
  4. Instant.now().toEpochMilli(): 毫秒
  5. 创建和转换:
    • Instant ins = Instant.ofEpochSecond(1567891234)
    • ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault())
    • ZonedDateTime.ofInstant(Instant ins, ZoneId zid)
新旧API转换

传送门


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值