← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~paul-lucas/zorba/bug-1167704 into lp:zorba

 

Paul J. Lucas has proposed merging lp:~paul-lucas/zorba/bug-1167704 into lp:zorba.

Commit message:
Added correct support for 'w' in format-date(), etc., functions now that the W3C has resolved the issue.

Requested reviews:
  Paul J. Lucas (paul-lucas)
Related bugs:
  Bug #1167704 in Zorba: "Implement [w] for ISO calendars for format-date/time functions"
  https://bugs.launchpad.net/zorba/+bug/1167704

For more details, see:
https://code.launchpad.net/~paul-lucas/zorba/bug-1167704/+merge/160437

Added correct support for 'w' in format-date(), etc., functions now that the W3C has resolved the issue.
-- 
https://code.launchpad.net/~paul-lucas/zorba/bug-1167704/+merge/160437
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'ChangeLog'
--- ChangeLog	2013-04-19 23:41:38 +0000
+++ ChangeLog	2013-04-23 17:00:37 +0000
@@ -43,6 +43,7 @@
   * Fixed bug #1123836 (overflows in date/time casts now return FODT0001 and
     in durations return FODT0002)
   * Fixed bug #1147518 (fn:round-half-to-even (at least 11 failures))
+  * Fixed bug #1167704 (Implement [w] for ISO calendars for format-date/time functions)
   * Fixed bug #1114228 (unrecognized options in the XQuery namespace now raise an error)
   * Fixed bug #1124273 (xqdoc crash because of annotation literals)
   * Fixed bug #1085408 (xs:date(): casting large year values)

=== modified file 'src/runtime/durations_dates_times/format_dateTime.cpp'
--- src/runtime/durations_dates_times/format_dateTime.cpp	2013-03-29 15:31:51 +0000
+++ src/runtime/durations_dates_times/format_dateTime.cpp	2013-04-23 17:00:37 +0000
@@ -561,6 +561,19 @@
   }
 }
 
+static void append_week_in_month( unsigned mday, unsigned mon, unsigned year,
+                                  modifier const &mod, zstring *dest ) {
+  int week = time::calendar::calc_week_in_month( mday, mon, year, mod.cal );
+  if ( week == -1 ) {
+    week = time::calendar::calc_week_in_month( mday, mon, year, calendar::ISO );
+    ostringstream oss;
+    // TODO: localize "Calendar"
+    oss << "[Calendar: " << calendar::string_of[ calendar::ISO ] << ']';
+    *dest += oss.str();
+  }
+  append_number( week, mod, dest );
+}
+
 static void append_week_in_year( unsigned mday, unsigned mon, unsigned year,
                                  modifier const &mod, zstring *dest ) {
   int week = time::calendar::calc_week_in_year( mday, mon, year, mod.cal );
@@ -1265,7 +1278,10 @@
           );
           break;
         case 'w':
-          append_number( dateTime.getWeekInMonth(), mod, &result_str );
+          append_week_in_month(
+            dateTime.getDay(), dateTime.getMonth() - 1, dateTime.getYear(),
+            mod, &result_str
+          );
           break;
         case 'Y':
           append_year( std::abs( dateTime.getYear() ), mod, &result_str );

