Markus, Fabian, and all:

This patch (patch.3) implements Old Style date processing in SMW_DV_Time.php. This requires the patch I sent earlier, so I am re-enclosing it today.

The English Old Style is slightly more complex than a simple preference for Julian calendar processing. According to the Old Style, the year began on March 25, /not/ January 1. Therefore the date "March 20, 1648 OS" is actually March 30, 1649 in the Gregorian calendar, not 1648. Therefore, Old Style processing requires an increment of the year for all dates between 1 January and 24 March inclusive, and calculating a date according to Julian rules.

This patch also changes the regex for calendar symbols to be strictly case-sensitive. This is required because the regex [ABOabo][DCSdcs] will match on "October" and make all dates in October unrecognizable. The simple regex (AD|BC|OS) will match those three letter pairs and no other.

This patch also tells the function parseXSDValue($value,$unit) to execute the createJD($model) function and create a Julian Day. Back-conversion will occur only if the JD is suitable for such conversion.

I have tested this datatype on a wide variety of dates. All are acceptable, and all process as intended.

I am open to suggestions about how to signal a Julian date beyond the proclamation of the Gregorian calendar.

The Hebrew calendar will be next.

Temlakos
--- ../SemanticMediaWiki-lng/SMW_DV_Time.php    2009-08-11 00:02:44.000000000 
-0400
+++ ./SMW_DV_Time.php   2009-08-11 11:03:39.000000000 -0400
@@ -20,7 +20,11 @@
  * All dates are supposed to refer either to the Gregorian calendar (October 
15, 1582
  * or later), or to the Julian calendar (earlier than October 15, 1582 
Gregorian). Any
  * date specified between October 5 and October 14, 1582 inclusive, will be 
recalculated
- * according to the Julian calendar. Other calendar-model support is planned.
+ * according to the Julian calendar. The "OS" (Old Style) symbol is supported 
in English,
+ * and dates annotated with this symbol are processed accordingly: the year is 
incremented
+ * by one if the date falls between 1 January and 24 March inclusive, and the 
resultant
+ * day is converted according to Julian rules, but the printout is either 
Gregorian or
+ * Julian according to the epoch. Other calendar-model support is planned.
  * Historical dates are, however, still experimental.
  *
  * This type can handle dates across history with full precision for storing, 
and
@@ -74,11 +78,12 @@
        protected $m_wikivalue; // a suitable wiki input value
        protected $m_xsdvalue = false; // cache for XSD value
        protected $m_printvalue = false; // cache for printout value
+       protected $m_pref = false; // holds a symbol for the calendar model
        protected $m_day = false; //Gregorian day, remains false if unspecified
        protected $m_month = false; //Gregorian month, remains false if 
unspecified
        protected $m_year = false; //Gregorian year, remains false if 
unspecified
        protected $m_time = false; //time, remains false if unspecified
-       protected $m_jd = ''; //numerical time representation similiar to 
Julian Day; for ancient times, a more compressed number is used (preserving 
ordering of time points)
+       protected $m_jd = 0; //numerical time representation similiar to Julian 
Day; for ancient times, a more compressed number is used (preserving ordering 
of time points)
        protected $m_format = false; // number of parts of the date that were 
specified
        protected $m_timeoffset; //contains offset (e.g. timezone) 
        protected $m_timeannotation; //contains am or pm
@@ -110,13 +115,13 @@
                global $smwgContLang;
 
                $band = false; //group of bits storing information about the 
possible meaning of each digit of the entered date
+               $this->m_pref = false;
                $this->m_day = false;
                $this->m_month = false;
                $this->m_year = false;
                $this->m_jd = false;
                $this->m_time = false;
                $this->m_timeoffset = 0;
-               $this->m_timepm = false;
                $this->m_timeannotation = false;
                $this->m_format = false;
 
@@ -131,10 +136,11 @@
                  $filteredvalue = preg_replace($regexp,'', $filteredvalue); 
//value without am/pm
                }
 
