如何将年周数转换为LocalDate

huangapple go评论106阅读模式
英文:

How to convert weeks of year to LocalDate

问题

我有一个包含年-周(例如"2015-40")和年-月(例如"2015-08")格式的字符串,想要在Scala中将其转换为LocalDate。

我尝试过使用:

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

但是最终遇到了DateTimeParseException错误。如果能提供关于如何解决这个问题的任何帮助,将不胜感激。

提前感谢。

英文:

I have a string with both year-week e.g. "2015-40" and year-month formats e.g. "2015-08", that would like to transform into LocalDate in Scala.

I have tried using

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

but end up with DateTimeParseException error. Would appreciate any help on how to do this

Thanks in advance

答案1

得分: 4

  1. import java.time.LocalDate
  2. import java.time.format.DateTimeFormatterBuilder
  3. import java.time.temporal.{ChronoField, DayOfWeek}
  4. import java.util.Locale
  5. object Main extends App {
  6. val date = "2015-40"
  7. val formatter = new DateTimeFormatterBuilder()
  8. .appendPattern("YYYY-ww")
  9. .parseDefaulting(ChronoField.DAY_OF_WEEK, DayOfWeek.MONDAY.getValue())
  10. .toFormatter(Locale.FRANCE)
  11. val ld = LocalDate.parse(date, formatter)
  12. println(ld)
  13. }

Output:

  1. 2015-09-28

在解析 2015-40 这个日期字符串到 LocalDate 时出现异常的原因是:

  • LocalDate 表示一个日历日期,而第40周包含7天。Java 不知道你想要这7天中的哪一天,所以拒绝为你做出选择。在我上面的代码中,我已经指定了星期一。周内的其他任何一天都应该有效。
  • 更微妙的是,虽然对于人类来说,2015年和第40周是明确的,但在新年附近的情况下,并不总是如此,因为第1周可能在新年之前开始,第52周或第53周可能在新年之后延续。因此,一个日历年和一个周数并不总是定义一个特定的周。相反,我们需要引入“周年”或“基于周的年”的概念。周年从包含第1周开始,无论这是否意味着它在新年前几天或之后几天开始。它持续到最后一周的最后一天,通常也是在新年前几天或之后几天。要告诉 DateTimeFormatter 我们要解析(或打印)周年,我们需要使用大写的 YYYY,而不是小写的 yyyy(或 uuuu)。

另外,如果你可以影响日期格式的话,考虑使用带有 W 的格式,例如 2015-W40。这是 ISO 8601 格式的年和周表示方式。在 ISO 中,2015-12 表示年和月,很多人会这样理解。因此,为了消除歧义和避免误读,可以采用带有 W 的格式。

编辑:

在我的解释中,我假设了 ISO 周计数方式(星期一是一周的第一天,第1周被定义为新年后至少有4天的第一周)。你可以将不同的区域设置传递给格式化器构建器,以获得不同的周计数方式。

如果你确信你的周计数遵循 ISO 标准,评论中的 Andreas 的建议已经足够解决问题:

或者,添加 ThreeTen Extra 库,这样你可以使用
YearWeek
类,它有一个方便的 atDay​(DayOfWeek dayOfWeek)
方法,可以用来获取 LocalDate