=== modified file 'src/unit_tests/test_time.cpp'
--- src/unit_tests/test_time.cpp	2013-03-22 19:04:51 +0000
+++ src/unit_tests/test_time.cpp	2013-04-23 17:00:37 +0000
@@ -48,6 +48,62 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+static void test_calc_week_in_month() {
+  struct test_type {
+    unsigned mday, mon, year;
+    time::calendar::type cal;
+    int expected;
+  };
+  static test_type const test[] = {
+    /*  1 */ {  1, time::jan, 2013, calendar::AD, 1 },
+    /*  2 */ {  2, time::jan, 2013, calendar::AD, 1 },
+    /*  3 */ {  3, time::jan, 2013, calendar::AD, 1 },
+    /*  4 */ {  4, time::jan, 2013, calendar::AD, 1 },
+    /*  5 */ {  5, time::jan, 2013, calendar::AD, 1 },
+    /*  6 */ {  6, time::jan, 2013, calendar::AD, 2 },
+    /*  7 */ {  1, time::feb, 2013, calendar::AD, 1 },
+    /*  8 */ {  1, time::jun, 2013, calendar::AD, 1 },
+    /*  9 */ {  2, time::jun, 2013, calendar::AD, 2 },
+    /* 10 */ { 28, time::dec, 2013, calendar::AD, 4 },
+    /* 11 */ { 31, time::dec, 2013, calendar::AD, 5 },
+
+    /* 12 */ {  1, time::jan, 2013, calendar::ISO, 1 },
+    /* 13 */ {  2, time::jan, 2013, calendar::ISO, 1 },
+    /* 14 */ {  3, time::jan, 2013, calendar::ISO, 1 },
+    /* 15 */ {  4, time::jan, 2013, calendar::ISO, 1 },
+    /* 16 */ {  5, time::jan, 2013, calendar::ISO, 1 },
+    /* 17 */ {  6, time::jan, 2013, calendar::ISO, 1 },
+    /* 18 */ {  7, time::jan, 2013, calendar::ISO, 2 },
+    /* 19 */ {  1, time::feb, 2013, calendar::ISO, 5 },
+    /* 20 */ {  1, time::jan, 2005, calendar::ISO, 5 },
+    /* 21 */ {  2, time::jan, 2005, calendar::ISO, 5 },
+    /* 22 */ {  3, time::jan, 2005, calendar::ISO, 1 },
+    /* 23 */ { 31, time::dec, 2005, calendar::ISO, 5 },
+    /* 24 */ {  1, time::jan, 2007, calendar::ISO, 1 },
+    /* 25 */ { 30, time::dec, 2007, calendar::ISO, 4 },
+    /* 26 */ { 31, time::dec, 2007, calendar::ISO, 1 },
+    /* 27 */ {  1, time::jan, 2008, calendar::ISO, 1 },
+    /* 28 */ { 28, time::dec, 2008, calendar::ISO, 4 },
+    /* 29 */ { 29, time::dec, 2008, calendar::ISO, 5 },
+    /* 30 */ { 30, time::dec, 2008, calendar::ISO, 5 },
+    /* 31 */ { 31, time::dec, 2008, calendar::ISO, 5 },
+    /* 32 */ { 31, time::dec, 2009, calendar::ISO, 5 },
+    /* 33 */ {  1, time::jan, 2010, calendar::ISO, 5 },
+    /* 34 */ {  2, time::jan, 2010, calendar::ISO, 5 },
+    /* 35 */ {  3, time::jan, 2010, calendar::ISO, 5 },
+    /* 36 */ {  4, time::jan, 2010, calendar::ISO, 1 },
+
+    { 0, 0, 0, calendar::unknown, 0 }
+  };
+
+  test_no = 0;
+  for ( test_type const *t = test; t->mday; ++t ) {
+    int w = calendar::calc_week_in_month( t->mday, t->mon, t->year, t->cal );
+    ++test_no;
+    ASSERT_TRUE( test_no, w == t->expected );
+  }
+}
+
 static void test_calc_week_in_year() {
   struct test_type {
     unsigned mday, mon, year;
@@ -93,10 +149,11 @@
     { 0, 0, 0, calendar::unknown, 0 }
   };
 
+  test_no = 0;
   for ( test_type const *t = test; t->mday; ++t ) {
     int w = calendar::calc_week_in_year( t->mday, t->mon, t->year, t->cal );
     ++test_no;
-    ASSERT_TRUE( test_no,  w == t->expected );
+    ASSERT_TRUE( test_no, w == t->expected );
   }
 }
 
