Xslt conversion for dateTime in different timezone with day light saving - xslt

Looking for some help on xslt conversion for dateTime in different timezone with day light saving. How to handle EST vs EDT while doing dateTime conversion in xslt?
enter code here
Below is one Sample order xml which will be converted into another order format <salesOrders> using xslt.
All dates in the "salesOrders" are supposed to be stored in GMT timezone.
<!-- Input orders xml -->
<xml>
<orders>
<order>
<order_id>1</order_id>
<!--lots of other details -->
<order_dateTime>2019/03/09 14:00</order_dateTime> <!-- yyyy/MM/dd hh24:mm-->
<order_timezone>America/New_York</order_timezone>
<!-- This time does not fall under day light saving ( UTC -0500) -->
</order>
<order>
<order_id>2</order_id>
<!--lots of other details -->
<order_dateTime>2019/03/10 14:00</order_dateTime>
<order_timezone>America/New_York</order_timezone>
<!-- This time falls under day light saving timing ( UTC -0400) -->
</order>
<order>
<order_id>3</order_id>
<!--lots of other details -->
<order_dateTime>2019/03/10 14:00</order_dateTime>
<!-- format : yyyy/MM/dd hh24:mm-->
<order_timezone>Asia/Kolkata</order_timezone>
<!-- Indian Standard Time ( UTC +0530) -->
</order>
</orders>
</xml>
<!-- after xslt conversion, the date should be converted as given below. -->
<xml>
<salesOrders>
<salesOrder>
<salesOrderId>1</salesOrderId>
<!-- required details -->
<salesOrderDttm>2019-03-09T19:00:00</salesOrderDttm> <!-- (14 + 5:00) -->
<!-- converted the time into GMT (-04:30)-->
</salesOrder>
<salesOrder>
<salesOrderId>2</salesOrderId>
<!-- required details -->
<salesOrderDttm>2019-03-09T18:00:00</salesOrderDttm> <!-- (14 + 4:00) -->
<!-- converted the time into GMT (-05:30)-->
</salesOrder>
<salesOrder>
<salesOrderId>2</salesOrderId>
<salesOrderDttm>2019-03-09T08:30:00</salesOrderDttm> <!-- (14 - 5:30) -->
</salesOrder>
</salesOrders>
</xml>
Need help for pupulating content of "salesOrderDttm"
The content of <orderDateTime> and <orderTimeZone> will be used to populate <salesOrderDttm>.
As mentioned above, it will be maintained in GMT (offset +0000) timezone.
The main problem is, same Time zone being treated differently. At one time(first order), offset is +5:00 and at another time(2nd order) the offset is +04:30
How to do it in xslt?
Came across adjust-dateTime-to-timezone() function, but that also expects us to provide the offset.
Is there any way to handle it?
I hope this is a very common problem and must be solved
Saw this post, but all it says it is not possible what I am looking for.
Similar query on stack overflow

In XSLT 3.0 you can achieve this using the $place argument of the format-dateTime() function. Quoting from the Functions and Operators spec ยง9.8.4
If the $place argument is supplied in the form of an IANA timezone
name that is recognized by the implementation, then the date or time
being formatted is adjusted to the timezone offset applicable in that
timezone. For example, if the xs:dateTime value 2010-02-15T12:00:00Z
is formatted with the $place argument set to America/New_York, then
the output will be as if the value 2010-02-15T07:00:00-05:00 had been
supplied. This adjustment takes daylight savings time into account
where possible; if the date in question falls during daylight savings
time in New York, then it is adjusted to timezone offset -PT4H rather
than -PT5H. Adjustment using daylight savings time is only possible
where the value includes a date, and where the date is within the
range covered by the timezone database.
Note that the way this is phrased gives implementations the option to "not recognize" timezone names; but let's assume they do.
First of course you need to convert 2019/03/09 14:00 to the xs:dateTime value 2019-03-09T14:00:00Z, which is a simple bit of string manipulation.
Now you can determine the timezone offset for America/New_York by doing format-time(xs:dateTime('2019-03-09T00:00:00'), '[Z]', (), (), 'America/New_York'), which will give you a value such as "-05:00" (as a string). You can convert this to a dayTimeDuration -PT05H00M using more simple string manipulation, and then use adjustDateTimeToTimezone() to apply this displacement to your original date/time value.
The XSLT 2.0 version of format-dateTime() does not have this capability defined.

Related

Date compare in XSLT

I want to compare two dates in XSLT (1.0). Here I have mentioned hard coded dates
<xsl:variable name="DATE1" select="ms:format-date(16-FEB-19, 'dd-MMM-yy')" />
<xsl:variable name="DATE2" select="ms:format-date(01-MAY-19, 'dd-MMM-yy')" />
<xsl:if test="$DATE1 $lt; $DATE2">
</xsl:if>
I tried above but not getting proper result.
It looks like you're using some kind of extension function ms:format-date to format the dates. If you can format them as pure numeric YYYYMMDD then you can compare them as numbers. XSLT 1.0 does not offer a "<" operator for strings, let alone for dates.
Do think about moving forward to a later XSLT version (available from third parties) rather than asking the StackOverflow community to help you use a 20-year old version of the language.

