/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.xpath.types;

import java.text.DecimalFormat;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;

import javax.xml.transform.TransformerException;

import xml.xpath31.processor.types.XSDate;
import xml.xpath31.processor.types.XSDateTime;
import xml.xpath31.processor.types.XSDayTimeDuration;
import xml.xpath31.processor.types.XSTime;

/**
 * This class definition, specifies few utility methods to support 
 * XPath 3.1 data model xs:dateTime, xs:date and xs:time value 
 * comparisons.
 * 
 * @author Mukul Gandhi <mukulg@apache.org>
 * 
 * @xsl.usage general
 */
public class DateTimeUtil {
	
	/**
	 * Method definition, to get string value of supplied 
	 * xs:dateTime object value.
	 * 
	 * @param xsDateTime			The supplied xs:dateTime object value
	 * @return						String value of supplied xs:dateTime value
	 */
	public static String getXSDateTimeStrValue(XSDateTime xsDateTime) {
	   
	   String result = null;
	                                           
       String strValue = xsDateTime.stringValue();           
       
       Calendar calendar = xsDateTime.getCalendar();
       int milliSecs = calendar.get(Calendar.MILLISECOND);
       boolean ms1 = false;
       if ((milliSecs % 100) == 0) {
          milliSecs = (calendar.get(Calendar.MILLISECOND)) / 100;
          ms1 = true;
       }
       
       if (milliSecs == 0) {
    	   result = strValue; 
       }
       else {
    	   String milliSecStr = null;
    	   if (ms1) {
    		   milliSecStr = String.valueOf(milliSecs);  
    	   }
    	   else if (milliSecs < 10) {
    		   milliSecStr = "00" + milliSecs;   
    	   }
    	   else if (milliSecs < 100) {
    		   milliSecStr = "0" + milliSecs; 
    	   }
    	   else if (milliSecs > 100) {
    		   milliSecStr = String.valueOf(milliSecs);  
    	   }

    	   int idx = strValue.indexOf('T');
    	   String prefixStr = strValue.substring(0, idx);
    	   String suffixStr = strValue.substring(idx);
    	   int timeZoneIdx = suffixStr.indexOf('+');
    	   if (timeZoneIdx == -1) {
    		   timeZoneIdx = suffixStr.indexOf('-'); 
    	   }
    	   if (timeZoneIdx == -1) {
    		   timeZoneIdx = suffixStr.indexOf('Z'); 
    	   }        	  
    	   if (timeZoneIdx > -1) {
    		   String timeStr = suffixStr.substring(0, timeZoneIdx);
    		   timeStr = timeStr + "." + milliSecStr;
    		   String timeZoneStr = suffixStr.substring(timeZoneIdx);
    		   strValue = prefixStr + timeStr + timeZoneStr;  
    	   }
    	   else {
    		   suffixStr = suffixStr + "." + milliSecStr;
    		   strValue = prefixStr + suffixStr;  
    	   }

    	   result = strValue;
       }
	   
	   return result;
	}
	