@@ -107,6 +164,7 @@
 
 int test_time( int, char*[] ) {
 
+  test_calc_week_in_month();
   test_calc_week_in_year();
 
   cout << failures << " test(s) failed\n";

=== modified file 'src/util/time_util.cpp'
--- src/util/time_util.cpp	2013-03-25 14:48:29 +0000
+++ src/util/time_util.cpp	2013-04-23 17:00:37 +0000
@@ -108,6 +108,43 @@
   "VS"    // Vikrama Samvat Era
 };
 
+int calc_week_in_month( unsigned mday, unsigned mon, unsigned year, type cal ) {
+  int mon1_wday = time::calc_wday( 1, mon, year );
+
+  switch ( cal ) {
+    case AD:
+      return (mon1_wday + mday - 1) / 7 + 1;
+    case ISO: {
+      //
+      // From https://www.w3.org/Bugs/Public/show_bug.cgi?id=21370#c6
+      //
+      //    When the 'w' component is used, the convention to be adopted is
+      //    that each Monday-to-Sunday week is considered to fall within a
+      //    particular month if its Thursday occurs in that month; the weeks
+      //    that fall in a particular month under this definition are numbered
+      //    starting from 1. Thus, for example, 29 January 2013 falls in week 5
+      //    because the Thursday of the relevant week (31 January 2013) is the
+      //    fifth Thursday in January, and 1 February 2013 is also in week 5
+      //    for the same reason.
+      //
+      mon1_wday = convert_wday_to( mon1_wday, cal );
+      int week = (mday + mon1_wday - 2) / 7 + 1;
+      if ( mon1_wday > iso8601::thu && !--week )
+        return 5;                       // week is part of previous month
+
+      int const wday =
+        convert_wday_to( time::calc_wday( mday, mon, year ), cal );
+      int const yday = time::calc_yday( mday, mon, year );
+      if ( time::days_in_year( year ) - yday + 1 < iso8601::thu - wday )
+        return 1;                       // date falls in week 1 of next year
+
+      return week;
+    }
+    default:
+      return -1;
+  }
+}
+
 int calc_week_in_year( unsigned mday, unsigned mon, unsigned year, type cal ) {
   int yday = time::calc_yday( mday, mon, year );
   int jan1_wday = time::calc_wday( 1, time::jan, year );
@@ -121,15 +158,15 @@
       jan1_wday = convert_wday_to( jan1_wday, cal );
 
       if ( jan1_wday > iso8601::thu && jan1_wday + yday <= 8 ) {
-        // date falls in week 52 or 53 of the previous year
+        // date falls in week 52 or 53 of previous year
         return  52
               + (jan1_wday == iso8601::fri ||
                 (jan1_wday == iso8601::sat && time::is_leap_year( year - 1 )));
       }
       int const wday =
         convert_wday_to( time::calc_wday( mday, mon, year ), cal );
-      if ( time::days_in_year( year ) - yday < 4 - wday ) {
-        // date falls in week 1 of the next year
+      if ( time::days_in_year( year ) - yday < iso8601::thu - wday ) {
+        // date falls in week 1 of next year
         return 1;
       }
       return  (yday + (7 - wday) + (jan1_wday - 1)) / 7

=== modified file 'src/util/time_util.h'
--- src/util/time_util.h	2013-04-10 22:41:09 +0000
+++ src/util/time_util.h	2013-04-23 17:00:37 +0000
@@ -80,10 +80,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-/**
- * XQuery 3.0 F&O: 9.8.4.3: The calendars listed below were known to be in use
- * during the last hundred years.
- */
 namespace calendar {
   extern char const* const string_of[];
 
@@ -99,7 +95,20 @@
   }
 
   /**
-   * Calculates the week number for the given date and calendar.
+   * Calculates the week number of the month for the given date and calendar.
+   *
+   * @param mday The month day [1-31].
+   * @param mon The month [0-11].
+   * @param year The year.
+   * @param cal The calendar.
+   * @return Returns the week [1-5] or -1 if it is unknown how to perform the
+   * calculation for \a cal.
+   */
+  int calc_week_in_month( unsigned mday, unsigned mon, unsigned year,
+                          type cal );
+
+  /**
+   * Calculates the week number of the year for the given date and calendar.
    *
    * @param mday The month day [1-31].
    * @param mon The month [0-11].

=== modified file 'src/zorbatypes/datetime.h'
--- src/zorbatypes/datetime.h	2013-03-20 15:08:29 +0000
+++ src/zorbatypes/datetime.h	2013-04-23 17:00:37 +0000
@@ -252,8 +252,6 @@
 
   static int getDayOfYear(int year, int month, int day);
 
-  static int getWeekInMonth(int year, int month, int day);
-
 protected:
   static int parse_date(
         const char* str,
@@ -356,8 +354,7 @@
    *  DateTime does not have a Date or DateTime facet, the function will return -1.
    */ 
   int getDayOfYear() const;
-  int getWeekInMonth() const;
-      
+
 protected:
   Duration* toDayTimeDuration() const;
 

=== modified file 'src/zorbatypes/datetime/datetimetype.cpp'
--- src/zorbatypes/datetime/datetimetype.cpp	2013-04-03 09:33:11 +0000
+++ src/zorbatypes/datetime/datetimetype.cpp	2013-04-23 17:00:37 +0000
@@ -1431,23 +1431,10 @@
 }
 
 
-int DateTime::getWeekInMonth(int year, int month, int day)
-{
-  int const wday = time::calc_wday( 1, month - 1, year );
-  return ((day + wday - 2) / 7) + (wday < 5 ? 1 : 0);
-}
-
-
 int DateTime::getDayOfYear() const
 {
   return getDayOfYear(data[YEAR_DATA], data[MONTH_DATA], data[DAY_DATA]);
 }
 
-
-int DateTime::getWeekInMonth() const
-{
-  return getWeekInMonth(data[YEAR_DATA], data[MONTH_DATA], data[DAY_DATA]);
-}
-
-} // namespace xqp
+} // namespace zorba
 /* vim:set et sw=2 ts=2: */

