I am facing the issue with time zones.
Code:
{
let $hour := hours-from-duration(fn:subtract-dateTimes-yielding-dayTimeDuration(xs:dateTime(data($FlightSegment/#ArrivalDateTime)),xs:dateTime(data($FlightSegment/#DepartureDateTime))))
let $min := minutes-from-duration(fn:subtract-dateTimes-yielding-dayTimeDuration(xs:dateTime(data($FlightSegment/#ArrivalDateTime)),xs:dateTime(data($FlightSegment/#DepartureDateTime))))
return
if($hour < 10 and $min < 10) then
<flt-seg:FlightDuration> {concat('0',$hour,':','0',$min)}</flt-seg:FlightDuration>
else if ($min < 10 ) then
<flt-seg:FlightDuration> {concat($hour,':','0',$min)}</flt-seg:FlightDuration>
else if ($hour < 10 ) then
<flt-seg:FlightDuration> {concat('0',$hour,':',$min)}</flt-seg:FlightDuration>
else
<flt-seg:FlightDuration> {concat($hour,':',$min)}</flt-seg:FlightDuration>
}
Departure airport code is :BNE(Brisbane)
Arrival airport code is :LAX(Lass angels)
Response i am getting:
DepartureDateTime:2015-08-15T09:50:00
ArrivalDateTime:2015-08-15T06:30:00
FlightDuration: 0-3:0-20
flight duration (0-3:0-20) iam getting negative value, so request you to pls help me on this how can i get the positive value.
could you pls let me know how i will get proper flight duration with different time zones.
Thanks in Advance.
Looks like you have two problems.
First problem is formatting the duration, which you can do using functx:pad-integer-to-length() or using the bea date functions (or number format functions) if you swing that way. That's the easy bit.
Your second, harder problem is your input data is airport-local, which cannot be compared the way you're doing it. You need to calculate the actual UTC date time from the local date time + port IATA code, probably via an interim lookup, so
airport -> timezone ID (cacheable)
port-local dateTime + tzID -> UTC dateTime.
It doesn't have to be UTC; as long as you're comparing dateTimes in the same time zone. However, UTC is a convenient timezone to choose, so it's probably best to use it.
Oh yeah. Make sure your OSB JVM has the latest tzdata or you'll find that your date calculation will be inaccurate for many destinations - Fiji loves to change daylight savings times at short notice.
Related
I'm trying to convert java datetime instant to hh:mm format using moment js
moment("2020-03-21T17:34:00Z").utcOffset(-0500).format("hh:mm")
it should give me 12:34, but somehow it is giving "12:14" which is the wrong time.
The moment js .utcOffset() method takes the offset in minutes.
so if you want to get 12:34 you need to use -300 instead of -0500
moment("2020-03-21T17:34:00Z").utcOffset(-300).format("hh:mm")
A few things:
The utcOffset function behaves differently whether you pass a string or a number. As a number, it's expected to be in terms of minutes. Since you have hours and minutes in your offset, you should pass it as a string: .utcOffset("-0500")
Format strings are case sensitive. You should use HH:mm (24-hour time), or hh:mm a (12-hour time). Since you used hh:mm without an a, anything after 12 pm will be misrepresented.
You are supplying a fixed offset. If that is your intent, then ok. But do recognize that there is a difference between an offset and a time zone. (See "Time Zone != Offset" in the timezone tag wiki.) For example, if you wanted to convert to US Eastern Time, you should use .tz('America/New_York) instead of .utcOffset("-0500"). (US Eastern time is at -4 for the date given, not -5.) You would need the moment-timezone addon to make this work.
Lastly, recognize that Moment is in maintenance mode. The moment team generally recommends Luxon for new development.
I was asked to create a query to pull a near-real-time report from an Informix database (I have select access only, I cannot create a SP) and I felt like I succeeded pretty well until I realized that there was a discrepancy in a datetime field. it seems that the program that is populating the db is hard-coded to enter the time in the datetime field in UTC (five hours off of the local time. When the time was 2:30 it entered a row in the database saying John Doe completed the task at 7:30). In my report I am supposed to calculate the number of seconds (as an int) since the user completed the task (field is "completionTime") and I was originally just using:
sysdate - completionTime interval seconds(9) to seconds cast to char then cast to int
When I realized the mistake in the timezone of the completionTime field I just subtracted the offset as an integer (I was already converting the interval to an integer, so I just adjusted the answer by 18000). This worked just fine until Daylight Saving started. Then all of a sudden local time was 4 hours (14400 seconds instead of 18000) off of UTC.
Since I can only select from the db, I next tried using an inefficient case statement (my query went from <0.5 seconds to 3-5 seconds for only 25 rows). Following a suggestion from another forum I changed the time to an integer of seconds from the unix epoch, then used the dbinfo('utc_to_datetime') sp to convert it back to a datetime in the right timezone.
This approach works, but the calculation looks terrible to me:
cast(cast(cast((sysdate - dbinfo("utc_to_datetime", cast(cast(cast((completionTime - TO_DATE('Friday January 1, 2010 0:00', '%A %B %d, %Y %R')) as interval second(9) to second) as char(10)) as int) +1262304000)) as interval second(9) to second) as char(10)) as int)
notice that I am calculating the length of time from the completiontime to 1-1-2010 then adding 12 billion seconds (going all the way back to the unix epoch is too big for Informix's interval seconds(9) to second, hence the two-steps) so that I can then plug it into the dbinfo("utc_to_datetime") sp to convert it back to a datetime in the right timezone, then subtracting it from sysdate. The worst part (besides the six casts) is that the completiontimes that I am dealing with are all within 24 hours of sysdate, most are within 10 minutes, yet I am adding on 12 billion seconds so that I can use the only function I can find that converts between timezones.
My question is, Is this really the best way to do this? By the way, this works very quickly, and my query is back down to a reasonable execution time (<0.5 seconds), I'm just looking at this query and thinking that there has got to be a better way.
Jared
Maybe instead of sysdate you can use DBINFO('utc_current'):
SELECT DBINFO('utc_current') - (completionTime interval seconds(9) to seconds) FROM ...
I need to save a time interval in a column in a table. based on: http://docs.sqlalchemy.org/en/rel_0_8/core/types.html
I can use Interval type for that. My database is SQLite, and I don't quite understand this description in the document:
"The Interval type deals with datetime.timedelta objects. In PostgreSQL, the
native INTERVAL type is used; for others, the value is stored as a date which
is relative to the “epoch” (Jan. 1, 1970)."
Can anybody tell me how should I do that?
So from what I get in the question, you want to just store an interval and take it out of the database to use it again? But you want to understand how it is stored?
Concerning the storage: This is probably easier with Unix timestamps than with DateTimes. Suppose you want to store timedelta(1), i.e. a delta of one day. What is stored in the database is the time since the "epoch", i.e. second "0" in Unix timestamps and as a date: 1970-01-01 00:00:00 (this is where Unix timestamps start counting the seconds). If you don't know about epoch or timestamp, then read Wikipedia on Unix time.
So we want to store one day of difference? The documentation claims it stored "time since epoch". We just learned "epoch" is "second 0", so a day later would be 60 seconds per minute, 60 minutes per hour, 24 hours per day: 60 * 60 * 24 = 86400. So stored as an integer this is easy to understand: If you find the value 86400 in your database, then it means 1 day, 0 hours, 0 minutes, 0 seconds.
Reality is a bit different: It does not store an integer but a DateTime object. Speaking from this perspective, the epoch is 1970-01-01 00:00:00. So what is a delta of one day since the epoch? That is easy: it's 1970-01-02 00:00:00. You can see, it is a day later.
An hour later? 1970-01-01 01:00:00.
Two days, four hours, 30 seconds?: 1970-01-03 04:00:30.
And you could even do it yourself:
epoch = datetime.utcfromtimestamp(0)
delta = timedelta(1)
one_day = datetime.utcfromtimestamp(86400)
print "Date to be stored in database:", epoch + delta
print "Timedelta from date:", one_day - epoch
As you can see, the calculation is easy and this is all that is done behind the scenes. Take a look at this full example:
interval = IntervalItem(interval=delta)
session.add(interval)
i = session.query(IntervalItem).first()
print "Timedelta from database:", i.interval
You can see it is no different from the above example except it goes through the database. The only thing to keep in mind with this, is this note:
Note that the Interval type does not currently provide date arithmetic operations
on platforms which do not support interval types natively.
That means you should be careful how you use it, for example addition in the query might not be a good idea, but you should just play around with it.
I have an Excel table which contains thousands of incident tickets. Each tickets typically carried over few hours or few days, and I usually calculate the total duration by substracting opening date and time from closing date and time.
However I would like to take into account and not count the out of office hours (night time), week-ends and holidays.
I have therefore created two additional reference tables, one which contains the non-working hours (eg everyday after 7pm until 7am in the morning, saturday and sunday all day, and list of public holidays).
Now I need to find some sort of VB macro that would automatically calculate each ticket "real duration" by removing from the total ticket time any time that would fall under that list.
I had a look around this website and other forums, however I could not find what I am looking for. If someone can help me achieve this, I would be extremely grateful.
Best regards,
Alex
You can use the NETWORKDAYS function to calculate the number of working days in the interval. Actually you seem to be perfectly set up for it: it takes start date, end date and a pointer to a range of holidays. By default it counts all days non-weekend.
For calculating the intraday time, you will need some additional magic. assuming that tickets are only opened and closed in bussines hours, it would look like this:
first_day_hrs := dayend - ticketstart
last_day_hrs := ticketend - daystart
inbeetween_hrs := (NETWORKDAYS(ticketstart, ticketend, rng_holidays) - 2) * (dayend - daystart)
total_hrs := first_day_hrs + inbetween_hrs + last_day_hrs
Of course the names should in reality refer to Excel cells. I recommend using lists and/or names.
I'm using the following syntax
TIMESTAMPDIFF(2, CHAR(CREATED - TIMESTAMP('1970-01-01 00:00:00'))
where CREATED is of type TIMESTAMP and the database is DB2. The intension is to get the timestamp converted to millis from epoch. If there is a better function that would be more helpful.
Sample data:
For 2011-10-04 13:54:50 returned value is 1316613290 but actual value should be 1317732890 (got from http://www.epochconverter.com)
Query to run
SELECT TIMESTAMPDIFF(2, CHAR(TIMESTAMP('2011-10-04 13:54:50') - TIMESTAMP('1970-01-01 00:00:00'))) FROM SYSIBM.SYSDUMMY1;
This is the result of the fact that TIMESTAMPDIFF returns an estimate of the difference between the timestamps, not the actual value, as expected.
From the reference, page 435 (assuming for iSeries):
The following assumptions are used when converting the element values
to the requested interval type:
One year has 365 days.
One year has 52 weeks.
One year has 12 months.
One quarter has 3 months.
One month has 30 days.
One week has 7 days.
One day has 24 hours.
One hour has 60 minutes.
One minute has 60 seconds.
One second has 1000000 microseconds.
And the actual calculation used is:
seconds + (minutes + (hours + ((days + (months * 30) + (years * 365)) * 24)) * 60) * 60
This is, for obvious reasons, inexact. Not helpful.
This appears to be a direct consequence of the way the timestamp arithmetic results are returned.
That is;
SELECT
TIMESTAMP('1971-03-02 00:00:00') - TIMESTAMP('1970-01-01 00:00:00')
FROM sysibm/sysdummy1
returns:
10,201,000,000.000000
Which can be divided into:
1 year
02 months
01 days
00 hours
00 minutes
00 seconds
000000 microseconds
Which is imprecise period/duration information. While there are a multitude of situations where this type of data is useful, this isn't one of them.
Short answer: The exact answer cannot be correctly calculated in the database, and in fact should not.
Long answer:
The calculations are possible, but rather complex, and definitely not suited for in-database calculation. I'm not going to reproduce them here (look up JodaTime if you're interested, specifically the various Chronology subclasses). Your biggest problem is going to be the fact that months aren't all the same length. Also, you're going to run into major problems if your timestamps are anything other than UTC - more specifically, Daylight Savings time is going to play havoc with the calculation. Why? Because the offsets can change at any time, for any country.
Maybe you could explain why you need the number of milliseconds? Hopefully you're using Java (or able to do so), and can use java.time. But if you're on an iSeries, it's probably RPG...
According to the v9.7 info center, TIMESTAMPDIFF returns an estimated time difference, based on 365 days in a year (not true ~25% of the time), 30 days in a month (not true 75% of the time, though averages out a bit better than that), 24 hours in a day (not true a couple days of the year in some timezones), 60 minutes in an hour (hooray, one right!), and 60 seconds in a minute (true >99.9% of the time - we do get leap seconds).
So, no, this is not the way to get epoch time in DB2. Thus far, I've resorted to getting the time as a timestamp, and converting it in the client.
Part of your error occurs because of the inaccuracy of the TIMESTAMPDIFF function, as others have pointed out.
The other source of error occurs because the Epoch is based on GMT – so you have to take your local timezone into account.
So, you can do this with the following expression:
(DAYS(timestamp('2011-10-04-13.54.50.000000') - current timezone) - DAYS('1970-01-01-00.00.00.000000')) * 86400 + MIDNIGHT_SECONDS(timestamp('2011-10-04-13.54.50.000000') - current timezone)
You can write a simple UDF to simplify this:
create or replace function epoch (in db2ts timestamp)
returns bigint
language sql
deterministic
no external action
return (days(db2ts - current timezone) - days('1970-01-01-00.00.00.000000')) * 86400 + midnight_seconds(db2ts - current timezone);
Good luck,