繁体   English   中英

如何使用java.time从年份和星期解析字符串中的日期

[英]How to parse date from string with year and week using java.time

在旧的Java中,我可以这样做:

System.out.println(new SimpleDateFormat("yyyy w", Locale.UK).parse("2015 1"));
// shows Mon Dec 29 00:00:00 CET 2014

System.out.println(new SimpleDateFormat("yyyy w", Locale.US).parse("2015 1"));
// shows Mon Dec 28 00:00:00 CET 2014

我想在Java 8中使用java.time。

System.out.println( LocalDate.parse("2015 1", DateTimeFormatter.ofPattern("yyyy w", Locale.US)));

结果:

java.time.format.DateTimeParseException:无法解析文本'2015 1':无法从TemporalAccessor获取LocalDate:{WeekOfWeekBasedYear [WeekFields [SUNDAY,1]] = 1,Year = 2015},ISO类型为java.time。 format.Parsed

如何在java.time中做到这一点?

此外,我不满意我必须通过Locale来确定一周的第一天:星期一和星期日。 它不是乡村功能,而是日历功能。 我想使用像java.time.temporal.WeekFields.ISO这样的东西来显示星期一从周一开始的世界

我发现了类似的情况: https//stackoverflow.com/questions/3941700/how-to-get-dates-of-a-week-i-know-week-number

但不适用于Java 8中的java.time。此外,首先创建日期对象并稍后设置正确周的解决方案并不优雅。 我想一次创建最终日期。

直接回答和解决方案:

System.out.println( 
  LocalDate.parse("2015 1", 
    new DateTimeFormatterBuilder().appendPattern("YYYY w")
    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
    .toFormatter()));
// output: 2014-12-29

说明:

a)你应该使用Y代替y,因为你对ISO-8601周日期感兴趣,而不是在年代。

b)仅通过给出(基于周的)年和周数不能形成日历日期。 星期几很重要,以确定指定日历周内的日期。 周日期的预定义格式化程序需要缺少星期几。 所以你需要使用builder-pattern构建一个专门的解析器。 然后有必要通过方法parseDefaulting()告诉解析器星期几是parseDefaulting()

c)我坚持(并在这里为JSR-310辩护)说一周开始时的问题不是日历问题,而是依赖于国家的问题。 美国和法国(例如)使用相同的日历,但对如何定义一周有不同的看法。 可以使用明确的ISO引用字段WeekFields.ISO.dayOfWeek()来应用ISO-8601标准。 注意:测试显示使用ChronoField.DAY_OF_WEEKLocale.ROOT似乎并不总是保证ISO周的行为,如我的第一个版本的答案所示(原因尚不清楚 - 我的近距离观察似乎有必要来源启发不直观的行为)。

d)java-time-package做得很好 - 除了星期一被指定为数字1.我会更喜欢枚举。 或者使用enum及其方法getValue()

e)侧面通知: SimpleDateFormat默认表现为宽松。 java-time-package更加严格,拒绝用空气来创造一个缺少的星期几 - 即使在宽松的模式下(在我看来这是一件好事)。 软件不应该如此猜测,相反,程序员应该更多地考虑哪一天是正确的。 同样在这里:美国和法国的应用要求可能会有所不同,关于正确的默认设置。

Meno Hochschild接受的答案是正确的。 这是另一条路线。

YearWeek

ThreeTen-Extra库中使用YearWeek类。 该库扩展了具有附加功能的java.time。 此特定类表示ISO 8601周日期系统中的一年周。

工厂方法YearWeek.of采用一对整数参数,基于周的年份和周数。

YearWeek yw = YearWeek.of( 2015 , 1 );  

ISO 8601

理想情况下,您将使用标准ISO 8601格式表示日期时间值的字符串。 对于yyyy-Www这一年的周数,一个连字符,一个W和两个数字的周数,根据需要填充零。

2015年-W01

在解析和生成字符串时,java.time类和ThreeTen-Extra类在默认情况下使用标准的ISO 8601格式。 如果你坚持标准,那么生活会容易。

YearWeek yw = YearWeek.parse( "2015-W01" );
String output = yw.toString(); // 2015-W01

解析整数。

您有一个非标准的数字格式。 因此,让我们解析你的字符串为两件,每一个号,被解释为int整数。

String string = "2015 1";
String[] parts = string.split(" "); // SPACE character.
String part1 = parts[0]; // 2015
String part2 = parts[1]; // 1

Integer类将此类字符串转换为int原始值。

int weekBasedYearNumber = Integer.parseInt( part1 ) ;
int weekNumber = Integer.parseInt( part2 ) ;

现在调用那个工厂方法。

YearWeek yw = YearWeek.of( weekBasedYearNumber , weekNumber );

LocalDate

至于一周的第一天,我们一直在讨论标准的ISO 8601周定义。 在该定义中,星期一总是第一天,从星期一到星期日运行一周。 第1周包含日历年的第一个星期四。 在2015-W01的情况下,星期四将是2015年1月1日。

因此,不需要Locale

我不太确定你的目标,但似乎是提取你一周内的特定日期。 使用YearWeek类和DayOfWeek枚举非常容易。

LocalDate monday = yw.atDay( DayOfWeek.MONDAY );  // 2014-12-29 start-of-week.
LocalDate friday = yw.atDay( DayOfWeek.FRIDAY );  // 2015-01-02
LocalDate sunday = yw.atDay( DayOfWeek.SUNDAY );  // 2015-01-04 end-of-week.

屏幕截图为2015年1月的日历月,ISO 8601周数为1,运行时间为2014-12-29周一至2015-01-04周日

这也可以通过使用“ChronoField.Day_Of_Week”为星期几设置默认分析值并将值设置为“1”来实现,如下所示:

System.out.println( "Date From Year and Week : "+
              LocalDate.parse("2015 1", 
                new DateTimeFormatterBuilder().appendPattern("YYYY w")
                .parseDefaulting(ChronoField.DAY_OF_WEEK, 1)
                .toFormatter()));

暂无
暂无

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

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