=== modified file 'test/fots/CMakeLists.txt'
--- test/fots/CMakeLists.txt	2013-04-23 13:55:03 +0000
+++ test/fots/CMakeLists.txt	2013-04-23 17:00:37 +0000
@@ -125,6 +125,7 @@
 EXPECTED_FOTS_FAILURE (DISPUTED fn-format-date format-date-en132 21423)
 EXPECTED_FOTS_FAILURE (DISPUTED fn-format-date format-date-en133 21423)
 EXPECTED_FOTS_FAILURE (DISPUTED fn-format-date format-date-en134 21423)
+EXPECTED_FOTS_FAILURE (DISPUTED fn-format-dateTime format-dateTime-011 21794)
 EXPECTED_FOTS_FAILURE (DISPUTED fn-format-integer format-integer-044 21448)
 EXPECTED_FOTS_FAILURE (DISPUTED fn-format-date format-date-en152 21558)
 EXPECTED_FOTS_FAILURE (DISPUTED fn-format-dateTime format-dateTime-en152 21558)
@@ -164,7 +165,6 @@
 EXPECTED_FOTS_FAILURE (fn-environment-variable environment-variable-006 0)
 EXPECTED_FOTS_FAILURE (fn-environment-variable environment-variable-007 0)
 EXPECTED_FOTS_FAILURE (fn-format-dateTime format-dateTime-006 0)
-EXPECTED_FOTS_FAILURE (fn-format-dateTime format-dateTime-011 0)
 EXPECTED_FOTS_FAILURE (fn-format-number numberformat41 1167427)
 EXPECTED_FOTS_FAILURE (fn-format-number numberformat42 1167427)
 EXPECTED_FOTS_FAILURE (fn-format-number numberformat60a 1167609)


Follow ups