繁体   English   中英

如何从 Java 中的 ISO8601 周数计算日期

[英]How to calculate Date from ISO8601 week number in Java

有什么办法可以做到这一点: 如何获取一周的日期(我知道周数)? 不使用任何 Java 库或日历的ISO 8601周数

更新:此处介绍的概念仍然适用,但代码已过时。 现在处于维护模式Joda-Time项目建议迁移到java.time类。 请参阅 Szulc 的答案中的 java.time 代码。

简答

DateTime dateTimeStart = new DateTime( "2003-W01-1", DateTimeZone.UTC ); // Joda-Time 2.4.
DateTime dateTimeStop = dateTimeStart.plusWeeks( 1 );

有关详细信息,请继续阅读。

避免 juDate

与 Java 捆绑在一起的旧 java.util.Date 和 java.util.Calendar 类是出了名的麻烦,应该避免。 Sun 及其合作伙伴在 Java 库中放入了很多整洁的东西,但并不是所有的东西都是好的。 日期时间类可能是其中最糟糕的。

此外,这些类对ISO 8601 周的支持较弱。 有关详细信息,请参阅此答案

ISO 周规则

您可以使用这些类编写自己的代码,但我不建议这样做。 ISO 周数的计算规则非常简单:

  • 第 1 周是日历年的第一个星期四。
  • 星期一是一周的第一天。

乔达时间

取而代之的是一个名为Joda-Time的库。 该库包括对 ISO 周的出色支持。

添加到您的项目很简单,只需添加一个.jar文件。

其他示例代码

请参阅我的其他答案答案,例如从 ISO 周数获取日期时间的代码。

时间

Java 8 有一个新的日期时间框架,其灵感来自于java.time包中的 Joda-Time。

添加库

Java 旨在将库混合在一起。 这样做是面向对象编程和后期绑定的主要目的之一。 关于你的问题的评论是指老板不合理或无知地禁止添加库的非常普遍的情况。 虽然此类禁令有正当理由,但这种情况很少见。

禁止在 Java 中添加库和 jar 就像禁止在配备了挂钩的车队上连接拖车一样。

旧的日期时间类真的很糟糕,以至于我们中的许多人将 Joda-Time 作为一种习惯添加到大多数新项目中。

半开

在日期时间工作中,定义时间跨度的常用方法是“半开”方法。 这意味着开头是包容性的,而结尾是排他性的。 所以一个标准周从星期一的第一刻开始,到下一个星期一的第一刻结束。 搜索 StackOverflow.com 以获取更多讨论和示例。

定义一周的半开放方法图,从第 1 天开始到第 8 天开始

ISO 周的文本表示

ISO 8601 标准定义了表示标准周甚至一周内一天的方法。

取年份、连字符、 W分隔符,周数代表整周: YYYY-Www 添加连字符和星期几以查明该周内的某一天: YYYY-Www-D

Joda-Time 理解这种格式,如下面的代码示例所示。

示例代码

这是一些 Joda-Time 2.4 代码。 在 StackOverflow.com 上搜索这些概念的讨论和示例。 这个问题和这个答案几乎重复了许多其他问题。

int year = 2003;
int week = 1; // Domain: 1 to 53.

// Build a String in ISO 8601 Week format: YYYY-Www-D
// Hard-coding a `1` for Monday, the standard first-day-of-week.
String input = ( String.format( "%04d", year ) + "-W" + String.format( "%02d", week ) + "-1" );

// Specify the time zone by which to define the beginning of a day.
DateTimeZone timeZone = DateTimeZone.UTC; // Or: DateTimeZone.forID( "America/Montreal" );

// Calculate beginning and ending, using Half-Open (inclusive, exclusive) approach.
DateTime dateTimeStart = new DateTime( input, timeZone );
DateTime dateTimeStop = dateTimeStart.plusWeeks( 1 );

// Use Joda-Time's tidy Interval class to represent the entire week. Use getters to access start and stop.
Interval weekInterval = new Interval( dateTimeStart, dateTimeStop );

// Is today in that week? Joda-Time has handy methods: contains, isBefore, isAfter, overlap.
boolean isTodayInThatWeek = weekInterval.contains( DateTime.now() );

转储到控制台。

System.out.println( "input: " + input );
System.out.println( "dateTimeStart: " + dateTimeStart );
System.out.println( "dateTimeStop: " + dateTimeStop );
System.out.println( "interval: " + interval );
System.out.println( "isTodayInThatWeek: " + isTodayInThatWeek );

跑的时候。

input: 2003-W01-1
dateTimeStart: 2002-12-30T00:00:00.000Z
dateTimeStop: 2003-01-06T00:00:00.000Z
interval: 2002-12-30T00:00:00.000Z/2003-01-06T00:00:00.000Z
isTodayInThatWeek: false

Java 8 / java.time 方式

在 Java 8 中,您可以使用TemporalField结合LocalDate::with(TemporalField, long)方法来获取正确的周(基于周的年份)和TemporalAdjuster结合LocalDate::with(TemporalAdjuster)方法来跳转到所需的日期本周,像这样:

final int year = 2020;
final int weekNumber = 34;

LocalDate mondayOfWeek = LocalDate.of(year, Month.JUNE, 1)
                         .with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber)
                         .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));

LocalDate sundayOfWeek = mondayOfWeek.plusDays(6);
LocalDate date = 
  LocalDate.parse("2015 53", 
     new DateTimeFormatterBuilder().appendPattern("YYYY w")
    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
    .toFormatter()));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM