当前位置:  开发笔记 > 编程语言 > 正文

使用ZonedDateTime和Calendar API计算年度周问题

如何解决《使用ZonedDateTime和CalendarAPI计算年度周问题》经验,为你挑选了1个好方法。

我试图从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

这两个看起来都很好.



1> Jon Skeet..:

您的代码有四个问题:

您在使用时使用的是系统默认时区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

这两个看起来都很好.

推荐阅读
Gbom2402851125
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有