简体   繁体   English

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

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

In old java I can do it in that way: 在旧的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

I would like to use java.time in Java 8. 我想在Java 8中使用java.time。

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

Result: 结果:

java.time.format.DateTimeParseException: Text '2015 1' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {WeekOfWeekBasedYear[WeekFields[SUNDAY,1]]=1, Year=2015},ISO of type java.time.format.Parsed java.time.format.DateTimeParseException:无法解析文本'2015 1':无法从TemporalAccessor获取LocalDate:{WeekOfWeekBasedYear [WeekFields [SUNDAY,1]] = 1,Year = 2015},ISO类型为java.time。 format.Parsed

How to do it in java.time? 如何在java.time中做到这一点?

Moreover, I'm not satisfied that I have to pass Locale to determine first day of week: Monday vs Sunday. 此外,我不满意我必须通过Locale来确定一周的第一天:星期一和星期日。 It is not country feature but calendar feature. 它不是乡村功能,而是日历功能。 I would like to use something like java.time.temporal.WeekFields.ISO to show the world that week start with Monday 我想使用像java.time.temporal.WeekFields.ISO这样的东西来显示星期一从周一开始的世界

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

but not for java.time in Java 8. Moreover, solution that first create a date object and later set correct week is not elegant. 但不适用于Java 8中的java.time。此外,首先创建日期对象并稍后设置正确周的解决方案并不优雅。 I want to create final date in one shot. 我想一次创建最终日期。

Direct answer and solution: 直接回答和解决方案:

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

Explanations: 说明:

a) You should use Y instead of y because you are interested in ISO-8601-week-date, not in year-of-era. a)你应该使用Y代替y,因为你对ISO-8601周日期感兴趣,而不是在年代。

b) A calendar date cannot be formed by just giving a (week-based) year and a week-number. b)仅通过给出(基于周的)年和周数不能形成日历日期。 The day of week matters to determine the day within the specified calendar week. 星期几很重要,以确定指定日历周内的日期。 The predefined formatter for week-dates requires the missing day-of-week. 周日期的预定义格式化程序需要缺少星期几。 So you need to construct a specialized parser using the builder-pattern. 所以你需要使用builder-pattern构建一个专门的解析器。 Then it is necessary to tell the parser what day of week is wanted - via the method parseDefaulting() . 然后有必要通过方法parseDefaulting()告诉解析器星期几是parseDefaulting()

c) I insist (and defend JSR-310 here) on saying that the question when a week starts is not a calendar issue but a country-dependent issue. c)我坚持(并在这里为JSR-310辩护)说一周开始时的问题不是日历问题,而是依赖于国家的问题。 US and France (as example) use the same calendar but have different views how to define a week. 美国和法国(例如)使用相同的日历,但对如何定义一周有不同的看法。 ISO-8601-standard can be applied using the explicitly ISO-referring field WeekFields.ISO.dayOfWeek() . 可以使用明确的ISO引用字段WeekFields.ISO.dayOfWeek()来应用ISO-8601标准。 Attention: Testing has revealed that using ChronoField.DAY_OF_WEEK together with Locale.ROOT does not always seem to guarantee ISO-week-behaviour as indicated in my first version of this answer (the reasons are not yet clear for me - a close view of the sources seems to be necessary to enlighten the unintuitive behaviour). 注意:测试显示使用ChronoField.DAY_OF_WEEKLocale.ROOT似乎并不总是保证ISO周的行为,如我的第一个版本的答案所示(原因尚不清楚 - 我的近距离观察似乎有必要来源启发不直观的行为)。

d) The java-time-package does it well - with the exception that Monday is just specified as number 1. I would have preferred the enum. d)java-time-package做得很好 - 除了星期一被指定为数字1.我会更喜欢枚举。 Or use the enum and its method getValue() . 或者使用enum及其方法getValue()

e) Side notice: SimpleDateFormat behaves leniently by default. e)侧面通知: SimpleDateFormat默认表现为宽松。 The java-time-package is stricter and rejects to invent a missing day-of-week out of thin air - even in lenient mode (which is in my opinion rather a good thing). java-time-package更加严格,拒绝用空气来创造一个缺少的星期几 - 即使在宽松的模式下(在我看来这是一件好事)。 Software should not guess so much, instead the programmer should think more about what day-of-week is the right one. 软件不应该如此猜测,相反,程序员应该更多地考虑哪一天是正确的。 Again here: The application requirements will probably differ in US and France about the right default setting. 同样在这里:美国和法国的应用要求可能会有所不同,关于正确的默认设置。

The accepted Answer by Meno Hochschild is correct. Meno Hochschild接受的答案是正确的。 Here is an alternate route. 这是另一条路线。

YearWeek

Use the YearWeek class in ThreeTen-Extra library. ThreeTen-Extra库中使用YearWeek类。 This library extends java.time with additional functionality. 该库扩展了具有附加功能的java.time。 This particular class represents a year-week in the ISO 8601 week date system . 此特定类表示ISO 8601周日期系统中的一年周。

The factory method YearWeek.of takes a pair of integer arguments, the week-based-year and the week number. 工厂方法YearWeek.of采用一对整数参数,基于周的年份和周数。

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

ISO 8601 ISO 8601

Ideally you would be using standard ISO 8601 formats for strings representing date-time values. 理想情况下,您将使用标准ISO 8601格式表示日期时间值的字符串。 For year-week that would be yyyy-Www the week-based-year number, a hyphen, a W , and two digits for week number with padding zero as needed. 对于yyyy-Www这一年的周数,一个连字符,一个W和两个数字的周数,根据需要填充零。

2015-W01 2015年-W01

The java.time classes, and ThreeTen-Extra classes, use the standard ISO 8601 formats by default when parsing and generating strings. 在解析和生成字符串时,java.time类和ThreeTen-Extra类在默认情况下使用标准的ISO 8601格式。 So life is much easier if you stick to the standard. 如果你坚持标准,那么生活会容易。

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

Parsing integers. 解析整数。

You have a non-standard format for numbers. 您有一个非标准的数字格式。 So let's parse your string as two pieces, one number each, to be interpreted as int integers. 因此,让我们解析你的字符串为两件,每一个号,被解释为int整数。

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

The Integer class converts such strings to int primitive values. Integer类将此类字符串转换为int原始值。

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

Now call that factory method. 现在调用那个工厂方法。

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

LocalDate

As for first day of week, here we have been discussing the standard ISO 8601 definition of week. 至于一周的第一天,我们一直在讨论标准的ISO 8601周定义。 In that definition, Monday is always the first day, a week running from Monday-Sunday. 在该定义中,星期一总是第一天,从星期一到星期日运行一周。 Week # 1 contains the first Thursday of the calendar-year. 第1周包含日历年的第一个星期四。 In the case of 2015-W01 that Thursday would be January 1, 2015. 在2015-W01的情况下,星期四将是2015年1月1日。

So, no Locale needed. 因此,不需要Locale

I am not quite sure of your goal, but it seems to be extracting particular dates for days within your week. 我不太确定你的目标,但似乎是提取你一周内的特定日期。 That is quite easy with the YearWeek class and the DayOfWeek enum. 使用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周日

This can also be achieved by putting default parse value for Day of week using "ChronoField.Day_Of_Week" and setting the value as "1" as follows: 这也可以通过使用“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