	/**
	 * Method definition, to check whether two supplied xs:dateTime 
	 * values are equal.
	 * 
	 * @param dt1						One of the supplied xs:dateTime value
	 * @param dt2						The second supplied xs:dateTime value
	 * @return							Boolean value 'true', if the two supplied 
	 *                                  xs:dateTime values are equal, otherwise 'false'.
	 */
	public static boolean isEqual(XSDateTime dt1, XSDateTime dt2) {
	   
		boolean result = false;

		String str1 = dt1.stringValue();
		String str2 = dt2.stringValue();

		int timeZoneIdx = str1.indexOf('T');
		String str3 = str1.substring(timeZoneIdx);
		if (!(str3.contains("+") || str3.contains("-") || str3.endsWith("Z"))) {
		   str1 = str1 + "Z";
		}

		timeZoneIdx = str2.indexOf('T');
		str3 = str2.substring(timeZoneIdx);
		if (!(str3.contains("+") || str3.contains("-") || str3.endsWith("Z"))) {
		   // For comparison purpose, if xs:dateTime value is not in a timezone,
		   // then its assumed to be in UTC timezone.
		   str2 = str2 + "Z"; 
		}				
		
		int yearIdx = str1.indexOf('-');
		int yearValue = Integer.valueOf(str1.substring(0, yearIdx));
		OffsetDateTime odt1 = null;
		if (yearValue > 9999) {
		   String tempStr1 = "9999" + str1.substring(yearIdx);  	
		   odt1 = OffsetDateTime.parse(tempStr1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		   odt1 = odt1.plusYears(yearValue - 9999);
		}
		else {
		   odt1 = OffsetDateTime.parse(str1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		}
		
		Instant instant1 = odt1.toInstant();				
		
		yearIdx = str2.indexOf('-');
		yearValue = Integer.valueOf(str2.substring(0, yearIdx));
		OffsetDateTime odt2 = null;
		if (yearValue > 9999) {
		   String tempStr1 = "9999" + str2.substring(yearIdx);  	
		   odt2 = OffsetDateTime.parse(tempStr1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		   odt2 = odt2.plusYears(yearValue - 9999);
		}
		else {
		   odt2 = OffsetDateTime.parse(str2, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		}
				
		Instant instant2 = odt2.toInstant();

		result = instant1.equals(instant2);

		return result;
	}

	/**
	 * Method definition, to check whether one supplied xs:dateTime value 
	 * occurs before another supplied xs:dateTime value.
	 * 
	 * @param dt1						One of the supplied xs:dateTime value
	 * @param dt2						The second supplied xs:dateTime value
	 * @return							Boolean value 'true', if the first xs:dateTime value 
	 *                                  occurs before the second xs:dateTime value, otherwise 
	 *                                  'false'.
	 */
	public static boolean isBefore(XSDateTime dt1, XSDateTime dt2) {
		
		boolean result = false;

		String str1 = dt1.stringValue();
		String str2 = dt2.stringValue();

		int timeZoneIdx = str1.indexOf('T');
		String str3 = str1.substring(timeZoneIdx);
		if (!(str3.contains("+") || str3.contains("-") || str3.endsWith("Z"))) {
		   str1 = str1 + "Z";
		}

		timeZoneIdx = str2.indexOf('T');
		str3 = str2.substring(timeZoneIdx);
		if (!(str3.contains("+") || str3.contains("-") || str3.endsWith("Z"))) {
		   // For comparison purpose, if xs:dateTime value is not in a timezone,
		   // then its assumed to be in UTC timezone.
		   str2 = str2 + "Z"; 
		}
		
		int yearIdx = str1.indexOf('-');
		int yearValue = Integer.valueOf(str1.substring(0, yearIdx));
		OffsetDateTime odt1 = null;
		if (yearValue > 9999) {
		   String tempStr1 = "9999" + str1.substring(yearIdx);  	
		   odt1 = OffsetDateTime.parse(tempStr1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		   odt1 = odt1.plusYears(yearValue - 9999);
		}
		else {
		   odt1 = OffsetDateTime.parse(str1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		}
		
		Instant instant1 = odt1.toInstant();				
		
		yearIdx = str2.indexOf('-');
		yearValue = Integer.valueOf(str2.substring(0, yearIdx));
		OffsetDateTime odt2 = null;
		if (yearValue > 9999) {
		   String tempStr1 = "9999" + str2.substring(yearIdx);  	
		   odt2 = OffsetDateTime.parse(tempStr1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		   odt2 = odt2.plusYears(yearValue - 9999);
		}
		else {
		   odt2 = OffsetDateTime.parse(str2, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		}
				
		Instant instant2 = odt2.toInstant();

		result = instant1.isBefore(instant2);

		return result;
	}
	
	/**
	 * Method definition, to check whether one supplied xs:dateTime value 
	 * occurs after another supplied xs:dateTime value.
	 * 
	 * @param dt1						One of the supplied xs:dateTime value
	 * @param dt2						The second supplied xs:dateTime value
	 * @return							Boolean value 'true', if the first xs:dateTime value 
	 *                                  occurs after the second xs:dateTime value, otherwise 
	 *                                  'false'.
	 */
	public static boolean isAfter(XSDateTime dt1, XSDateTime dt2) {
		
		boolean result = false;

		String str1 = dt1.stringValue();
		String str2 = dt2.stringValue();

		int timeZoneIdx = str1.indexOf('T');
		String str3 = str1.substring(timeZoneIdx);
		if (!(str3.contains("+") || str3.contains("-") || str3.endsWith("Z"))) {
		   str1 = str1 + "Z";
		}

		timeZoneIdx = str2.indexOf('T');
		str3 = str2.substring(timeZoneIdx);
		if (!(str3.contains("+") || str3.contains("-") || str3.endsWith("Z"))) {
		   // For comparison purpose, if xs:dateTime value is not in a timezone,
		   // then its assumed to be in UTC timezone.
		   str2 = str2 + "Z"; 
		}
		
		int yearIdx = str1.indexOf('-');
		int yearValue = Integer.valueOf(str1.substring(0, yearIdx));
		OffsetDateTime odt1 = null;
		if (yearValue > 9999) {
		   String tempStr1 = "9999" + str1.substring(yearIdx);  	
		   odt1 = OffsetDateTime.parse(tempStr1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		   odt1 = odt1.plusYears(yearValue - 9999);
		}
		else {
		   odt1 = OffsetDateTime.parse(str1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		}
		
		Instant instant1 = odt1.toInstant();				
		
		yearIdx = str2.indexOf('-');
		yearValue = Integer.valueOf(str2.substring(0, yearIdx));
		OffsetDateTime odt2 = null;
		if (yearValue > 9999) {
		   String tempStr1 = "9999" + str2.substring(yearIdx);  	
		   odt2 = OffsetDateTime.parse(tempStr1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		   odt2 = odt2.plusYears(yearValue - 9999);
		}
		else {
		   odt2 = OffsetDateTime.parse(str2, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		}
				
		Instant instant2 = odt2.toInstant();

		result = instant1.isAfter(instant2);

		return result;
	}
	
	/**
	 * Method definition, to check whether one supplied xs:dateTime value 
	 * is equal, or occurs before another supplied xs:dateTime value.
	 * 
	 * @param dt1						One of the supplied xs:dateTime value
	 * @param dt2						The second supplied xs:dateTime value
	 * @return							Boolean value 'true', if the requested
	 *                                  relational comparison is true between 
	 *                                  two supplied xs:dateTime values, otherwise 'false'.
	 */
	public static boolean lessThanOrEqual(XSDateTime dt1, XSDateTime dt2) {
		
		boolean result = false;

		String str1 = dt1.stringValue();
		String str2 = dt2.stringValue();

		int timeZoneIdx = str1.indexOf('T');
		String str3 = str1.substring(timeZoneIdx);
		if (!(str3.contains("+") || str3.contains("-") || str3.endsWith("Z"))) {
		   str1 = str1 + "Z";
		}

		timeZoneIdx = str2.indexOf('T');
		str3 = str2.substring(timeZoneIdx);
		if (!(str3.contains("+") || str3.contains("-") || str3.endsWith("Z"))) {
		   // For comparison purpose, if xs:dateTime value is not in a timezone,
		   // then its assumed to be in UTC timezone.
		   str2 = str2 + "Z"; 
		}
		
		int yearIdx = str1.indexOf('-');
		int yearValue = Integer.valueOf(str1.substring(0, yearIdx));
		OffsetDateTime odt1 = null;
		if (yearValue > 9999) {
		   String tempStr1 = "9999" + str1.substring(yearIdx);  	
		   odt1 = OffsetDateTime.parse(tempStr1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		   odt1 = odt1.plusYears(yearValue - 9999);
		}
		else {
		   odt1 = OffsetDateTime.parse(str1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		}
		
		Instant instant1 = odt1.toInstant();				
		
		yearIdx = str2.indexOf('-');
		yearValue = Integer.valueOf(str2.substring(0, yearIdx));
		OffsetDateTime odt2 = null;
		if (yearValue > 9999) {
		   String tempStr1 = "9999" + str2.substring(yearIdx);  	
		   odt2 = OffsetDateTime.parse(tempStr1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		   odt2 = odt2.plusYears(yearValue - 9999);
		}
		else {
		   odt2 = OffsetDateTime.parse(str2, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
		}
				
		Instant instant2 = odt2.toInstant();

		result = (instant1.isBefore(instant2) || instant1.equals(instant2));

		return result;
	}

	/**
	 * Method definition, to check whether two supplied xs:date 
	 * values are equal.
	 * 
	 * @param date1						One of the supplied xs:date value
	 * @param date2						The second supplied xs:date value
	 * @return							Boolean value 'true', if the two supplied 
	 *                                  xs:date values are equal, otherwise 'false'.
	 */
	public static boolean isEqual(XSDate date1, XSDate date2) throws TransformerException {
		
		boolean result = false;
		
		// For comparison purpose, if xs:date value is not in a timezone,
		// then its assumed to be in UTC timezone.
		
		String str1 = date1.stringValue();
		String[] str1Parts = str1.split("-");
		if (str1Parts.length == 3) {
		   String str3 = str1Parts[2];
		   if (!(str3.contains("+") || str3.endsWith("Z"))) {
			  str1 = str1 + "T00:00:00Z"; 
		   }
		   else {
			  String[] temp = str3.split("\\+|Z");
			  if (str3.contains("+")) {
				 str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + temp[0] + "T00:00:00" + "+" + temp[1];  
			  }
			  else {
				 str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + temp[0] + "T00:00:00Z"; 
			  }
		   }
		}
		else if (str1Parts.length == 4) {
		   String str3 = str1Parts[3];
		   str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + str1Parts[2] + "T00:00:00" + "-"+ str3;
		}
		
		XSDateTime dt1 = XSDateTime.parseDateTime(str1); 
		
		String str2 = date2.stringValue();
		String[] str2Parts = str2.split("-");
		if (str2Parts.length == 3) {
		   String str3 = str2Parts[2];
		   if (!(str3.contains("+") || str3.endsWith("Z"))) {
			   str2 = str2 + "T00:00:00Z"; 
		   }
		   else {
			  String[] temp = str3.split("\\+|Z");
			  if (str3.contains("+")) {
				  str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + temp[0] + "T00:00:00" + "+" + temp[1];  
			  }
			  else {
				  str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + temp[0] + "T00:00:00Z"; 
			  }
		   }
		}
		else if (str2Parts.length == 4) {
		   String str3 = str2Parts[3];
		   str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + str2Parts[2] + "T00:00:00" + "-"+ str3;
		}
		
		XSDateTime dt2 = XSDateTime.parseDateTime(str2);
		
		result = isEqual(dt1, dt2);
		
		return result;
	}
	
	/**
	 * Method definition, to check whether one supplied xs:date value 
	 * occurs before another supplied xs:date value.
	 * 
	 * @param date1						One of the supplied xs:date value
	 * @param date2						The second supplied xs:date value
	 * @return							Boolean value 'true', if the first xs:date value 
	 *                                  occurs before the second xs:date value, otherwise 
	 *                                  'false'.
	 */
    public static boolean isBefore(XSDate date1, XSDate date2) throws TransformerException {
		
		boolean result = false;
		
		// For comparison purpose, if xs:date value is not in a timezone,
		// then its assumed to be in UTC timezone.
		
		String str1 = date1.stringValue();
		String[] str1Parts = str1.split("-");
		if (str1Parts.length == 3) {
		   String str3 = str1Parts[2];
		   if (!(str3.contains("+") || str3.endsWith("Z"))) {
			  str1 = str1 + "T00:00:00Z"; 
		   }
		   else {
			  String[] temp = str3.split("\\+|Z");
			  if (str3.contains("+")) {
				 str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + temp[0] + "T00:00:00" + "+" + temp[1];  
			  }
			  else {
				 str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + temp[0] + "T00:00:00Z"; 
			  }
		   }
		}
		else if (str1Parts.length == 4) {
		   String str3 = str1Parts[3];
		   str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + str1Parts[2] + "T00:00:00" + "-"+ str3;
		}
		
		XSDateTime dt1 = XSDateTime.parseDateTime(str1); 
		
		String str2 = date2.stringValue();
		String[] str2Parts = str2.split("-");
		if (str2Parts.length == 3) {
		   String str3 = str2Parts[2];
		   if (!(str3.contains("+") || str3.endsWith("Z"))) {
			   str2 = str2 + "T00:00:00Z"; 
		   }
		   else {
			  String[] temp = str3.split("\\+|Z");
			  if (str3.contains("+")) {
				  str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + temp[0] + "T00:00:00" + "+" + temp[1];  
			  }
			  else {
				  str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + temp[0] + "T00:00:00Z"; 
			  }
		   }
		}
		else if (str2Parts.length == 4) {
		   String str3 = str2Parts[3];
		   str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + str2Parts[2] + "T00:00:00" + "-"+ str3;
		}
		
		XSDateTime dt2 = XSDateTime.parseDateTime(str2);
		
		result = isBefore(dt1, dt2);
		
		return result;
	}
    
    /**
	 * Method definition, to check whether one supplied xs:date value 
	 * occurs after another supplied xs:date value.
	 * 
	 * @param date1						One of the supplied xs:date value
	 * @param date2						The second supplied xs:date value
	 * @return							Boolean value 'true', if the first xs:date value 
	 *                                  occurs after the second xs:date value, otherwise 
	 *                                  'false'.
	 */
    public static boolean isAfter(XSDate date1, XSDate date2) throws TransformerException {
		
		boolean result = false;
		
		// For comparison purpose, if xs:date value is not in a timezone,
		// then its assumed to be in UTC timezone.
		
		String str1 = date1.stringValue();
		String[] str1Parts = str1.split("-");
		if (str1Parts.length == 3) {
		   String str3 = str1Parts[2];
		   if (!(str3.contains("+") || str3.endsWith("Z"))) {
			  str1 = str1 + "T00:00:00Z"; 
		   }
		   else {
			  String[] temp = str3.split("\\+|Z");
			  if (str3.contains("+")) {
				 str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + temp[0] + "T00:00:00" + "+" + temp[1];  
			  }
			  else {
				 str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + temp[0] + "T00:00:00Z"; 
			  }
		   }
		}
		else if (str1Parts.length == 4) {
		   String str3 = str1Parts[3];
		   str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + str1Parts[2] + "T00:00:00" + "-"+ str3;
		}
		
		XSDateTime dt1 = XSDateTime.parseDateTime(str1); 
		
		String str2 = date2.stringValue();
		String[] str2Parts = str2.split("-");
		if (str2Parts.length == 3) {
		   String str3 = str2Parts[2];
		   if (!(str3.contains("+") || str3.endsWith("Z"))) {
			   str2 = str2 + "T00:00:00Z"; 
		   }
		   else {
			  String[] temp = str3.split("\\+|Z");
			  if (str3.contains("+")) {
				  str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + temp[0] + "T00:00:00" + "+" + temp[1];  
			  }
			  else {
				  str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + temp[0] + "T00:00:00Z"; 
			  }
		   }
		}
		else if (str2Parts.length == 4) {
		   String str3 = str2Parts[3];
		   str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + str2Parts[2] + "T00:00:00" + "-"+ str3;
		}
		
		XSDateTime dt2 = XSDateTime.parseDateTime(str2);
		
		result = isAfter(dt1, dt2);
		
		return result;
	}
    
    /**
	 * Method definition, to check whether one supplied xs:date value 
	 * is equal, or occurs before another supplied xs:date value.
	 * 
	 * @param date1						One of the supplied xs:date value
	 * @param date2						The second supplied xs:date value
	 * @return							Boolean value 'true', if the requested
	 *                                  relational comparison is true between 
	 *                                  two supplied xs:date values, otherwise 'false'.
	 */
    public static boolean lessThanOrEqual(XSDate date1, XSDate date2) throws TransformerException {
        
    	boolean result = false;
    	
    	// For comparison purpose, if xs:date value is not in a timezone,
    	// then its assumed to be in UTC timezone.
		
		String str1 = date1.stringValue();
		String[] str1Parts = str1.split("-");
		if (str1Parts.length == 3) {
		   String str3 = str1Parts[2];
		   if (!(str3.contains("+") || str3.endsWith("Z"))) {
			  str1 = str1 + "T00:00:00Z"; 
		   }
		   else {
			  String[] temp = str3.split("\\+|Z");
			  if (str3.contains("+")) {
				 str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + temp[0] + "T00:00:00" + "+" + temp[1];  
			  }
			  else {
				 str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + temp[0] + "T00:00:00Z"; 
			  }
		   }
		}
		else if (str1Parts.length == 4) {
		   String str3 = str1Parts[3];
		   str1 = str1Parts[0] + "-" + str1Parts[1] + "-" + str1Parts[2] + "T00:00:00" + "-"+ str3;
		}
		
		XSDateTime dt1 = XSDateTime.parseDateTime(str1); 
		
		String str2 = date2.stringValue();
		String[] str2Parts = str2.split("-");
		if (str2Parts.length == 3) {
		   String str3 = str2Parts[2];
		   if (!(str3.contains("+") || str3.endsWith("Z"))) {
			   str2 = str2 + "T00:00:00Z"; 
		   }
		   else {
			  String[] temp = str3.split("\\+|Z");
			  if (str3.contains("+")) {
				  str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + temp[0] + "T00:00:00" + "+" + temp[1];  
			  }
			  else {
				  str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + temp[0] + "T00:00:00Z"; 
			  }
		   }
		}
		else if (str2Parts.length == 4) {
		   String str3 = str2Parts[3];
		   str2 = str2Parts[0] + "-" + str2Parts[1] + "-" + str2Parts[2] + "T00:00:00" + "-"+ str3;
		}
		
		XSDateTime dt2 = XSDateTime.parseDateTime(str2);
		
		result = lessThanOrEqual(dt1, dt2);
		
		return result;
		
	}
    
    /**
	 * Method definition, to check whether two supplied xs:time values 
	 * are equal.
	 * 
	 * @param time1						One of the supplied xs:time value
	 * @param time2						The second supplied xs:time value
	 * @return							Boolean value 'true', if the two supplied 
	 *                                  xs:time values are equal, otherwise 'false'.
	 */
    public static boolean isEqual(XSTime time1, XSTime time2) throws TransformerException {
    	
    	boolean result = false;
    	
    	String str1 = time1.stringValue();
    	if (!(str1.contains("+") || str1.contains("-") || str1.endsWith("Z"))) {
    	   str1 = str1 + "Z"; 
 		}
    	
    	// Prefixing with a fixed implementation chosen literal date
    	str1 = "2000-01-01T" + str1;
    	XSDateTime dt1 = XSDateTime.parseDateTime(str1);
    	
    	String str2 = time2.stringValue();
    	if (!(str2.contains("+") || str2.contains("-") || str2.endsWith("Z"))) {
    	   str2 = str2 + "Z"; 
  		}
    	
    	// Prefixing with a fixed implementation chosen literal date
    	str2 = "2000-01-01T" + str2;
    	XSDateTime dt2 = XSDateTime.parseDateTime(str2);
    	
    	result = isEqual(dt1, dt2);
    	
    	return result;
    }
    
    /**
	 * Method definition, to check whether one supplied xs:time value 
	 * occurs before another supplied xs:time value.
	 * 
	 * @param time1						One of the supplied xs:time value
	 * @param time2						The second supplied xs:time value
	 * @return							Boolean value 'true', if the first xs:time value 
	 *                                  occurs before the second xs:time value, otherwise 
	 *                                  'false'.
	 */
    public static boolean isBefore(XSTime time1, XSTime time2) throws TransformerException {
    	
    	boolean result = false;
    	
    	String str1 = time1.stringValue();
    	if (!(str1.contains("+") || str1.contains("-") || str1.endsWith("Z"))) {
    	   str1 = str1 + "Z"; 
 		}
    	
    	// Prefixing with a fixed implementation chosen literal date
    	str1 = "2000-01-01T" + str1;
    	XSDateTime dt1 = XSDateTime.parseDateTime(str1);
    	
    	String str2 = time2.stringValue();
    	if (!(str2.contains("+") || str2.contains("-") || str2.endsWith("Z"))) {
    	   str2 = str2 + "Z"; 
  		}
    	
    	// Prefixing with a fixed implementation chosen literal date
    	str2 = "2000-01-01T" + str2;
    	XSDateTime dt2 = XSDateTime.parseDateTime(str2);
    	
    	result = isBefore(dt1, dt2);
    	
    	return result;
    }
    
    /**
	 * Method definition, to check whether one supplied xs:time value occurs 
	 * after another supplied xs:time value.
	 * 
	 * @param time1						One of the supplied xs:time value
	 * @param time2						The second supplied xs:time value
	 * @return							Boolean value 'true', if the first xs:time value 
	 *                                  occurs after the second xs:time value, otherwise 
	 *                                  'false'.
	 */
    public static boolean isAfter(XSTime time1, XSTime time2) throws TransformerException {
    	
    	boolean result = false;
    	
    	String str1 = time1.stringValue();
    	if (!(str1.contains("+") || str1.contains("-") || str1.endsWith("Z"))) {
    	   str1 = str1 + "Z"; 
 		}
    	
    	// Prefixing with a fixed implementation chosen literal date
    	str1 = "2000-01-01T" + str1;
    	XSDateTime dt1 = XSDateTime.parseDateTime(str1);
    	
    	String str2 = time2.stringValue();
    	if (!(str2.contains("+") || str2.contains("-") || str2.endsWith("Z"))) {
    	   str2 = str2 + "Z"; 
  		}
    	
    	// Prefixing with a fixed implementation chosen literal date
    	str2 = "2000-01-01T" + str2;
    	XSDateTime dt2 = XSDateTime.parseDateTime(str2);
    	
    	result = isAfter(dt1, dt2);
    	
    	return result;
    }
    
    /**
	 * Method definition, to check whether one supplied xs:time value 
	 * is equal, or occurs before another supplied xs:time value.
	 * 
	 * @param time1						One of the supplied xs:time value
	 * @param time2						The second supplied xs:time value
	 * @return							Boolean value 'true', if the requested
	 *                                  relational comparison is true between 
	 *                                  two supplied xs:time values, otherwise 'false'.
	 */
    public static boolean lessThanOrEqual(XSTime time1, XSTime time2) throws TransformerException {
        
    	boolean result = false;
    	
    	String str1 = time1.stringValue();
    	if (!(str1.contains("+") || str1.contains("-") || str1.endsWith("Z"))) {
    	   str1 = str1 + "Z"; 
 		}
    	
    	// Prefixing with a fixed implementation chosen literal date
    	str1 = "2000-01-01T" + str1;
    	XSDateTime dt1 = XSDateTime.parseDateTime(str1);
    	
    	String str2 = time2.stringValue();
    	if (!(str2.contains("+") || str2.contains("-") || str2.endsWith("Z"))) {
    	   str2 = str2 + "Z"; 
  		}
    	
    	// Prefixing with a fixed implementation chosen literal date
    	str2 = "2000-01-01T" + str2;
    	XSDateTime dt2 = XSDateTime.parseDateTime(str2);
    	
    	result = lessThanOrEqual(dt1, dt2);
    	
    	return result;
    }
    
    /**
	 * Method definition, to get xs:date's string value, from supplied xs:dateTime 
	 * value. This method, strips the supplied xs:dateTime value's time component 
	 * and retains xs:dateTime value's time zone component to construct an xs:date 
	 * string value.
	 * 
	 * @param xsDateTime					  Supplied xs:dateTime value
	 * @return							      xs:date value string
	 */
	public static String getXsDateStrFromXsDateTime(XSDateTime xsDateTime) {

		String result = null;

		String xsDateTimeStr = xsDateTime.stringValue();
		int idx2 = xsDateTimeStr.indexOf('T');
		String prfxStr = xsDateTimeStr.substring(0, idx2);
		String sffxStr = xsDateTimeStr.substring(idx2 + 1);
		int zi = sffxStr.indexOf('Z');
		int pi = sffxStr.indexOf('+');
		int mi = sffxStr.indexOf('-');
		String dateStr1 = null; 
		if (zi != -1) {
			dateStr1 = prfxStr + "Z";   
		}
		else if (pi != -1) {
			dateStr1 = prfxStr + sffxStr.substring(pi); 
		}
		else if (mi != -1) {
			dateStr1 = prfxStr + sffxStr.substring(pi); 
		}
		else {
			dateStr1 = prfxStr;  
		}

		result = dateStr1;

		return result;
	}
	
	/**
	 * Method definition, to format xs:dayTimeDuration's seconds value 
	 * component, to either two or three decimal places.
	 * 
	 * @param xsDayTimeDuration                   The supplied xs:dayTimeDuration value
	 * @return                                    The formatted xs:dayTimeDuration string 
	 *                                            value.
	 */
	public static String getFormattedStrXsDaytimeDuration(XSDayTimeDuration xsDayTimeDuration) {

		String result = null;

		int days = xsDayTimeDuration.days();
		int hrs = xsDayTimeDuration.hours();
		int mins = xsDayTimeDuration.minutes();

		double secs = xsDayTimeDuration.seconds();

		// Format seconds value to two decimal places
		DecimalFormat df = new DecimalFormat("#.##");
		String frmtSecValue = df.format(secs);
		double secs1 = (Double.valueOf(frmtSecValue)).doubleValue();

		// Format seconds value to three decimal places
		df = new DecimalFormat("#.###");
		frmtSecValue = df.format(secs);
		double secs2 = (Double.valueOf(frmtSecValue)).doubleValue();

		if (secs2 > secs1) {
			secs = secs2;  
		}
		else {
			secs = secs1; 
		}

		boolean isNegative = xsDayTimeDuration.negative();

		XSDayTimeDuration xsDtdNormalizedValue = new XSDayTimeDuration(days, hrs, mins, secs, isNegative);

		result = xsDtdNormalizedValue.stringValue();

		return result;
	}
	
	/**
	 * Method definition, to get time zone string value, from
	 * the supplied xs:dateTime value.
	 * 
	 * @param xsDateTime                        The supplied xs:dateTime value
	 * @return                                  Time zone string value
	 */
    public static String getTimeZoneStrFromXsDateTimeValue(XSDateTime xsDateTime) {
		
    	String result = null;

    	String xsDateTimeStr = xsDateTime.stringValue();
    	String[] strArray = xsDateTimeStr.split("-");		   
    	int idx2 = xsDateTimeStr.indexOf('+');
    	int idx3 = xsDateTimeStr.indexOf('Z');
    	if (strArray.length == 4) {
    		int idx = xsDateTimeStr.lastIndexOf('-');
    		result = xsDateTimeStr.substring(idx); 
    	}
    	else if (idx2 != -1) {
    		result = xsDateTimeStr.substring(idx2); 
    	}
    	else if (idx3 != -1) {
    		result = xsDateTimeStr.substring(idx3); 
    	}

    	return result;
	}

    /**
	 * Method definition, to get time zone string value, from
	 * the supplied xs:date value.
	 * 
	 * @param xsDate                           The supplied xs:date value
	 * @return                                 Time zone string value
	 */
    public static String getTimeZoneStrFromXsDateValue(XSDate xsDate) {
		
		String result = null;
		
		String xsDateStr = xsDate.stringValue();
		String[] strArray = xsDateStr.split("-");		
		int idx2 = xsDateStr.indexOf('+');
		int idx3 = xsDateStr.indexOf('Z');
		if (strArray.length == 4) {
			int idx = xsDateStr.lastIndexOf('-');
			result = xsDateStr.substring(idx); 
		}
		else if (idx2 != -1) {
			result = xsDateStr.substring(idx2); 
		}
		else if (idx3 != -1) {
			result = xsDateStr.substring(idx3); 
		}
		
		return result;
	}

}
