2017-01-16 8 views
2

私は、ISO-8601の日付形式の文字列入力から週を計算しようとしていました。当初はjava.time.ZonedDateTimeで試してみましたが、Input Date - 2041年2月2日に間違った結果が返されました。それから、Calendar APIを試してみましたが、それは2049年12月31日に間違った応答を返します。ZonedDateTimeとカレンダーAPIで週の問題を計算する

私はサンプルテストコードを添付している

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 
====================================== 
上記のコードからの出力
+1

質問*には、コメント*を論理的に入れてください。また、カレンダー部分のどこにでもタイムゾーンを指定していないと、結果に簡単に影響する可能性があることは残念です。 –

+1

フォーマットを中断しないでください。私は今あなたのコードのフォーマットを2回修正しました。そして、あなたはそれを元に戻しました。私は結果を再フォーマットして読みやすくし、やり直しました。 –

答えて

6

を開始するにはあなたのコードを持つ4つの問題があります。

  • あなたが使用しているが、 Calendarを使用すると、システムのデフォルトのタイムゾーンが変更される可能性があります。Instantが落ちる。 UTCを使用するようにカレンダーを設定すると、より一貫性のあるものになります。
  • あなたは週よりカレンダー年を与えるCalendar.YEARを使用しています。年です。代わりにCalendar.getWeekYear()を使用する必要があります。
  • ZonedDateTime.getYear()をもう一度暦年に使用しています。あなたはあなたに非グレゴリオ暦を与える可能性があるCalendar.getInstance()を使用している、またはそれが最初の曜日あなたは

固定が実行する計算のために不適切に設定されている可能性がutcTimestamp.get(IsoFields.WEEK_BASED_YEAR)

  • を使用することshuoldこれらの問題(と命名規則)私たちはで終わる:

    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 
    

    両方それらの私によく見える。

  • +0

    weekOfYear計算を知りたいと思っています。 ZonedDateTimeまたはCalendarの両方が誤った応答をする可能性があります。 – kanchan

    +0

    @ kanchan:そうではありません。私の編集を見てください - 彼らはどちらも正しい週の週の結果を与えていますが、 'カレンダー 'はあなたが週に来ることを許しません。 –

    +0

    ご協力いただきありがとうございます。 – kanchan

    1

    古いCalendar -stuffは確かに私はジョンスキートのJavaの-8関連の回答の補足として、それを表示するJava-7以来のソリューションを可能にします:このAPIはAndroidのユーザーのために

    String instantStr1 = "2049-01-02T03:48:00Z"; 
    String instantStr2 = "2049-12-31T03:48:00Z"; 
    
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); 
    Date d1 = sdf.parse(instantStr1); 
    Date d2 = sdf.parse(instantStr2); 
    
    GregorianCalendar gcal = new GregorianCalendar(); 
    gcal.setFirstDayOfWeek(Calendar.MONDAY); 
    gcal.setMinimalDaysInFirstWeek(4); 
    
    gcal.setTime(d1); 
    System.out.println(
        "Using Calendar API: Year " + gcal.getWeekYear() + " weekOfYear " 
        + gcal.get(Calendar.WEEK_OF_YEAR) 
    ); // Using Calendar API: Year 2048 weekOfYear 53 
    
    gcal.setTime(d2); 
    System.out.println(
        "Using Calendar API: Year " + gcal.getWeekYear() + " weekOfYear " 
        + gcal.get(Calendar.WEEK_OF_YEAR) 
    ); // Using Calendar API: Year 2049 weekOfYear 52 
    

    標準:メソッドgetWeekYear()は、APIレベル24以降で利用可能です。

    +0

    Meno HochschildとJon Skeetに感謝します。 – kanchan