]> granicus.if.org Git - icu/commitdiff
ICU-9836 C/Java mismatch parsing years with pattern "yyyy"
authorScott Russell <DTownSMR@gmail.com>
Fri, 4 Jan 2013 17:16:07 +0000 (17:16 +0000)
committerScott Russell <DTownSMR@gmail.com>
Fri, 4 Jan 2013 17:16:07 +0000 (17:16 +0000)
X-SVN-Rev: 33011

icu4c/source/i18n/smpdtfmt.cpp
icu4c/source/test/cintltst/cdattst.c
icu4c/source/test/cintltst/cdattst.h

index 622a2f311a676902a78a66d003b544d749b88c5e..3b319af65d7ffd30d5450572b0493d91e4c1b35c 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 1997-2012, International Business Machines Corporation and    *
+* Copyright (C) 1997-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 *
@@ -2541,19 +2541,22 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
             && u_isdigit(text.charAt(start))
             && u_isdigit(text.charAt(start+1)))
         {
-            // Assume for example that the defaultCenturyStart is 6/18/1903.
-            // This means that two-digit years will be forced into the range
-            // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
-            // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
-            // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
-            // other fields specify a date before 6/18, or 1903 if they specify a
-            // date afterwards.  As a result, 03 is an ambiguous year.  All other
-            // two-digit years are unambiguous.
-          if(fHaveDefaultCentury) { // check if this formatter even has a pivot year
-              int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
-              ambiguousYear[0] = (value == ambiguousTwoDigitYear);
-              value += (fDefaultCenturyStartYear/100)*100 +
-                (value < ambiguousTwoDigitYear ? 100 : 0);
+               // only adjust year for patterns less than 3.
+               if(count < 3) {
+                       // Assume for example that the defaultCenturyStart is 6/18/1903.
+                       // This means that two-digit years will be forced into the range
+                       // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
+                       // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
+                       // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
+                       // other fields specify a date before 6/18, or 1903 if they specify a
+                       // date afterwards.  As a result, 03 is an ambiguous year.  All other
+                       // two-digit years are unambiguous.
+                       if(fHaveDefaultCentury) { // check if this formatter even has a pivot year
+                               int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
+                               ambiguousYear[0] = (value == ambiguousTwoDigitYear);
+                               value += (fDefaultCenturyStartYear/100)*100 +
+                                               (value < ambiguousTwoDigitYear ? 100 : 0);
+                       }
             }
         }
         cal.set(UCAL_YEAR, value);
index 0d2ab2521d3f189177c3adbaee405a352ed24c62..18cc874efdaeac876b71f3b3648d1acac02a2d43 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 1997-2012, International Business Machines Corporation and
+ * Copyright (c) 1997-2013, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 /********************************************************************************
@@ -36,6 +36,7 @@ static void TestExtremeDates(void);
 static void TestAllLocales(void);
 static void TestRelativeCrash(void);
 static void TestContext(void);
+static void TestCalendarDateParse(void);
 
 #define LEN(a) (sizeof(a)/sizeof(a[0]))
 
@@ -53,6 +54,7 @@ void addDateForTest(TestNode** root)
     TESTCASE(TestAllLocales);
     TESTCASE(TestRelativeCrash);
     TESTCASE(TestContext);
+    TESTCASE(TestCalendarDateParse);
 }
 /* Testing the DateFormat API */
 static void TestDateFormat()
@@ -880,7 +882,101 @@ static void TestDateFormatCalendar() {
     ctest_resetTimeZone();
 }
 
+
+
+/**
+ * Test parsing two digit year against "YY" vs. "YYYY" patterns 
+ */
+static void TestCalendarDateParse() {
+
+       int32_t result;
+       UErrorCode ec = U_ZERO_ERROR;
+    UDateFormat* simpleDateFormat = 0;
+       int parsePos = 0;
+    int twoDigitCenturyStart = 75;
+    int currentTwoDigitYear = 0;
+    int startCentury = 0;
+    UCalendar* tempCal = 0;
+    UCalendar* calendar = 0;
+
+    U_STRING_DECL(pattern, "yyyy", 4);
+    U_STRING_INIT(pattern, "yyyy", 4);
+    U_STRING_DECL(pattern2, "yy", 2);
+    U_STRING_INIT(pattern2, "yy", 2);
+    U_STRING_DECL(text, "75", 2);
+    U_STRING_INIT(text, "75", 2);
+
+    simpleDateFormat = udat_open(UDAT_FULL, UDAT_FULL, "en-GB", 0, 0, 0, 0, &ec);
+    udat_applyPattern(simpleDateFormat, 0, pattern, u_strlen(pattern));
+    udat_setLenient(simpleDateFormat, 0);
+
+    currentTwoDigitYear = getCurrentYear() % 100;
+    startCentury = getCurrentYear() - currentTwoDigitYear;
+    if (twoDigitCenturyStart > currentTwoDigitYear) {
+       startCentury -= 100;
+    }
+       tempCal = ucal_open(NULL, -1, NULL, UCAL_GREGORIAN, &ec);
+       ucal_setMillis(tempCal, 0, &ec);
+       ucal_setDateTime(tempCal, startCentury + twoDigitCenturyStart, UCAL_JANUARY, 1, 0, 0, 0, &ec);
+       udat_set2DigitYearStart(simpleDateFormat, ucal_getMillis(tempCal, &ec), &ec);
+
+       calendar = ucal_open(NULL, -1, NULL, UCAL_GREGORIAN, &ec);
+       ucal_setMillis(calendar, 0, &ec);
+       ucal_setDateTime(calendar, twoDigitCenturyStart, UCAL_JANUARY, 1, 0, 0, 0, &ec);
+
+       udat_parseCalendar(simpleDateFormat, calendar, text, u_strlen(text), &parsePos, &ec);
+
+    /* Check result */
+    result = ucal_get(calendar, UCAL_YEAR, &ec);
+    if (U_FAILURE(ec)) {
+        log_err("FAIL: ucal_get(UCAL_YEAR) failed with %s\n", u_errorName(ec));
+        goto FAIL;
+    }
+
+    if (result != 75) {
+        log_err("FAIL: parsed incorrect year: %d\n", result);
+        goto FAIL;
+    }
+
+    parsePos = 0;
+    udat_applyPattern(simpleDateFormat, 0, pattern2, u_strlen(pattern2));
+       udat_parseCalendar(simpleDateFormat, calendar, text, u_strlen(text), &parsePos, &ec);
+
+    /* Check result */
+    result = ucal_get(calendar, UCAL_YEAR, &ec);
+    if (U_FAILURE(ec)) {
+        log_err("FAIL: ucal_get(UCAL_YEAR) failed with %s\n", u_errorName(ec));
+        goto FAIL;
+    }
+
+    if (result != 1975) {
+        log_err("FAIL: parsed incorrect year: %d\n", result);
+        goto FAIL;
+    }
+
+ FAIL:
+    udat_close(simpleDateFormat);
+    udat_close(tempCal);
+    udat_close(calendar);
+}
+
+
 /*INTERNAL FUNCTIONS USED*/
+static int getCurrentYear() {
+    static int currentYear = 0;
+    if (currentYear == 0) {
+        UErrorCode status = U_ZERO_ERROR;
+        UCalendar *cal = ucal_open(NULL, -1, NULL, UCAL_GREGORIAN, &status);
+        if (!U_FAILURE(status)) {
+            /* Get the current year from the default UCalendar */
+            currentYear = ucal_get(cal, UCAL_YEAR, &status);
+            ucal_close(cal);
+        }
+    }
+
+    return currentYear;
+}
+
 /* N.B.:  use idx instead of index to avoid 'shadow' warnings in strict mode. */
 static void VerifygetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, int32_t idx, const char* expected)
 {
index 7159f88c55cbb0d1d8da13fa522937bdbe427ba0..7fc03251aa89b5c4aa2cf00061acc2a3ffd0f7d2 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 1997-2009, International Business Machines Corporation and
+ * Copyright (c) 1997-2013, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 /********************************************************************************
@@ -49,6 +49,7 @@
      * test subroutine used by the testing functions
      **/
     static UChar* myNumformat(const UNumberFormat* numfor, double d);
+    static int getCurrentYear(void);
 
 #endif /* #if !UCONFIG_NO_FORMATTING */