← Back to team overview

anewt-developers team mailing list archive

[Branch ~uws/anewt/anewt.uws] Rev 1781: [core] Add support for year-week dates to AnewtDateTime

 

------------------------------------------------------------
revno: 1781
committer: Wouter Bolsterlee <uws@xxxxxxxxx>
branch nick: anewt.uws
timestamp: Sat 2010-03-27 21:50:26 +0100
message:
  [core] Add support for year-week dates to AnewtDateTime
  
  AnewtDateTime can now parse ISO8601 year-week dates like
  2010-W12. The result will be a datetime pointing to the
  first day of the week.
modified:
  core/datetime.lib.php
  core/datetime.test.php


--
lp:anewt
https://code.launchpad.net/~uws/anewt/anewt.uws

Your team Anewt developers is subscribed to branch lp:anewt.
To unsubscribe from this branch go to https://code.launchpad.net/~uws/anewt/anewt.uws/+edit-subscription.
=== modified file 'core/datetime.lib.php'
--- core/datetime.lib.php	2010-02-16 00:06:07 +0000
+++ core/datetime.lib.php	2010-03-27 20:50:26 +0000
@@ -37,7 +37,7 @@
 /** Regular expression for day of year */
 define('DATETIME_RE_DAY_OF_YEAR',        '([0-3]\d{2})');
 /** Regular expression for week of year */
-define('DATETIME_RE_WEEK_OF_YEAR',       '([0-4]\d|5[0-3])');
+define('DATETIME_RE_WEEK_OF_YEAR',       '(0[1-9]|[1-4]\d|5[0-3])');
 /** Regular expression for abbreviated day names */
 define('DATETIME_RE_DAY_NAMES_ABBR',    '(Sun|Mon|Tue|Wed|Thu|Fri|Sat)');
 /** Regular expression for abbreviated month names */
@@ -345,6 +345,43 @@
 
 		// ISO 8601: 2005-W02
 		/* TODO: Dates specified by year, week and day. */
+		$pattern = sprintf('/^(%s)-?W(%s)$/', DATETIME_RE_YEAR, DATETIME_RE_WEEK_OF_YEAR);
+		if (preg_match($pattern, $date, $matches) === 1)
+		{
+			$y_not_final = (int) $matches[1];
+			$w = (int) $matches[3];
+
+			/* Too bad, it seems strptime() cannot parse %V correctly, so we
+			 * implement our own logic:
+			 *
+			 *  - start with the beginning of the year
+			 *  - add a very conservative guess of the number of days in the
+			 *    year based on the number of weeks. We need to make sure the
+			 *    date is always too early (hence the $w - 2 below)
+			 *  - repeatedly increment the timestamp with one day until we find
+			 *    the first matching date
+			 */
+
+			/* Find the highest possible week number for the year... */
+			$last_day_of_the_last_week_of_the_year = 31;
+			do {
+				$w_max = (int) strftime('%V', mktime(0, 0, 0, 12, $last_day_of_the_last_week_of_the_year, $y_not_final));
+				$last_day_of_the_last_week_of_the_year--;
+			} while ($w_max == 1);
+
+			/* ... and only proceed if the week number is actually valid for the
+			 * specified year. */
+			if ($w <= $w_max)
+			{
+				$ts = mktime(0, 0, 0, 1, 1, $matches[1]);
+				$ts += ($w - 2) * 7 * 24 * 60 * 60;
+
+				while ((int) strftime('%V', $ts) != $w)
+					$ts += 24 * 60 * 60;
+
+				list ($y, $m, $d) = explode('-', strftime('%Y-%m-%d', $ts));
+			}
+		}
 
 
 		// MS SQL default format: Mon Jan 23 00:00:00 2006

=== modified file 'core/datetime.test.php'
--- core/datetime.test.php	2009-07-20 20:39:48 +0000
+++ core/datetime.test.php	2010-03-27 20:50:26 +0000
@@ -53,7 +53,14 @@
 f('Fri, 21 Nov 1997 09:55:06 -0600');
 f('Fri, 21 Nov 1997 09:55:06 +0630');
 
-echo '(There should only be empty lines below)', NL;
+f('2010-W01');
+f('2010-W02');
+f('2009W53');
+echo 'This one should be empty:', NL;
+f('2010-W53');
+f('2013-W01');
+
+echo 'There should only be empty lines below:', NL;
 f(null);