-               //browse string for special abbreviations referring to year 
like AD, BC
+               //browse string for special abbreviations referring to year 
like AD, BC, and OS
                $is_yearbc = false;
-               if(preg_match("/[ABab][DCdc]/u", $filteredvalue, $match)){
-                       if ( strtoupper($match[0]) == 'BC' ) {
+               if(preg_match("/(AD|BC|OS)/u", $filteredvalue, $match)){
+                       $this->m_pref = strtoupper($match[0]);
+                       if ($this->m_pref == 'BC') {
                                $is_yearbc = true;
                        }
                        $regexp = "/(\040|T){0,1}".str_replace("+", "\+", 
$match[0])."(\040){0,1}/u"; //delete ad/bc value and preceding and following 
chars
@@ -254,13 +260,21 @@
                        return true;
                }
 
+               // Handle OS: Increment the year if earlier than March 25.
+               if ($this->m_pref == 'OS') {
+                       if(($this->m_month < 3) || (($this->m_month == 3) && 
($this->m_day < 25))) {
+                               $this->m_year++;
+                       } 
+               }
+
+               // Handle BC: the year is negative.
                if ($is_yearbc) {
                        if ($this->m_year > 0) { // see class documentation on 
BC, "year 0", and ISO conformance ...
                                $this->m_year = -($this->m_year);
                        }
                }
 
-               //handle offset
+               //Make the JD value and handle offset if applicable
                $this->createJD($this->findModel());
                if ($this->m_jd > -0.5) {
                        $this->m_jd = $this->m_jd - $this->m_timeoffset;
@@ -309,6 +323,10 @@
 
        // finds the appropriate model to use.
        protected function findModel() {
+               if ($this->m_pref == 'OS') {
+                       $this->m_pref = ''; // Erase the OS marker; it will not 
be needed after this.
+                       return 'JU'; // Old Style dates are converted per 
Julian rules.
+               }
                if ($this->m_year > 1582) {
                        return 'GR'; // All dates after 1582 are Gregorian 
dates.
                }
@@ -327,6 +345,10 @@
                if (count($d)==3) 
list($this->m_year,$this->m_month,$this->m_day) = $d;
                elseif (count($d)==2) list($this->m_year,$this->m_month) = $d;
                elseif (count($d)==1) list($this->m_year) = $d;
+               $this->createJD($this->findModel());
+               if($this->m_jd > -0.5) {//Back-convert only if the JD is 
suitable for that
+                       $this->JD2Date();
+               }
                $this->makePrintoutValue();
                $this->m_caption = $this->m_printvalue;
                $this->m_wikivalue = $this->m_printvalue;
--- ../SemanticMediaWiki-lng/SMW_DV_Time.php	2009-08-10 16:42:58.000000000 -0400
+++ ./SMW_DV_Time.php	2009-08-10 23:40:13.000000000 -0400
@@ -6,23 +6,24 @@
 
 /**
  * This datavalue captures values of dates and times. All dates and times refer to
- * the "local time" of the server (or the wiki). A wiki may define what timezone this
- * refers to by common conventions. For export, times are given without timezone
- * information. However, time offsets to that local time are supported (see below).
+ * Coordinated Universal Time (UTC), or the local time of the wiki server.
+ * A wiki may define what timezone this refers to by common conventions.
+ * For export, times are given without timezone information. However, time offsets to
+ * that local time, or to UTC, are supported (see below). The difference is arbitrary.
  *
  * Dates can be given in many formats, using numbers, month names, and abbreviated
  * month names. The preferred interpretation of ambiguous dates ("1 2 2008" or even
  * "1 2 3 BC") is controlled by the language file, as is the local naming of months.
  * English month names are always supported. Currently, the additions "AM", "PM", "BC",
- * and "AD" are supported, but not localised to other languages.
+ * and "AD" are supported, but not (yet) localised to other languages.
  *
- * There is currently no support for different calendar models or conversion between
- * them. All dates are supposed to refer to Gregorian calendar (or its extension to
- * the past, the proleptic Gregorian claendar). Attention: this may change in future
- * versions, and historical dates may be treated as Julian calendar dates in certain
- * ranges. Consider historical dates to be experimental.
+ * All dates are supposed to refer either to the Gregorian calendar (October 15, 1582
+ * or later), or to the Julian calendar (earlier than October 15, 1582 Gregorian). Any
+ * date specified between October 5 and October 14, 1582 inclusive, will be recalculated
+ * according to the Julian calendar. Other calendar-model support is planned.
+ * Historical dates are, however, still experimental.
  *
- * It is able to handle dates across history with full precision for storing, and
+ * This type can handle dates across history with full precision for storing, and
  * substantial precision for sorting and querying. The range of supported past dates
  * should encompass the Beginning of Time according to most of today's theories. The
  * range of supported future dates is limited more strictly, but it does also allow
@@ -41,25 +42,30 @@
  * The implementation notices and stores whether parts of a date/time have been
  * omitted (as in "2008" or "May 2007"). For all exporting and sorting purposes,
  * incomplete dates are completed with defaults (usually using the earliest possible
- * time, i.e. interpreting "2008" as "Jan 1 2008 00:00:00"). But the information
+ * time, i.e. interpreting "2008" as "Jan 1 2008 00:00:00"). The information
  * on what was unspecified is kept internally for improving behaviour e.g. for
  * outputs (defaults are not printed when querying for a value). Functions are
  * provided to access the individual time components (getYear, getMonth, getDay,
  * getTimeString), and those can also be used to find out what was unspecified.
  *
- * Time offests are supported (e.g. "1 1 2008 12:00-2:00"). As explained above, those
- * refer to the local time. Time offsets take leap years into account, e.g. the date
+ * Time offsets are supported (e.g. "1 1 2008 12:00-2:00"). A time offset is the number
+ * of hours:minutes to be added to UTC (GMT) to obtain the local-clock reading. Time zone
+ * monikers (EST, CST, CET, MEZ, etc.) and military time (e.g. 1240Z, equivalent to 12:40
+ * UTC) are also supported.
+ *
+ * Time offsets take leap years into account, e.g. the date
  * "Feb 28 2004 23:00+2:00" is equivalent to "29 February 2004 01:00:00", while
  * "Feb 28 1900 23:00+2:00" is equivalent to "1 March 1900 01:00:00".
  *
- * @todo Add support for different calendar models (mainly requires to settle how this
- * should be specified in various languages).
+ * @todo Add support for additional calendar models (mainly requires conversion algorithms and
+ * internationalization support).
  * @todo Internationalise the treatment of AD, BC, PM, AM. Add more formats (p.m. or BCE).
  * @todo Try to reuse more of MediaWiki's records, e.g. to obtain month names or to
  * format dates. The problem is that MW is based on SIO timestamps that don't extend to
  * very ancient or future dates, and that MW uses PHP functions that are bound to UNIX time.
  *
  * @author Fabian Howahl
+ * @author Terry A. Hurlbut
  * @author Markus Krötzsch
  * @ingroup SMWDataValues
  */
@@ -73,6 +79,7 @@
 	protected $m_year = false; //Gregorian year, remains false if unspecified
 	protected $m_time = false; //time, remains false if unspecified
 	protected $m_jd = ''; //numerical time representation similiar to Julian Day; for ancient times, a more compressed number is used (preserving ordering of time points)
+	protected $m_format = false; // number of parts of the date that were specified
 	protected $m_timeoffset; //contains offset (e.g. timezone) 
 	protected $m_timeannotation; //contains am or pm
 	// The following are constant (array-valued constants are not supported, hence the decalration as variable):
@@ -96,6 +103,9 @@
 		"U" => -8, "UTC" => 0, "V" => -9, "W" => -10, "WDT" => 9, "WEDT" => 1,
 		"WEST" => 1, "WET" => 0, "WST" => 8, "X" => -11, "Y" => -12, "Z" => 0);
 
+// constant epochal values
+	const J1582 = 2299160.5;	// Date of switchover to Gregorian calendar
+
 	protected function parseUserValue($value) {
 		global $smwgContLang;
 
@@ -108,6 +118,7 @@
 		$this->m_timeoffset = 0;
 		$this->m_timepm = false;
 		$this->m_timeannotation = false;
+		$this->m_format = false;
 
 		$value = trim($value); // ignore whitespace
 		$this->m_wikivalue = $value;
@@ -245,13 +256,13 @@
 
 		if ($is_yearbc) {
 			if ($this->m_year > 0) { // see class documentation on BC, "year 0", and ISO conformance ...
-				$this->m_year = -($this->m_year-1);
+				$this->m_year = -($this->m_year);
 			}
 		}
 
 		//handle offset
-		if ($this->m_timeoffset != 0) {
-			$this->createJD();
+		$this->createJD($this->findModel());
+		if ($this->m_jd > -0.5) {
 			$this->m_jd = $this->m_jd - $this->m_timeoffset;
 			$this->JD2Date();
 		}
@@ -296,6 +307,20 @@
 		}
 	}
 
+	// finds the appropriate model to use.
+	protected function findModel() {
+		if ($this->m_year > 1582) {
+			return 'GR'; // All dates after 1582 are Gregorian dates.
+		}
+		if (($this->m_year == 1582) && ($this->m_month > 10)) {
+			return 'GR'; // The Gregorian calendar was inaugurated after October 4, 1582.
+		}
+		if (($this->m_year == 1582) && ($this->m_month == 10) && ($this->m_day > 4)) {
+			return 'GR';
+		} // Set $model to 'JU'
+		return 'JU';
+	}
+
 	protected function parseXSDValue($value, $unit) {
 		list($date,$this->m_time) = explode('T',$value,2);
 		$d = explode('/',$date,3);
@@ -336,7 +361,6 @@
 	}
 
 	public function getNumericValue() {
-		$this->createJD();
 		return $this->m_jd;
 	}
 
@@ -346,7 +370,6 @@
 
 	public function getHash() {
 		if ($this->isValid()) {
-			$this->createJD();
 			return strval($this->m_jd);
 		} else {
 			return implode("\t", $this->m_errors);
@@ -367,7 +390,7 @@
 	}
 
 	/**
-	 * Return the year as a number corresponding to the year in the proleptic
+	 * Return the year as a number corresponding to the year in the Julian or
 	 * Gregorian calendar and using the astronomical year numbering (0 means 1 BC).
 	 */
 	public function getYear() {
@@ -375,7 +398,7 @@
 	}
 
 	/**
-	 * Return the month as a number (between 1 and 12) based on the proleptic
+	 * Return the month as a number (between 1 and 12) based on the Julian or
 	 * Gregorian calendar.
 	 * The parameter $default optionally specifies the value returned
 	 * if the date is valid but has no explicitly specified month. It can
@@ -386,7 +409,7 @@
 	}
 
 	/**
-	 * Return the day as a number based on the proleptic Gregorian calendar.
+	 * Return the day as a number based on the Julian or Gregorian calendar.
 	 * The parameter $default optionally specifies the value returned
 	 * if the date is valid but has no explicitly specified date. It can
 	 * also be set to FALSE to detect this situation.
@@ -443,7 +466,7 @@
 			if ($this->m_year > 0) {
 				$this->m_printvalue = number_format($this->m_year, 0, '.', ''); // note: there should be no digits after the comma anyway
 			} else {
-				$this->m_printvalue = number_format(-($this->m_year-1), 0, '.', '') . ' BC'; // note: there should be no digits after the comma anyway
+				$this->m_printvalue = number_format(-($this->m_year), 0, '.', '') . ' BC'; // note: there should be no digits after the comma anyway
 			}
 			if ($this->m_month) {
 				$this->m_printvalue =  $smwgContLang->getMonthLabel($this->m_month) . " " . $this->m_printvalue;
@@ -475,42 +498,94 @@
 	}
 
 	/**
+	 * This function adds a time fraction to any Julian Day.
+	 */
+	 protected function createTime(){
+		if ($this->m_time != false) { //Calculate fraction only if time is set -- the default time is 0
+			list ($hours, $minutes, $seconds) = explode(':',$this->getTimeString(),3);
+			$time = ($hours/24) + ($minutes / (60*24)) + ($seconds / (3600*24));
+			$this->m_jd += $time;
+		}
+	 }
+
+	/**
 	 * This function computes a numerical value based on the currently set date. If the year is
-	 * grater or equal to -4712 (4713 BC), then (something that is closely inspired by) the Julian Day
+	 * greater or equal to -4712 (4713 BC), then (something that is closely inspired by) the Julian Day
 	 * (JD) is computed. The JD has the form XXXX.YYYY where XXXX is the number of days having elapsed since
-	 * 4713 BC and YYYY is the elapsed time of the day as fraction of 1. See http://en.wikipedia.org/wiki/Julian_day
+	 * noon on 1 January 4713 BC and YYYY is the elapsed time of the day as fraction of 1.
+	 * See http://en.wikipedia.org/wiki/Julian_day
 	 * If the year is before -4713, then the computed number XXXX.YYYY has the following form: XXXX is 
 	 * the number of years BC and YYYY represents the elapsed days of the year as fraction of 1. This
 	 * enables even large negative dates using 32bit floats.
 	 *
-	 * @note The result of this function is used only internally and should not be assumed to be the
-	 * exact JD, even for dates after 4713 BC. The reason is that the time information used in this number is
-	 * based on the local timezone of the wiki (see class documentation), and not necessarily normalized
-	 * to Greenwhich noon. The JD computation, however, is based on proleptic Gregorian calendar, and hence
-	 * is precise for the current input conventions.
+	 * @note The result of this function is used only internally. It should not be assumed to be the
+	 * exact JD, even for dates after 4713 BC, unless a proper time-zone offset or moniker is specified.
 	 */
-	protected function createJD(){
+	protected function createJD($model) {
+		switch($model) {
+			case "GR":
+				$this->gregorian2JD();
+				break;
+			case "JU":
+				$this->julian2JD();
+				break;
+		}
+		$this->createTime();
+	}
+
+	/// Calculate a Julian day according to Gregorian calendar rules
+	protected function gregorian2JD(){
 		$this->m_jd = 0;
-		if ($this->m_year >= -4712) {
-			$a = intval((14-$this->getMonth())/12);
-			$y = $this->m_year + 4800 - $a;
-			$m = $this->getMonth() + 12 * $a - 3;
-
-			if ($this->m_time != false) { //just calculate fraction if time is set -- the default time is 0 anyway
-				list ($hours, $minutes, $seconds) = explode(':',$this->getTimeString(),3);
-				$time = ($hours/24) + ($minutes / (60*24)) + ($seconds / (3600*24));
-				$this->m_jd += $time;
-			}
-			$this->m_jd += $this->getDay() + intval((153*$m+2)/5) + 365*$y + intval($y/4) - intval($y/100) + intval($y/400) - 32045;
+		$a = intval((14-$this->getMonth())/12);
+		$y = $this->m_year + 4800 - $a;
+		$m = $this->getMonth() + 12 * $a - 3;
+		$this->m_jd += $this->getDay() + intval((153*$m+2)/5) + 365*$y + intval($y/4) - intval($y/100) + intval($y/400) - 32045.5;
+		$this->m_format = ($this->m_day != false) ? 3 : (($this->m_month != false) ? 2 : 1);
+	}
+
+	/// Calculate a Julian day according to Julian calendar rules
+	protected function julian2JD(){
+		if ($this->m_year >= -4713) {
+			$this->m_jd = 0;
+			$y1 = ($this->m_year < 1) ? ($this->m_year + 1) : $this->m_year;
+			$m1 = $this->getMonth();
+			$y2 = ($m1 <= 2) ? ($y1 - 1) : $y1;
+			$m2 = ($m1 <= 2) ? ($m1 + 12) : $m1;
+			$this->m_jd += intval((365.25 * ($y2 + 4716))) + intval((30.6001 * ($m2+1))) + $this->getDay() - 1524.5;
 		} else { // starting from the time when JD would be negative, use our own "stretched" representation, currently this just ignores local time
 			$time = 1 - (($this->getMonth() / 12) + ($this->getDay() / 365));
 			$this->m_jd = $this->m_year - $time;
 		}
+		$this->m_format = ($this->m_day != false) ? 3 : (($this->m_month != false) ? 2 : 1);
 	}
 
-	/// Convert Julian Day (see createJD) back to a proleptic Gregorian date.
+	/// Convert the Julian Day fraction to the time string.
+	protected function fracToTime() {
+		$wjd = $this->m_jd + 0.5;
+		$fraction = $wjd - intval($wjd);
+		$time = round($fraction * 3600 * 24);
+		$hours = intval($time / 3600);
+		$time = $time - $hours * 3600;
+		$minutes = intval($time / 60);
+		$seconds = intval($time - $minutes * 60);
+		$this->m_time = $this->normalizeValue($hours).":".$this->normalizeValue($minutes).":".$this->normalizeValue($seconds);
+	}
+
+	/// Convert Julian Day to m_year, m_month, and m_day according to the proper model.
 	protected function JD2Date() {
-		$j = intval($this->m_jd) + 32044;
+		if($this->m_jd < self::J1582) {
+			$this->JD2Julian();
+		} else {
+			$this->JD2Gregorian();
+		}
+		if($this->m_time != false) { // Do not fill this in if it was not filled in to begin with
+			$this->fracToTime();
+		}
+	}
+
+	/// Convert Julian Day (see createJD) back to a Gregorian date.
+	protected function JD2Gregorian() {
+		$j = intval($this->m_jd + 0.5) + 32044;
 		$g = intval($j / 146097);
 		$dg = $j % 146097;
 		$c = intval(((intval($dg / 36524) + 1) * 3) / 4);
@@ -523,17 +598,21 @@
 		$m = intval(($da * 5 + 308) / 153) - 2;
 		$d = $da - intval((($m + 4) * 153) / 5) + 122;
 		$this->m_year = $y - 4800 + intval(($m + 2) / 12);
-		$this->m_month = ($m + 2) % 12 + 1;
-		$this->m_day = $d + 1;
-
-		$fraction = $this->m_jd - intval($this->m_jd);
-		$time = round($fraction * 3600 * 24);
-		$hours = intval($time / 3600);
-		$time = $time - $hours * 3600;
-		$minutes = intval($time / 60);
-		$seconds = intval($time - $minutes * 60);
+		$this->m_month = ($this->m_format >= 2) ? (($m + 2) % 12 + 1) : false;
+		$this->m_day = ($this->m_format == 3) ? ($d + 1) : false;
+	}
 
-		$this->m_time = $this->normalizeValue($hours).":".$this->normalizeValue($minutes).":".$this->normalizeValue($seconds);		
+	/// Convert Julian Day back to a Julian date.
+	protected function JD2Julian() {
+		$b = intval($this->m_jd + 0.5) + 1524;
+		$c = intval(($b - 122.1)/365.25);
+		$d = intval(365.25 * $c);
+		$e = intval(($b - $d)/30.6001);
+		$m = intval(($e < 14) ? ($e - 1) : ($e - 13));
+		$y = intval(($m > 2) ? ($c - 4716) : ($c - 4715));
+		$this->m_year = ($y < 1) ? ($y - 1) : $y;
+		$this->m_month = ($this->m_format >= 2) ? $m : false;
+		$this->m_day = ($this->m_format == 3) ? ($b - $d - intval(30.6001 * $e)) : false;
 	}
 
 }
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Semediawiki-devel mailing list
Semediawiki-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/semediawiki-devel

Reply via email to