2017-01-16 2 views
2

Ich habe versucht, Woche des Jahres aus einem ISO-8601 Datumsformat String-Eingabe zu berechnen. Anfangs versuchte ich dies mit java.time.ZonedDateTime, aber es gibt ein falsches Ergebnis für das Eingabedatum - 2-Jan-2049. Dann habe ich versucht mit Kalender-API es gibt auch falsche Antwort für 31-Dec-2049.Compute Woche des Jahres Probleme mit ZonenedDateTime und Kalender API

ich die Probe Testcode

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); 
    } 
} 

Ausgabe von Code über

====================================== 
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

Bitte setzen Sie diesen Kommentar * in die Frage * - logisch ist das Teil der Frage. Es ist auch bedauerlich, dass Sie keine Zeitzone irgendwo im "Kalender" -Teil angegeben haben, was sich leicht auf die Ergebnisse auswirken könnte. –

+1

Bitte beenden Sie die Formatierung. Ich habe Ihre Code-Formatierung jetzt zweimal korrigiert, und beide Male haben Sie sie rückgängig gemacht. Ich habe die Ergebnisse dann neu formatiert, damit sie leichter zu lesen sind, und Sie haben es wieder rückgängig gemacht. –

Antwort

6

Es mit Ihrem Code sind vier Probleme angeschlossen haben, mit zu beginnen:

  • Sie verwenden die Systemstandardzeitzone, wenn Sie Calendar verwenden, die das Datum dergut ändern kannfällt auf. Wenn Sie den Kalender auf UTC setzen, wird er konsistenter.
  • Sie verwenden Calendar.YEAR, die geben Sie die Kalender Jahr statt der Woche Jahr. Sie müssen stattdessen Calendar.getWeekYear() verwenden.
  • Sie verwenden ZonedDateTime.getYear(), die wieder das Kalenderjahr ist. Sie shuold utcTimestamp.get(IsoFields.WEEK_BASED_YEAR) verwenden
  • Sie Calendar.getInstance() verwenden, die Ihnen eine nicht-gregorianischen Kalender geben könnte, oder könnte es haben Tagss-of-Woche unpassend für die Berechnung festgelegt Sie

Fixing ausführen möchten diese Fragen (und Namenskonventionen) wir am Ende mit:

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(); 
    } 
} 

Ausgang:

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 

Both von denen sehen gut zu mir aus.

+0

Ich bin interessiert, weekOfYear Berechnung kennen. Sowohl die Zeitzone als auch der Kalender geben möglicherweise eine falsche Antwort. – kanchan

+0

@kanchan: Nein, tun sie nicht. Sehen Sie sich meinen Schnitt an - beide geben das korrekte ISO-Wochenzeitraumergebnis an, aber "Kalender" lässt Sie nicht auf das Kalenderjahr zugreifen. –

+0

danke für Ihre Hilfe. – kanchan

1

Der alte Calendar -stuff ermöglicht zwar eine Lösung, da Java-7, damit ich es als Ergänzung zu der Java-8-bezogene Antwort von Jon Skeet zeigen:

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 

Für Android-Nutzer, wo diese API ist Standard: Die Methode getWeekYear() ist seit API-Level 24 verfügbar.

+0

Vielen Dank Meno Hochschild und Jon Skeet für Ihre Hilfe. – kanchan

Verwandte Themen