Java中是否存在支持ISO 8601周的类及基础时间操作?
Java 11+ 处理ISO 8601周数据的方案
Java标准库(Java 11及以上)没有专门用于表示ISO 8601周格式(如2012-W48)的内置类,但可以通过两种方式实现你需要的时间操作:
方案一:基于LocalDate扩展实现
利用LocalDate结合DateTimeFormatter.ISO_WEEK_DATE解析,默认补全周内的具体日期(ISO周的第一天为周一,补-1即可),再通过标准时间API完成比较和间隔计算。
1. 解析周字符串
import java.time.LocalDate; import java.time.format.DateTimeFormatter; public class WeekUtils { private static final DateTimeFormatter ISO_WEEK_FORMATTER = DateTimeFormatter.ISO_WEEK_DATE; // 解析ISO周字符串,默认取周的第一天(周一) public static LocalDate parseToWeekStart(String weekStr) { return LocalDate.parse(weekStr + "-1", ISO_WEEK_FORMATTER); } }
2. 周比较
直接使用LocalDate的isBefore/isAfter方法,周起始日期的先后即可代表整个周的先后:
LocalDate weekAStart = WeekUtils.parseToWeekStart("2012-W48"); LocalDate weekBStart = WeekUtils.parseToWeekStart("2013-W03"); boolean weekABeforeWeekB = weekAStart.isBefore(weekBStart); // 返回true
3. 计算间隔周数
使用ChronoUnit.WEEKS.between方法计算两个周起始日的间隔:
import java.time.temporal.ChronoUnit; long weeksInterval = ChronoUnit.WEEKS.between(weekAStart, weekBStart); // 返回5
方案二:自定义ISOWeek类(更贴合需求)
如果需要更直观的周对象表示,可以自定义一个ISOWeek类,封装年份和周数,实现比较和间隔计算逻辑,完全基于Java标准库:
import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.time.temporal.WeekFields; import java.util.Objects; public class ISOWeek implements Comparable<ISOWeek> { private final int year; private final int week; private static final WeekFields ISO_WEEK_FIELDS = WeekFields.ISO; public ISOWeek(int year, int week) { if (week < 1 || week > ISO_WEEK_FIELDS.getWeekOfYear().range().getMaximum()) { throw new IllegalArgumentException("无效周数: " + week); } this.year = year; this.week = week; } // 从ISO周字符串解析 public static ISOWeek parse(String weekStr) { String[] parts = weekStr.split("-W"); if (parts.length != 2) { throw new IllegalArgumentException("无效ISO周格式: " + weekStr); } return new ISOWeek(Integer.parseInt(parts[0]), Integer.parseInt(parts[1])); } // 判断当前周是否早于另一个周 public boolean isBefore(ISOWeek other) { return compareTo(other) < 0; } // 判断当前周是否晚于另一个周 public boolean isAfter(ISOWeek other) { return compareTo(other) > 0; } // 计算与另一个周的间隔周数 public long weeksBetween(ISOWeek other) { LocalDate thisWeekStart = LocalDate.of(year, 1, 1) .with(ISO_WEEK_FIELDS.weekOfYear(), week) .with(ISO_WEEK_FIELDS.dayOfWeek(), 1); LocalDate otherWeekStart = LocalDate.of(other.year, 1, 1) .with(ISO_WEEK_FIELDS.weekOfYear(), other.week) .with(ISO_WEEK_FIELDS.dayOfWeek(), 1); return ChronoUnit.WEEKS.between(thisWeekStart, otherWeekStart); } @Override public int compareTo(ISOWeek other) { if (year != other.year) { return Integer.compare(year, other.year); } return Integer.compare(week, other.week); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ISOWeek isoWeek = (ISOWeek) o; return year == isoWeek.year && week == isoWeek.week; } @Override public int hashCode() { return Objects.hash(year, week); } @Override public String toString() { return String.format("%04d-W%02d", year, week); } }
使用示例
ISOWeek weekA = ISOWeek.parse("2012-W48"); ISOWeek weekB = ISOWeek.parse("2013-W03"); System.out.println(weekA.isBefore(weekB)); // 输出true System.out.println(weekA.weeksBetween(weekB)); // 输出5
内容的提问来源于stack exchange,提问作者Joris Kinable
相关产品推荐
相关产品推荐

