Converting epoch to date & time with time zone in xslt 2.0 - xslt

How do I convert epoch time to date & time based on time zone in xslt 2.0 ?
For example, epoch time 1212497304 converts to
GMT: Tue, 03 Jun 2008 12:48:24 GMT
time zone: martes, 03 de junio de 2008 14:48:24 GMT+2
This is because of the Daylight Saving Time (DST): in many countries there is one hour more in summer, during some dates that varies each year.
For example, it is supposed that this instruction:
<xsl:value-of select=" format-dateTime(xs:dateTime('2013-07-07T23:08:00+00:00'), '[D] [MNn] [Y] [h]:[m01][PN,*-2] [Z] ([C])', 'en', 'AD', 'IST') "/>
would calculate the given GMT date event into Indian Standard Time (IST) with Gregorian Calendar (AD) but it just prints:
7 July 2013 11:08PM +00:00 (Gregorian)
So it does not shift the time zone.
To shift the time zone we must use:
adjust-dateTime-to-timezone
But this function accepts only a duration in number of hours/minutes, not a TimeZone so that the processor determines if there is DST or not.
Any advise, please

Edit: This is not really the answer to the actual question asked, which was how to get the correct local time, respecting its timezone, but I'll still leave it here since it might be usefull to someone.
Because epoch is just seconds past since unix time you can just add it to unix time like this:
Unix time is the number of seconds elapsed since the epoch of midnight 1970-01-01, you can do:
<xsl:value-of select="xs:dateTime('1970-01-01T00:00:00') + xs:dayTimeDuration('PT1212497304S')"
/>
This will give you the correct xs:dateTime of 2008-06-03T12:48:24
Put into a function:
<xsl:function name="fn:epochToDate">
<xsl:param name="epoch"/>
<xsl:variable name="dayTimeDuration" select="concat('PT',$epoch,'S')"/>
<xsl:value-of select="xs:dateTime('1970-01-01T00:00:00') + xs:dayTimeDuration($dayTimeDuration)"/>
</xsl:function>

Related

how to handle precise hours when using WIN32 _mktime on date with DST (daylight saving time)?

Let's say I develop a ticket application that runs on windows. A given ticket has a validity of 3 hours. Now if I want to print a ticket on 28th of March 2020 (GMT+1, Germany) at 11 PM (23:00:00) it should be valid until 2 AM the next morning. (I manipulate my system time for testing)
Problem is, on the 29th DST-change happens: at 2 AM time will be set to 3 AM.
Due to DST the ticket is only valid until 1 AM (so technically only 2 hours), even though the actual time-leap happens later that day.
Here is what I do:
for the current time I use struct tm myTime;
myTime.tm_mday; \* = 28 *\
myTime.tm_hour; \* = 23 *\
struct tm newTime;
newTime.tm_mday = myTime.tm_mday; \* also done for remaining fields *\
newTime.tm_hour = myTime.tm_hour + 3; \* = 26 *\
no problem so far. On any other day the 26 hours will be converted to the following day 2 AM.
But if I call time_t result = _mktime64( newTime ); in this specific case, the resulting timestamp (e.g. 1585440205) will have mday = 29 and hour = 1 (when converted)
Is there another option, that calculates the time hour-precise, so that my ticket-validity doesn't lose one hour? (I assume _mktime64 recognizes the DST-change and manipulates all times for the day, no matter if they are before or after the actual time change at 2 AM)

RRD Tool - confusing start time