链接: Wikipedia 文章:ISO 8601

  1. <details>
  2. <summary>英文:</summary>
  3. String date = &quot;2015-40&quot;;
  4. DateTimeFormatter formatter = new DateTimeFormatterBuilder()
  5. .appendPattern(&quot;YYYY-ww&quot;)
  6. .parseDefaulting(ChronoField.DAY_OF_WEEK, DayOfWeek.MONDAY.getValue())
  7. .toFormatter(Locale.FRANCE);
  8. LocalDate ld = LocalDate.parse(date, formatter);
  9. System.out.println(ld);
  10. Sorry that I can write only Java, I trust you to translate to Scala. Output is:
  11. &gt; 2015-09-28
  12. Why were you getting an exception? There were a couple of things missing for us to parse `2015-40` into a `LocalDate`:
  13. - A `LocalDate` is a calendar date, and week 40 consists of 7 days. Java doesn’t know which of those 7 days you want and refuses to make the choice for you. In my code above I have specified Monday. Any other day of the week should work.
  14. - A bit subtler. While to a human year 2015 and week 40 is unambiguous, the same is not always the case around New Year where week 1 may begin before New Year or week 52 or 53 extend after New Year. So a calendar year and a week number don’t always define one specific week. Instead we need the concept of a *week year* or *week-based year*. A week year lasts from week 1 inclusive no matter if that means it begins a few days before or after New Year. And it lasts until the last day of the last week, again most often a few days before or after New Year. To tell a `DateTimeFormatter` that we want to parse (or print) the week year we need to use upper case `YYYY` instead of lower case `yyyy` (or `uuuu`).
  15. As an aside, if you can influence the format, consider `2015-W40` with a `W`. This is ISO 8601 format for year and week. In ISO `2015-12` denotes year and month, and many will read it this way. So to disambiguate and avoid misreading.
  16. Edit:
  17. In my explanation I have assumed ISO week scheme (Monday is the first day of week and week 1 is defined as the first week having at least 4 days in the new year). You may pass a different locale to the formatter builder to obtain a different week scheme.
  18. If you are sure that your weeks follow ISO, Andreas’ suggestion in the comment is good enough that we want as part of the answer:
  19. &gt; Alternatively, add the [ThreeTen Extra](https://www.threeten.org/threeten-extra/) library, so you can use the
  20. &gt; [`YearWeek`](https://www.threeten.org/threeten-extra/apidocs/org.threeten.extra/org/threeten/extra/YearWeek.html)
  21. &gt; class, that has a nice [`atDay​(DayOfWeek
  22. &gt; dayOfWeek)`](https://www.threeten.org/threeten-extra/apidocs/org.threeten.extra/org/threeten/extra/YearWeek.html#atDay(java.time.DayOfWeek))
  23. &gt; method for getting a `LocalDate`.
  24. **Link:** [Wikipedia article: ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)
  25. </details>
  26. # 答案2
  27. **得分**: 0
  28. `LocalDate`有三个部分:年、月和月份中的日期。因此,在`year-month`字符串的情况下,根据您的要求,您将需要获取特定日期的`LocalDate`。解析年月字符串就像演示代码中所示的那样直接。
  29. 在`year-week`字符串的情况下,您将需要获取特定星期几的`LocalDate`,例如星期一或今天的日期等。此外,与其直接解析字符串,我发现更容易获取年份和周数,然后使用`LocalDate`的方法来获取所需的`LocalDate`实例。
  30. ```java
  31. import java.time.DayOfWeek;
  32. import java.time.LocalDate;
  33. import java.time.YearMonth;
  34. import java.time.format.DateTimeFormatter;
  35. import java.time.temporal.TemporalAdjusters;
  36. import java.time.temporal.WeekFields;
  37. public class Main {
  38. public static void main(String[] args) {
  39. //#################### Year-Month #######################
  40. // 给定 year-month 字符串
  41. var yearMonthStr = "2015-08";
  42. // 从 yearMonthStr 解析出的 LocalDate,位于该月的第一天
  43. LocalDate date2 = YearMonth.parse(yearMonthStr, DateTimeFormatter.ofPattern("u-M")).atDay(1);
  44. System.out.println(date2);
  45. // 从 yearMonthStr 解析出的 LocalDate,位于该月的最后一天
  46. date2 = YearMonth.parse(yearMonthStr, DateTimeFormatter.ofPattern("u-M")).atEndOfMonth();
  47. System.out.println(date2);
  48. // 从 yearMonthStr 解析出的 LocalDate,位于该月的特定日期
  49. date2 = YearMonth.parse(yearMonthStr, DateTimeFormatter.ofPattern("u-M")).atDay(1).withDayOfMonth(10);
  50. System.out.println(date2);
  51. //#################### Year-Week #######################
  52. // 给定 year-week 字符串
  53. var yearWeekStr = "2015-40";
  54. // 在 '-' 上拆分字符串,并获取年份和周数值
  55. String[] parts = yearWeekStr.split("-");
  56. int year = Integer.parseInt(parts[0]);
  57. int week = Integer.parseInt(parts[1]);
  58. // 拥有年份、周数和今天的日期,例如星期五的 LocalDate
  59. LocalDate date1 = LocalDate.now()
  60. .withYear(year)
  61. .with(WeekFields.ISO.weekOfYear(), week);
  62. System.out.println(date1);
  63. // 拥有年份、周数和下一个星期一(如果今天是星期一,则为同一天)
  64. date1 = LocalDate.now()
  65. .withYear(year)
  66. .with(WeekFields.ISO.weekOfYear(), week)
  67. .with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
  68. System.out.println(date1);
  69. // 拥有年份、周数和今天之前的星期一(如果今天是星期一,则为同一天)
  70. date1 = LocalDate.now()
  71. .withYear(year)
  72. .with(WeekFields.ISO.weekOfYear(), week)
  73. .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
  74. System.out.println(date1);
  75. }
  76. }

输出:

  1. 2015-08-01
  2. 2015-08-31
  3. 2015-08-10
  4. 2015-10-02
  5. 2015-10-05
  6. 2015-09-28
英文:

LocalDate has three parts: year, month and day of the month. So, in the case of year-month string, you will have to get the LocalDate on a specific day as per your requirement. Parsing the year-month string is straight forward as shown in the demo code.

In the case of year-week string, you will have to get the LocalDate on a specific day of the week e.g. Mon or today's day etc. Also, instead of parsing the string directly, I found it easier to get the year and week and then use the methods LocalDate to get the required instance of LocalDate.

  1. import java.time.DayOfWeek;
  2. import java.time.LocalDate;
  3. import java.time.YearMonth;
  4. import java.time.format.DateTimeFormatter;
  5. import java.time.temporal.TemporalAdjusters;
  6. import java.time.temporal.WeekFields;
  7. public class Main {
  8. public static void main(String[] args) {
  9. //#################### Year-Month #######################
  10. // Given year-month string
  11. var yearMonthStr = &quot;2015-08&quot;;
  12. // LocalDate parsed from yearMonthStr and on the 1st day of the month
  13. LocalDate date2 = YearMonth.parse(yearMonthStr, DateTimeFormatter.ofPattern(&quot;u-M&quot;)).atDay(1);
  14. System.out.println(date2);
  15. // LocalDate parsed from yearMonthStr and on the last day of the month
  16. date2 = YearMonth.parse(yearMonthStr, DateTimeFormatter.ofPattern(&quot;u-M&quot;)).atEndOfMonth();
  17. System.out.println(date2);
  18. // LocalDate parsed from yearMonthStr and on specific day of the month
  19. date2 = YearMonth.parse(yearMonthStr, DateTimeFormatter.ofPattern(&quot;u-M&quot;)).atDay(1).withDayOfMonth(10);
  20. System.out.println(date2);
  21. //#################### Year-Week #######################
  22. // Given year-week string
  23. var yearWeekStr = &quot;2015-40&quot;;
  24. // Split the string on &#39;-&#39; and get year and week values
  25. String[] parts = yearWeekStr.split(&quot;-&quot;);
  26. int year = Integer.parseInt(parts[0]);
  27. int week = Integer.parseInt(parts[1]);
  28. // LocalDate with year, week and today&#39;s day e.g. Fri
  29. LocalDate date1 = LocalDate.now()
  30. .withYear(year)
  31. .with(WeekFields.ISO.weekOfYear(), week);
  32. System.out.println(date1);
  33. // LocalDate with year, week and next Mon (or same if today is Mon)
  34. date1 = LocalDate.now()
  35. .withYear(year)
  36. .with(WeekFields.ISO.weekOfYear(), week)
  37. .with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
  38. System.out.println(date1);
  39. // LocalDate with year, week and today&#39;s day previous Mon (or same if today is Mon)
  40. date1 = LocalDate.now()
  41. .withYear(year)
  42. .with(WeekFields.ISO.weekOfYear(), week)
  43. .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
  44. System.out.println(date1);
  45. }
  46. }

Output:

  1. 2015-08-01
  2. 2015-08-31
  3. 2015-08-10
  4. 2015-10-02
  5. 2015-10-05
  6. 2015-09-28

huangapple
  • 本文由 发表于 2020年8月21日 22:22:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/63524671.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定