tl;dr (tl; dr)
Never use Calendar
, now legacy, supplanted by java.time classes such as ZonedDateTime
. (永远不要使用由Java.time类(例如ZonedDateTime
取代的Calendar
(现已遗留)。)
Use a purpose-built class, YearWeek
from the ThreeTen-Extra project, to track standard ISO 8601 weeks . (使用一个专用类, YearWeek
从ThreeTen-额外的项目,跟踪标准ISO8601周 。)
Custom formatter (自定义格式器)
Define a DateTimeFormatter
object to match your non-standard input string. (定义一个DateTimeFormatter
对象以匹配您的非标准输入字符串。)
org.threeten.extra.YearWeek
.parse(
"202001" ,
new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendValue( IsoFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
.appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2)
.toFormatter()
)
.toString()
2020-W01 (2020-W01)
Standard formatter (标准格式器)
Or manipulate your input string to comply with the ISO 8601 standard format , inserting a -W
in the middle between the week-based-year and the week. (或操纵您的输入字符串以符合ISO 8601标准格式 ,在基于周的年份和星期之间的中间插入-W
。) The java.time classes and the ThreeTen-Extra classes all use the ISO 8601 formats by default when parsing/generating strings. (解析/生成字符串时,默认情况下, java.time类和ThreeTen-Extra类均使用ISO 8601格式。)
String input = "202001";
String inputModified = input.substring( 0 , 4 ) + "-W" + input.substring( 4 );
YearWeek yearWeek = YearWeek.parse( inputModified ) ;
yearWeek.toString(): 2020-W01 (yearWeek.toString():2020-W01)
Avoid legacy date-time classes (避免使用旧的日期时间类)
Do not waste your time trying to understand Calendar
. (不要浪费时间尝试了解Calendar
。) This terrible class was supplanted years ago by the modern java.time classes defined in JSR 310. (几年前,这个可怕的类被JSR 310中定义的现代java.time类所取代。)
Definition of week (周的定义)
You must specify your definition of a week. (您必须指定一周的定义。) Do you mean week number 1 contains the first day of the year? (您是说第1周包含一年的第一天吗?) Or week # 1contains a certain day of the week? (还是第1周包含一周中的某天?) Or week # 1 is the first calendar week to consist entirely of dates in the new year? (还是#1周是第一个完全包含新年日期的日历周?) Or perhaps an industry-specific definition of week? (还是特定于行业的周定义?) Some other definition? (还有其他定义吗?)
One of the confusing things about Calendar
is that its definition of a week shifts by Locale
. (关于Calendar
的令人困惑的事情之一是,它对周的定义因Locale
。) This one of many reasons to avoid that legacy class. (这是避免该传统类的许多原因之一。)
Week-based year (基于周的年份)
Depending on your definition of week, the year of a week may not be the calendar year of some dates on that week. (根据您对周的定义,一周中的年份可能不是该周中某些日期的日历年。) A week-based year may overlap with calendar years. (基于星期的年份可能与日历年份重叠。)
Standard weeks and week-based year (标准周和周基年)
For example, the standard ISO 8601 week defines a week as: (例如, 标准ISO 8601星期将一周定义为:)
- Starting on Monday, and (从星期一开始,并且)
- Week # 1 contains the first Thursday of the calendar year. (第1周包含日历年的第一个星期四。)
So there are 52 or 53 whole weeks in every week-based year. (因此,每个每周的年度有52或53个整周。) Of course, that means some dates from the previous and/or following calendar years may appear in the first/last weeks of our week-based year. (当然,这意味着上一个日历年和/或下一个日历年的某些日期可能会出现在我们基于周的年份的第一周/最后一周。)
org.threeten.extra.YearWeek
One problem is that you are trying to represent a year-week with a class that represents a moment, a date with time of day in the context of a time zone. (一个问题是,您试图用一个代表时刻的类来代表一年中的一周,这个时刻在时区的上下文中具有日期。)
Instead, use a purpose-built class. (而是使用专门构建的类。) You can find one in the ThreeTen-Extra library, YearWeek
. (您可以在ThreeTen-Extra库YearWeek
找到一个。) This library extends the functionality of the java.time classes built into Java 8 and later. (该库扩展了Java 8及更高版本中内置的java.time类的功能。)
With that class I would think that we could define a DateTimeFormatter
to parse your input using the formatting pattern YYYYww
where the YYYY
means a 4-digit year of week-based-year, and the ww
means the two-digit week number. (在该类中,我认为我们可以定义一个DateTimeFormatter
来使用格式模式YYYYww
解析您的输入,其中YYYY
表示基于星期的年份的4位数字,而ww
表示两位的星期数。) Like this: (像这样:)
// FAIL
String input = "202001" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "YYYYww" ) ;
YearWeek yearWeek = YearWeek.parse( input , f ) ;
But using that formatter throws an DateTimeParseException
for reasons that escape me. (但是使用该格式化程序会引发DateTimeParseException
,这是出于逃避我的原因。)
Exception in thread "main" java.time.format.DateTimeParseException: Text '202001' could not be parsed: Unable to obtain YearWeek from TemporalAccessor: {WeekOfWeekBasedYear[WeekFields[SUNDAY,1]]=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2020},ISO of type java.time.format.Parsed (线程“主”中的异常java.time.format.DateTimeParseException:无法解析文本“ 202001”:无法从TemporalAccessor获取YearWeek:{WeekOfWeekBasedYear [WeekFields [SUNDAY,1]] = 1,WeekBasedYear [WeekFields [SUNDAY,1] ]] = 2020},ISO类型为java.time.format.Parsed的ISO)
… (…)
Caused by: java.time.DateTimeException: Unable to obtain YearWeek from TemporalAccessor: {WeekOfWeekBasedYear[WeekFields[SUNDAY,1]]=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2020},ISO of type java.time.format.Parsed (由以下原因引起:java.time.DateTimeException:无法从TemporalAccessor获取YearWeek:{WeekOfWeekBasedYear [WeekFields [SUNDAY,1]] = 1,WeekBasedYear [WeekFields [SUNDAY,1]] = 2020},ISO类型为java.time.format 。解析)
… (…)
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: WeekBasedYear (原因:java.time.temporal.UnsupportedTemporalTypeException:不支持的字段:WeekBasedYear)
Alternatively, we can use DateTimeFormatterBuilder
to build up a DateTimeFormatter
from parts. (或者,我们可以使用DateTimeFormatterBuilder
建立一个DateTimeFormatter
从零件。) By perusing the OpenJDK source code for Java 13 for DateTimeFormatter.ISO_WEEK_DATE
I was able to cobble together this formatter that seems to work. (通过仔细阅读适用于DateTimeFormatter.ISO_WEEK_DATE
Java 13 的OpenJDK源代码 ,我可以将这个似乎有效的格式化程序拼凑在一起。)
DateTimeFormatter f =
new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendValue( IsoFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
.appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2)
.toFormatter()
;
Using that: (使用:)
String input = "202001" ;
YearWeek yearWeek = YearWeek.parse( input , f ) ;
ISO 8601 (ISO 8601)
Educate the publisher of your data about the ISO 8601 standard defining formats for repr