我试图从ISO-8601日期格式字符串输入计算一年中的一周.最初我用java.time.ZonedDateTime尝试了这个,但它给输入日期 - 20-Jan-2049提供了错误的结果.然后我尝试使用Calendar API,它也给出了错误的响应,即31-Dec-2049.
我附上了示例测试代码
public class ZonedDateTimeTest { public static void main(String[] args) throws InterruptedException { System.out.println("======================================"); String instantStr1 = "2049-01-02T03:48:00Z"; printYearAndWeekOfYear(instantStr1); System.out.println("======================================"); String instantStr2 = "2049-12-31T03:48:00Z"; printYearAndWeekOfYear(instantStr2); System.out.println("======================================"); } public static void printYearAndWeekOfYear(String ISODate) { System.out.println("Date provided -> " + ISODate); ZonedDateTime utcTimestamp = parseToInstant(ISODate).atZone(ZoneOffset.UTC); int year = utcTimestamp.getYear(); int weekOfYear = utcTimestamp.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); System.out.println("Using ZonedDateTime API:: Year " + year + " weekOfYear " + weekOfYear); Date d1 = Date.from(parseToInstant(ISODate)); Calendar cl = Calendar.getInstance(); cl.setTime(d1); int year1 = cl.get(Calendar.YEAR); int weekOfYear1 = cl.get(Calendar.WEEK_OF_YEAR); System.out.println("Using Calendar API:: Year " + year1 + " weekOfYear " + weekOfYear1); } public static Instant parseToInstant(String ISODate) { return DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(ISODate, Instant::from); } }
上面代码的输出
====================================== Date provided 2049-01-02T03:48:00Z Using ZonedDateTime API: Year 2049 weekOfYear 53 Using Calendar API: Year 2049 weekOfYear 1 ====================================== Date provided 2049-12-31T03:48:00Z Using ZonedDateTime API: Year 2049 weekOfYear 52 Using Calendar API: Year 2049 weekOfYear 1 ======================================
Jon Skeet.. 7
您的代码有四个问题:
您在使用时使用的是系统默认时区Calendar
,这可能会更改Instant
落在哪个日期.如果您将日历设置为使用UTC,则会使其更加一致.
你正在使用Calendar.YEAR
哪个会给你日历年而不是一周.你需要Calendar.getWeekYear()
改用.
你正在使用的ZonedDateTime.getYear()
是日历年.你应该使用utcTimestamp.get(IsoFields.WEEK_BASED_YEAR)
你正在使用Calendar.getInstance()
哪个可以给你一个非公历日历,或者它可能有一天的第一天设置不适合你想要执行的计算
修复这些问题(和命名约定)我们最终得到:
import java.util.*; import java.time.*; import java.time.format.*; import java.time.chrono.*; import java.time.temporal.*; public class ZonedDateTimeTest { public static void main(String[] args) { printYearAndWeekOfYear("2049-01-02T03:48:00Z"); String instantStr2 = "2049-12-31T03:48:00Z"; printYearAndWeekOfYear("2049-12-31T03:48:00Z"); } public static void printYearAndWeekOfYear(String isoDate) { System.out.println("Date provided -> " + isoDate); Instant instant = DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(isoDate, Instant::from); ZonedDateTime utcTimestamp = instant.atZone(ZoneOffset.UTC); int year = utcTimestamp.get(IsoFields.WEEK_BASED_YEAR); int weekOfYear = utcTimestamp.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); System.out.println("ZonedDateTime: Year " + year + " weekOfYear " + weekOfYear); // Force the Gregorian calendar with ISO rules and using UTC Calendar calendar = new GregorianCalendar(); calendar.setFirstDayOfWeek(Calendar.MONDAY); calendar.setMinimalDaysInFirstWeek(4); calendar.setTimeZone(TimeZone.getTimeZone("UTC")); calendar.setTime(Date.from(instant)); int calYear = calendar.getWeekYear(); int calWeekOfYear = calendar.get(Calendar.WEEK_OF_YEAR); System.out.println("Calendar: Year " + calYear + " weekOfYear " + calWeekOfYear); System.out.println(); } }
输出:
Date provided -> 2049-01-02T03:48:00Z ZonedDateTime: Year 2048 weekOfYear 53 Calendar: Year 2048 weekOfYear 53 Date provided -> 2049-12-31T03:48:00Z ZonedDateTime: Year 2049 weekOfYear 52 Calendar: Year 2049 weekOfYear 52
这两个看起来都很好.
您的代码有四个问题:
您在使用时使用的是系统默认时区Calendar
,这可能会更改Instant
落在哪个日期.如果您将日历设置为使用UTC,则会使其更加一致.
你正在使用Calendar.YEAR
哪个会给你日历年而不是一周.你需要Calendar.getWeekYear()
改用.
你正在使用的ZonedDateTime.getYear()
是日历年.你应该使用utcTimestamp.get(IsoFields.WEEK_BASED_YEAR)
你正在使用Calendar.getInstance()
哪个可以给你一个非公历日历,或者它可能有一天的第一天设置不适合你想要执行的计算
修复这些问题(和命名约定)我们最终得到:
import java.util.*; import java.time.*; import java.time.format.*; import java.time.chrono.*; import java.time.temporal.*; public class ZonedDateTimeTest { public static void main(String[] args) { printYearAndWeekOfYear("2049-01-02T03:48:00Z"); String instantStr2 = "2049-12-31T03:48:00Z"; printYearAndWeekOfYear("2049-12-31T03:48:00Z"); } public static void printYearAndWeekOfYear(String isoDate) { System.out.println("Date provided -> " + isoDate); Instant instant = DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(isoDate, Instant::from); ZonedDateTime utcTimestamp = instant.atZone(ZoneOffset.UTC); int year = utcTimestamp.get(IsoFields.WEEK_BASED_YEAR); int weekOfYear = utcTimestamp.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); System.out.println("ZonedDateTime: Year " + year + " weekOfYear " + weekOfYear); // Force the Gregorian calendar with ISO rules and using UTC Calendar calendar = new GregorianCalendar(); calendar.setFirstDayOfWeek(Calendar.MONDAY); calendar.setMinimalDaysInFirstWeek(4); calendar.setTimeZone(TimeZone.getTimeZone("UTC")); calendar.setTime(Date.from(instant)); int calYear = calendar.getWeekYear(); int calWeekOfYear = calendar.get(Calendar.WEEK_OF_YEAR); System.out.println("Calendar: Year " + calYear + " weekOfYear " + calWeekOfYear); System.out.println(); } }
输出:
Date provided -> 2049-01-02T03:48:00Z ZonedDateTime: Year 2048 weekOfYear 53 Calendar: Year 2048 weekOfYear 53 Date provided -> 2049-12-31T03:48:00Z ZonedDateTime: Year 2049 weekOfYear 52 Calendar: Year 2049 weekOfYear 52
这两个看起来都很好.