【问题标题】:How to calculate Date from ISO8601 week number in Java如何从 Java 中的 ISO8601 周数计算日期
【发布时间】:2014-08-01 16:19:55
【问题描述】:

有没有办法做到这一点:How to get dates of a week (I know week number)? for ISO 8601 week number 不使用 Java 中的任何库或日历?

【问题讨论】:

  • 我不知道这个“要求”会属于“延迟”类别。抱歉问了。我认为这个“问答网站”是为“狂热的程序员”准备的。我不是一个经验丰富的开发人员,但我正在尝试开发东西。认为这是一个提问的好地方,甚至可能是愚蠢的问题。
  • 为什么要避免使用任何库/日历? (我的意思是,他们在那里是有原因的:让您的工作更简单/更容易)如果有充分的理由,请编辑您的帖子并添加它......如果有充分的理由,这可能会成为一个非常有趣的问题。
  • 正如我所说,我不是开发人员。我是一名使用 Processing 的设计师,过去我曾使用过 Processing (Java) 库,这些库给了我“模棱两可的错误”。我开始知道这是重复相同的类名,我更改了库并且没有再次出现相同的错误。因此,考虑到这一点,并且因为我正在尝试开发一个处理库,我想避免使用库。 Processing 也是一个未来的 Javascript 框架,所以如果我在没有外部库或 Java 日历的情况下完成我的工作,那么将来将它移植到 javascript 会更容易。

标签: java iso8601 week-number


【解决方案1】:

更新:此处介绍的概念仍然适用,但代码已过时。 Joda-Time 项目现在位于 maintenance mode,建议迁移到 java.time 类。查看Answer by Szulc中的java.time代码。

简答

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

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

避免 j.u.Date

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

此外,这些类对ISO 8601 weeks 的支持较弱。详情请见this answer

ISO 周规则

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

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

乔达时间

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

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

其他示例代码

参见 other answer of minethis one 示例代码,用于从 ISO 周数中获取日期时间。

java.time

Java 8 有一个新的日期时间框架,它受 Joda-Time 的启发,位于 java.time 包中。

添加库

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

禁止在 Java 中添加库和 jar 就像禁止将拖车挂在配备挂钩的车队上。

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

半开

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

ISO 周的文字表示

ISO 8601 标准定义了represent a standard week 甚至该周内的一天的方式。

以年份、连字符、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

【讨论】:

  • 感谢您的解释。这是查找给定年份和周数的第一个和最后一个日期的正确方法吗?整数年 = 2012;整数周数 = 8; LocalDate weekStartDate = new LocalDate().withWeekOfWeekyear(weekNumber).withYear(year); LocalDate weekEndDate = new LocalDate().withWeekOfWeekyear(weekNumber + 1).withYear(year);我在将这些日期输入 Unix 时间戳时遇到了一些麻烦,你能提供一些帮助或链接,我可以在其中看到它是如何完成的。
  • @mjh 我添加了一个代码示例,发现 Joda-Time 支持 ISO 标准周字符串格式。
  • @mjh [A] 至于LocalDate,你可以使用它们。要么使用我的代码并转换为 LocalDate,要么采取更直接的方法。但请注意,天真的程序员倾向于认为忽略时区会使思考变得更容易和更简单,但情况几乎总是相反。如果有任何机会您可能关心共享或比较参考任何其他地区的数据,请使用DateTime 与时区。 [B] Unix 时间戳呢?你的问题中没有提到这一点。在 StackOverflow 中搜索许多 Unix 时间戳转换的示例。
【解决方案2】:

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(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
                         .with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber)
                         

LocalDate sundayOfWeek = mondayOfWeek.plusDays(6);

【讨论】:

  • 什么是日期?新的 LocalDate() ?
【解决方案3】:
LocalDate date = 
  LocalDate.parse("2015 53", 
     new DateTimeFormatterBuilder().appendPattern("YYYY w")
    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
    .toFormatter()));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-11
    • 2015-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    相关资源
    最近更新 更多