I'm setting up a rrd database to store sensor data for 3 days in 12hr intervalls (43200s) = 6 row in RRA.
rrdtool create test.rrd --step 43200 --start 1562429286 DS:temp:GAUGE:86400:U:U RRA:AVERAGE:0:1:6
The databases starting time is 1562429286 (06.07.2019 - 18:08:06).
When I dump the database:
rrdtool dump test.rrd
it says (output trimmed for clarity):
2019-07-04 02:00:00 CEST / 1562198400 NaN
2019-07-04 14:00:00 CEST / 1562241600 NaN
2019-07-05 02:00:00 CEST / 1562284800 NaN
2019-07-05 14:00:00 CEST / 1562328000 NaN
2019-07-06 02:00:00 CEST / 1562371200 NaN
2019-07-06 14:00:00 CEST / 1562414400 NaN
I expected rrdtool to give the next nearest timestamp ( 6.7.19 18:00 ) as the last entry ("starting point") instead. So why is it at 14:00 ?
At first this explanation (How to create a rrd file with a specific time?) made perfect sense for the small intervall of 5m to me. But in my case I cannot get behind the logic if the intervall is bigger (12h)
This is because the RRA buckets are always normalised to be aligned to the GMT (UCT) timezone. It is not visible if you are using a cdp (consolodated data point) width of an hour or less; but in your case, your cdp are 12 hours in width. Your timezone means that these are offset by 2 hours from UCT zero resulting in apparent boundaries of 02 and 14 local time (if you were in London then you'd be seeing 0 and 12 as expected).
This effect is much more noticeable when you are using 1-day rollups and are located in somewhere like New Zealand, when you'll see the CDP boundary appearing at noon rather than at midnight.
It is not currently possible to specify a different timezone to use as a base for the RRA buckets (this would make the data nonportable) though I believe it has been on the RRDTool feature request list for a number of years.

Redshift - Adding timezone offset (Varchar) to timestamp column

as part of ETL to Redshift, in one of the source tables, there are 2 columns:
original_timestamp - TIMESTAMP: which is the local time when the record was inserted in whichever region
original_timezone_offset - Varchar: which is the offset to UTC
The data looks something like this:
original_timestamp original_timezone_offset
2011-06-22 11:00:00.000000 -0700
2014-11-29 17:00:00.000000 -0800
2014-12-02 22:00:00.000000 +0900
2011-06-03 09:23:00.000000 -0700
2011-07-28 03:00:00.000000 -0700
2011-05-01 01:30:00.000000 -0700
In my target table, I need to convert this to UTC (using the offset). How do I do it?
So far I have tried multiple things but dateadd() seems to be the closest solution. But the problem with dateadd() is, when I say:
SELECT original_timestamp, original_timezone_offset
,dateadd(H, original_timezone_offset, original_timestamp) as original_utc_time
it is adding/subtracting '700'/'800' hours instead of 7/8 hrs to the original timestamp because the offset is a VARCHAR and the values are like: -0700 etc.
Did anyone see this issue before? Appreciate any help/inputs. Thanks.
Just take the 'hours' part of the offset:
WITH t as (
SELECT '2011-06-22 11:00:00.000000'::timestamp as original_timestamp, '-0700' as original_timezone_offset
UNION ALL
SELECT '2014-11-29 17:00:00.000000'::timestamp,'-0800'
UNION ALL
SELECT '2014-12-02 22:00:00.000000'::timestamp,'+0900'
)
SELECT
original_timestamp,
original_timezone_offset,
DATEADD(hour, SUBSTRING(original_timezone_offset, 1, 3)::INT, original_timestamp)
FROM t
2011-06-22 11:00:00 -0700 2011-06-22 04:00:00
2014-11-29 17:00:00 -0800 2014-11-29 09:00:00
2014-12-02 22:00:00 +0900 2014-12-03 07:00:00
You'll need some additional fancy code if you have non-full-hour offsets (eg +0730).
First, recognize that if your timestamps are already in local time of the given offset, then you need to subtract that offset to convert back to UTC. In that first example you gave, 2011-06-22 11:00:00 -0700 is equivalent to 2011-06-22 18:00:00 UTC.
However, rather than try to add or subtract these values yourself, you should let the AT TIME ZONE function do the work for you. It will create a timestamptz that is in your supplied offset, then you can use it again to convert to UTC.
(Note that you could use the CONVERT_TIMEZONE function instead, but that one is only understood by Redshift, where AT TIME ZONE works on regular PostgreSQL also.)
However, you have is that the time zone offsets you have aren't in a format understood by these functions. See time zone usage notes. So, before we try to convert, let's translate your offset strings to an understood format.
We will want -0700 to become +07:00. The colon is required, and the sign must be flipped because it will be interpreted with the POSIX-style time zone format. In that format, positive values lie west of GMT instead of the usual conventions specified in ISO 8601.
concat(translate(substring(original_timezone_offset, 1, 3), '-+', '+-'),':',substring(original_timezone_offset, 4, 2))
Then we will use that with AT TIME ZONE to do the conversion:
(original_timezone AT TIME ZONE <the above mess>) AT TIME ZONE 'UTC' AS utc_timestamp
Putting it all together...
WITH t as (
SELECT '2011-06-22 11:00:00.000000'::timestamp as original_timestamp, '-0700' as original_timezone_offset
UNION ALL
SELECT '2014-11-29 17:00:00.000000'::timestamp,'-0800'
UNION ALL
SELECT '2014-12-02 22:00:00.000000'::timestamp,'+0900'
)
SELECT
original_timestamp,
original_timezone_offset,
concat(translate(substring(original_timezone_offset, 1, 3), '-+', '+-'),':',substring(original_timezone_offset, 4, 2)) as modified_timezone_offset,
(original_timestamp AT TIME ZONE concat(translate(substring(original_timezone_offset, 1, 3), '-+', '+-'),':',substring(original_timezone_offset, 4, 2))) AT TIME ZONE 'UTC' AS utc_timestamptz
FROM t
Output:
2011-06-22 11:00:00 -0700 +07:00 2011-06-22 18:00:00
2014-11-29 17:00:00 -0800 +08:00 2014-11-30 01:00:00
2014-12-02 22:00:00 +0900 -09:00 2014-12-02 13:00:00
SQL Fiddle here.

Why my Python timestamp to datetime conversion is wrong?

Portal epochconverter.com converts timestamp 1531423084013 to correct date of Thursday, July 12, 2018 3:18:04.013 PM GMT-04:00 DST. But in Python 2.7.12 I got below which is wrong
>>> timestamp=1531423084013
>>> time.ctime(timestamp).rsplit(' ', 1)[0]
'Wed Nov 12 00:06:53'
How to make it correct ?
1531423084013 is in milliseconds not is seconds.
As you can see from epochconverter.com the hour is : 3:18:04.013, so the seconds part is 4.013, this site handle time in seconds and in milliseconds (it seems when the input has 13 digits instead of 10 for time around nowadays).
But time.ctime() from python handle only time in seconds and this is why you get a wrong answer when you enter a time in milliseconds (in my system it throws an out of range).
So you must divide your time in milliseconds by 1000 :
time.ctime(1531423084)
'Thu Jul 12 21:18:04 2018'
(My time zone is UTC+0200)

Freemarker print date in template

I am trying to print the current date when the template is activated. I have read that I have to pass a new Date() Java object to the template, but I don't know how to do that or where to put it in the code.
Does someone know how to pass a Java object to the template in this case?
Thank you !!
Actually you don't have to pass a new Date() to your template, because placing a timestamp into a template's output is quite common and therefore FreeMarker provides a special variable called .now which returns the current date and time. You can use it in your template like this:
Page generated: ${.now}
(FreeMarker also contains different built-ins for formatting dates: http://freemarker.org/docs/ref_builtins_date.html)
Update: Works only with the latest version of FreeMarker, 2.3.17.
${.now} is the perfect answer. Just wanted to add few other ways to get direct values from date
#-- Predefined format names: -->
${openingTime?string.short}
${openingTime?string.medium}
${openingTime?string.long}
${openingTime?string.full}
${openingTime?string.xs} <#-- XSD xs:time -->
${openingTime?string.iso} <#-- ISO 8601 time -->
${.now?string.short}
${.now?string.medium}
${.now?string.long}
${.now?string.full}
${.now?string.xs} <#-- XSD xs:date -->
${.now?string.iso} <#-- ISO 8601 date -->
${.now?string.short}
${.now?string.medium}
${.now?string.long}
${.now?string.full}
${.now?string.medium_short} <#-- medium date, short time -->
${.now?string.xs} <#-- XSD xs:dateTime -->
${.now?string.iso} <#-- ISO 8601 combined date and time -->
<#-- Programmer-defined named format (# + name): -->
${.now?string.#fileDate}
<#-- Advanced ISO 8601 and XSD formatting: -->
${.now?string.iso_m_u}
${.now?string.xs_ms_nz}
<#-- SimpleDateFormat patterns: -->
${.now?string["dd.MM.yyyy, HH:mm"]}
${.now?string["EEEE, MMMM dd, yyyy, hh:mm a '('zzz')'"]}
${.now?string["EEE, MMM d, ''yy"]}
${.now?string.yyyy} <#-- Same as ${.now?string["yyyy"]} -->
will output
01:45 PM
01:45:09 PM
01:45:09 PM PST
01:45:09 PM PST
13:45:09-08:00
13:45:09-08:00
2/20/07
Apr 20, 2007
April 20, 2007
Friday, April 20, 2007
2007-02-20-08:00
2007-02-20
2/20/07 01:45 PM
Feb 20, 2007 01:45:09 PM
February 20, 2007 01:45:09 PM PST
Friday, February 20, 2007 01:45:09 PM PST
Feb 8, 2003 9:24 PM
2007-02-20T13:45:09-08:00
2007-02-20T13:45:09-08:00
Apr/20/2007 13:45
2007-02-20T21:45Z
2007-02-20T13:45:09.000
08.04.2003 21:24
Tuesday, April 08, 2003, 09:24 PM (PDT)
Tue, Apr 8, '03
2003
Source
Use the ObjectConstructor API of Freemarker to create a calendar object and a formatter object, then combine the two to print the date:
<#-- Create constructor object -->
<#assign objectConstructor = "freemarker.template.utility.ObjectConstructor"?new()>
<#-- Call calendar constructor -->
<#assign clock = objectConstructor("java.util.GregorianCalendar")>
<#-- Call formatter constructor -->
<#assign mmddyy = objectConstructor("java.text.SimpleDateFormat","MM/dd/yyyy")>
<#-- Call getTime method to return the date in milliseconds-->
<#assign date = clock.getTime()>
<#-- Call format method to pretty print the date -->
<#assign now = mmddyy.format(date)>
<#-- Display date -->
${now}
The ?new built-in, as it was implemented, was a security hole. Now, it only allows you to instantiate a java object that implements the freemarker.template.TemplateModel interface. If you want the functionality of the ?new built-in as it existed in prior versions, make available an instance of the freemarker.template.utility.ObjectConstructor class to your template. For example:
myDataModel.put("objConstructor", new ObjectConstructor());
and then in the template you can do this:
<#assign aList = objConstructor("java.util.ArrayList", 100)>)
References
Freemarker 2.3: Version History
Tag Developers Guide: Freemarker
CRUD Operations using Servlet and FreeMarker Template Engine