Modify date as per matching a attribute name value in XSLT

I have an array of element where a:value element can have different values in it. In case the element contains date in Zulu format i.e.: 2019-04-17T10:42:48.0135859, I need to change it to YYYY-MM-DD format. I have already come up with a solution. However, I am more interested in the matching i:type="b:dateTime" in my condition. Which means if i:type is equal to or contains b:dateTime then the XSLT will fetch the date and do the required transformation.
The input XML is:
<Properties
xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
>
<a:KeyValueOfstringanyType>
<a:Key>dtDynamicModifyDate</a:Key>
<a:Value i:type="b:dateTime"
xmlns:b="http://www.w3.org/2001/XMLSchema"
>2019-04-17T10:42:48.0135859</a:Value>
</a:KeyValueOfstringanyType>
<a:KeyValueOfstringanyType>
<a:Key>tiEnrollmentStatus</a:Key>
<a:Value i:type="b:string"
xmlns:b="http://www.w3.org/2001/XMLSchema"
>Enrolled</a:Value>
</a:KeyValueOfstringanyType>
<a:KeyValueOfstringanyType>
<a:Key>tiNumberOfEnrollments</a:Key>
<a:Value i:type="b:int"
xmlns:b="http://www.w3.org/2001/XMLSchema"
>1</a:Value>
</a:KeyValueOfstringanyType>
<a:KeyValueOfstringanyType>
<a:Key>dtModifyDate</a:Key>
<a:Value i:type="b:dateTime"
xmlns:b="http://www.w3.org/2001/XMLSchema"
>2019-04-16T15:57:39.331-04:00</a:Value>
</a:KeyValueOfstringanyType>
</Properties>
The transformation is available here: https://xsltfiddle.liberty-development.net/ncdD7mC/1
Instead of this condition, I want the above condition to be checked (i:type is equal to or contains b:dateTime)
<xsl:when test="contains($payload/*[local-name()='Value'], '-') and contains($payload/*[local-name()='Value'], 'T') and contains($payload/*[local-name()='Value'], ':')">
Any pointer for the XPATH will be appreciated.
Cheers,
Sierra
The expression I think you are looking for is this...
<xsl:when test="$payload/*[local-name()='Value']/#*[name()='i:type'] ='b:dateTime'">
However, this would fail if the namespace prefix changed, so perhaps you should do this:
<xsl:when test="$payload/*[local-name()='Value']/#*[local-name()='type'] ='b:dateTime'">
But this could potentially not give you the right results if you had two attributes named type in different namespace. The only real solution is to declare the xmlns:i namespace in the XSLT, then you would do this:
<xsl:when test="$payload/*[local-name()='Value']/#i:type ='b:dateTime'">

Umbraco.library:DateDiff() Throws an error when used with umbraco Datepicker document type field value

I am trying to compare a date value set in Datepicker (an umbraco document type field) with current date (umbraco.library:FormatDateTime(umbraco.library:CurrentDate()) in an XSLT provided by umbraco cms(version 4.7).
The function i used for this was,
Umbraco.library:DateDiff($expiryDate, $currentDate, 's')
The XSLT throws the following error,
Error occured
System.FormatException: String was not recognized as a valid DateTime.
at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
at umbraco.library.DateDiff(String firstDate, String secondDate, String diffType)
I am sure this is related to some issue with datepicker value. Plain date string instead of datepicker value is working well.
Please help me out if any one went through such a situation.
Edit :
Please see my date diff code used in XSLT below,
<xsl:variable name="currentDate" select="umbraco.library:FormatDateTime(umbraco.library:CurrentDate(), 'yyyy-MM-dd')"/>
Now:<xsl:value-of select="$currentDate"/><br/>
<xsl:variable name="expiryDate" select="umbraco.library:FormatDateTime($node/expiryDate, 'yyyy-MM-dd')"/>
Exp:<xsl:value-of select="$expiryDate"/><br/> // Where **$node/expiryDate** is my datepicker value
<xsl:variable name="diffInSecs" select="umbraco.library:DateDiff($expiryDate, $currentDate, 's')"/>
Diff :<xsl:value-of select="$diffInSecs"/>
You must first make sure that both dates are in the same known format, so you should use this:
<xsl:variable name="currentDate"
select="umbraco.library:FormatDateTime(umbraco.library:CurrentDate(),
'dd/MM/yyyy')" />
and:
<xsl:variable name="formattedExpiryDate"
select="umbraco.library:FormatDateTime($expiryDate, 'dd/MM/yyyy')" />

Classic ASP xsl date conversion

