【问题标题】:How to convert weeks of year to LocalDate如何将一年中的几周转换为 LocalDate
【发布时间】:2020-08-21 14:22:35
【问题描述】:

我有一个包含年份和星期的字符串,例如“2015-40”和年月格式,例如“2015-08”,想在 Scala 中转换为 LocalDate。

我尝试过使用

val date = "2015-40"
val formatter = DateTimeFormatter.ofPattern("yyyy-ww") 
LocalDate.parse(date, formatter)

但最终会出现 DateTimeParseException 错误。希望对如何执行此操作提供任何帮助

提前致谢

【问题讨论】:

  • 如果给你写在一张纸上的“2015-04”,你怎么知道它是指 2015 年的第四周还是 2015 年的第四个月?只需使用您用来回答该问题的算法来指导您的编程。

标签: java scala java-time localdate datetimeformatter


【解决方案1】:
    String date = "2015-40";
    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendPattern("YYYY-ww")
            .parseDefaulting(ChronoField.DAY_OF_WEEK, DayOfWeek.MONDAY.getValue())
            .toFormatter(Locale.FRANCE);
    LocalDate ld = LocalDate.parse(date, formatter);
    
    System.out.println(ld);

对不起,我只会写 Java,我相信你会翻译成 Scala。输出是:

2015-09-28

为什么会出现异常?我们缺少一些东西来将2015-40解析为LocalDate:

  • LocalDate 是日历日期,第 40 周包含 7 天。 Java 不知道您想要这 7 天中的哪一天,并且拒绝为您做出选择。在我上面的代码中,我指定了星期一。一周中的任何其他日子都应该工作。
  • 有点微妙。虽然对于人类的 2015 年和第 40 周是明确的,但在新年前后并非总是如此,第 1 周可能在新年之前开始,或者第 52 周或第 53 周在新年之后延长。因此,日历年和周数并不总是定义一个特定的周。相反,我们需要周年或周年的概念。一周年从第 1 周开始,无论这是否意味着它是在新年之前或之后的几天开始的。它一直持续到上周的最后一天,最常见的是新年前后的几天。要告诉DateTimeFormatter 我们要解析(或打印)星期几,我们需要使用大写的YYYY 而不是小写的yyyy(或uuuu)。

顺便说一句,如果您可以影响格式,请考虑使用2015-W40 和W。这是年和周的 ISO 8601 格式。在 ISO 中,2015-12 表示年和月,许多人会这样读。所以要消除歧义,避免误读。

编辑:

在我的解释中,我假设了 ISO 周计划(星期一是一周的第一天,第 1 周被定义为新年中至少有 4 天的第一周)。您可以将不同的语言环境传递给格式化程序生成器以获得不同的周计划。

如果您确定您的周数遵循 ISO,Andreas 在评论中的建议已经足够好,我们希望将其作为答案的一部分:

或者,添加 ThreeTen Extra 库,这样您就可以使用 YearWeek 类,有一个很好的atDay​(DayOfWeek dayOfWeek) 获取LocalDate的方法。

链接: Wikipedia article: ISO 8601

【讨论】:

  • 对问题的Year-Week 方面的一个很好的解释。老实说,我也试图以你的方式解决这方面的问题,但在某个时候卡住了,然后我求助于在 - 上拆分字符串,这在我看来是一个 hack。你是惯用的方式。
  • 或者,添加ThreeTen Extra 库,这样您就可以使用YearWeek 类,它有一个很好的atDay​(DayOfWeek dayOfWeek) 方法来获取LocalDate。
【解决方案2】:

LocalDate 包含三个部分:年、月和月日。因此,对于year-month 字符串,您必须根据您的要求在特定日期获取LocalDate。解析年月字符串很简单,如演示代码所示。

对于year-week 字符串,您必须在一周中的特定日期获取LocalDate,例如星期一或今天等。此外,我发现不是直接解析字符串,而是更容易获取年份和星期,然后使用方法 LocalDate 获取所需的 LocalDate 实例。

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;

public class Main {
    public static void main(String[] args) {
        //#################### Year-Month #######################
        // Given year-month string
        var yearMonthStr = "2015-08";

        // LocalDate parsed from yearMonthStr and on the 1st day of the month
        LocalDate date2 = YearMonth.parse(yearMonthStr, DateTimeFormatter.ofPattern("u-M")).atDay(1);
        System.out.println(date2);

        // LocalDate parsed from yearMonthStr and on the last day of the month
        date2 = YearMonth.parse(yearMonthStr, DateTimeFormatter.ofPattern("u-M")).atEndOfMonth();
        System.out.println(date2);

        // LocalDate parsed from yearMonthStr and on specific day of the month
        date2 = YearMonth.parse(yearMonthStr, DateTimeFormatter.ofPattern("u-M")).atDay(1).withDayOfMonth(10);
        System.out.println(date2);

        
        //#################### Year-Week #######################
        // Given year-week string
        var yearWeekStr = "2015-40";

        // Split the string on '-' and get year and week values
        String[] parts = yearWeekStr.split("-");
        int year = Integer.parseInt(parts[0]);
        int week = Integer.parseInt(parts[1]);

        // LocalDate with year, week and today's day e.g. Fri
        LocalDate date1 = LocalDate.now()
                            .withYear(year)
                            .with(WeekFields.ISO.weekOfYear(), week);
        System.out.println(date1);

        // LocalDate with year, week and next Mon (or same if today is Mon)
        date1 = LocalDate.now()
                .withYear(year)
                .with(WeekFields.ISO.weekOfYear(), week)
                .with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
        System.out.println(date1);

        // LocalDate with year, week and today's day previous Mon (or same if today is Mon)
        date1 = LocalDate.now()
                .withYear(year)
                .with(WeekFields.ISO.weekOfYear(), week)
                .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        System.out.println(date1);
    }
}

输出:

2015-08-01
2015-08-31
2015-08-10
2015-10-02
2015-10-05
2015-09-28

【讨论】:

  • 看来 OP 不知道,也不知道它是 year-month 字符串还是 year-week 字符串。
  • @AndrewMorton - OP 没有提到这两个值是来自同一个变量还是来自不同的变量。在进行任何更改之前,我将等待 OP 的评论。
  • 感谢您的详细解决方案。在这种情况下,我确实知道变量何时是年月或年周,所以这是一个很好的解决方案
猜你喜欢
  • 2012-09-28
  • 2023-03-29
  • 2020-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多