I have the following code that reads a rss feed into my page, but I would like to have the pubDate convert into a more human readable date if alt all possible.
<?xml version="1.0" encoding="iso-8859-1"?><!-- DWXMLSource="mm_news.xml" -->
<!DOCTYPE xsl:stylesheet]>
<xsl:output method="html" encoding="iso-8859-1"/>
<xsl:template match="/">
<p class="newsList-date"><xsl:value-of select="pubDate"/></p>........
This gives me:
Fri, 9 Sept 2011 15:21:36 GMT
but Would Like to read something like
Friday 9 Sept 2011
Even be happy if I could simply trim off the end to just have 'Fri, 9 Sept 2011'
Also if easier can I add an extra section within the xml so i can simply enter the date like I want it so I can read it, something like below? (The xml is hand written not dynamically created)
<?xml version="1.0" encoding="US-ASCII" ?>
<?xml-stylesheet title="XSL_formatting" type="text/xsl" href="direct.xsl"?>
<rss version="2.0">
<channel>....
<item>....
<title>.....
<description>....
<thedate>.....
Many Thanks
Well, the quick & dirty way would be to substitute select="pubDate" for an expression like this:
select="substring(pubDate,1,16)"
That one's dependent on the month being four letters however, and only gives you your 'fallback' result of 'Fri, 9 Sept 2011'.
If necessary, you can be a bit cleverer and remove the requirement of the month being four letters (which seems unlikely for May), by using this expression:
select="substring(pubDate,1,string-length(substring-before(pubDate,':'))-3)"
Rather than taking a fixed length of 16, it bases it on where the first : is (in the time), and subtracts 3 from that.
If you REALLY want, there's a one-line expression that can give you what you want, but it's a bit convoluted:
select="concat(normalize-space(substring('Monday Tuesday WednesdayThursday Friday Saturday Sunday ',string-length(substring-before('MonTueWedThuFriSatSun',substring(pubDate,1,3))) * 3 + 1,9)),substring(pubDate,5,string-length(substring-before(pubDate,':'))-7))"
This uses a 'lookup', to find where the day of the week exists in one string, and uses that to pick the full name from another, finally using 'normalize-space' to trim any extra spaces. Then it just concatenates it with the date part.

date minus another date in xslt

Hope someone can help. I am trying to compare 2 dates inside an XML file and using a XSLT to do some calculation:
For example I have 2 dates in XML: 2011-05-23 and 2011-04-29. I want to do calculation inside XSLT like below:
('2011-05-23'-'2011-04-29')*30 = 24*30= 720
Can anyone shed any light?
An XSLT 2.0 solution
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="/">
<xsl:value-of select="days-from-duration(
xs:date('2011-05-23')
- xs:date(xs:date('2011-04-29'))
)*30"/>
</xsl:template>
</xsl:stylesheet>
Yields: 720
xs:date() function evaluates the dates, which can be used to perform date operations
subtracting the second date from the first yields the xdt:dayTimeDuration P24D (24 days)
days-from-duration() extracts the days component from the xdt:dayTimeDuration (24)
then you can use that number to perform normal arethmatic (e.g. 24*30=720)
It might be worth looking at the EXSLT - date:difference solution. I believe that should do what you want, and there's even a straight XSLT implementation available.
Be aware though that the returned value is in duration format as specified in the XML Schema Part 2: Datatypes Second Edition, so it's likely you will need to process the result to derive the unit you wish to use in calculation (for instance in your example above you're expecting a result detailing the number of days difference - so you would need to pull out the relevant unit you want to work with, the result from date:difference in that case would most likely be "P24D").
Here's two templates I sometimes use for date calculations:
<xsl:template name="calcseconds">
<xsl:param name="date" />
<xsl:value-of select="(((substring($date,1,4) - 1970) * 365)+floor((substring($date,1,4) - 1970) div 4)+substring('000,031,059,090,120,151,181,212,243,273,304,334,365',substring($date,6,2)*4-3,3)+(substring($date,9,2)-1)+(1-floor(((substring($date,1,4) mod 4) + 2) div 3))*floor((substring($date,6,2)+17) div 20))*86400+(substring($date,12,2)*3600)+(substring($date,15,2)*60)+substring($date,18,2)" />
</xsl:template>
<xsl:template name="calcdays">
<xsl:param name="date" />
<xsl:value-of select="(((substring($date,1,4) - 1970) * 365)+floor((substring($date,1,4) - 1970) div 4)+substring('000,031,059,090,120,151,181,212,243,273,304,334,365',substring($date,6,2)*4-3,3)+(substring($date,9,2)-1)+(1-floor(((substring($date,1,4) mod 4) + 2) div 3))*floor((substring($date,6,2)+17) div 20))" />
</xsl:template>
They're a bit of a mouthful, but they'll calculate the number of seconds/days since midnight 1st January 1970 as an integer, which you can then do straight arithmetic on. They rely on the date format being yyyy-mm-dd hh:mm:ss, but manipulation of the parameters of the substring calls should allow you to process dates in any format you need.